mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
commit
a24b02f5cc
@ -136,6 +136,9 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||||||
/* mc3_decoder */
|
/* mc3_decoder */
|
||||||
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
|
|
||||||
|
/* fadpcm_decoder */
|
||||||
|
void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
|
|
||||||
/* ea_mt_decoder*/
|
/* ea_mt_decoder*/
|
||||||
ea_mt_codec_data *init_ea_mt(int channel_count, int type);
|
ea_mt_codec_data *init_ea_mt(int channel_count, int type);
|
||||||
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
|
85
src/coding/fadpcm_decoder.c
Normal file
85
src/coding/fadpcm_decoder.c
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "coding.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
/* FADPCM table */
|
||||||
|
static const int8_t fadpcm_coefs[8][2] = {
|
||||||
|
{ 0 , 0 },
|
||||||
|
{ 60 , 0 },
|
||||||
|
{ 122 , 60 },
|
||||||
|
{ 115 , 52 },
|
||||||
|
{ 98 , 55 },
|
||||||
|
{ 0 , 0 },
|
||||||
|
{ 0 , 0 },
|
||||||
|
{ 0 , 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* FMOD's FADPCM, basically XA/PSX ADPCM with a fancy header layout.
|
||||||
|
* Code/layout could be simplified but tries to emulate FMOD's code.
|
||||||
|
* Algorithm and tables debugged from their PC DLLs. */
|
||||||
|
void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
|
off_t frame_offset;
|
||||||
|
int i, j, k;
|
||||||
|
int block_samples, num_frame, samples_done = 0, sample_count = 0;
|
||||||
|
int coef_index[8], shift_factor[8];
|
||||||
|
int32_t hist1; //= stream->adpcm_history1_32;
|
||||||
|
int32_t hist2; //= stream->adpcm_history2_32;
|
||||||
|
|
||||||
|
/* external interleave (fixed size), mono */
|
||||||
|
block_samples = (0x8c - 0xc) * 2;
|
||||||
|
num_frame = first_sample / block_samples;
|
||||||
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
|
frame_offset = stream->offset + 0x8c*num_frame;
|
||||||
|
|
||||||
|
|
||||||
|
/* parse 0xc header */
|
||||||
|
{
|
||||||
|
uint32_t coefs, shifts;
|
||||||
|
coefs = read_32bitLE(frame_offset + 0x00, stream->streamfile);
|
||||||
|
shifts = read_32bitLE(frame_offset + 0x04, stream->streamfile);
|
||||||
|
hist1 = read_16bitLE(frame_offset + 0x08, stream->streamfile);
|
||||||
|
hist2 = read_16bitLE(frame_offset + 0x0a, stream->streamfile);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
coef_index[i] = (coefs >> i*4) & 0x0f;
|
||||||
|
shift_factor[i] = (shifts >> i*4) & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* header samples are not written to outbuf */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* decode nibbles, grouped in 0x10 * 0x04 * 2 */
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
off_t group_offset = frame_offset + 0x0c + 0x10*i;
|
||||||
|
int32_t coef1 = fadpcm_coefs[(coef_index[i] % 0x07)][0]; /* indexes > 7 are repeats (ex. 0x9 is 0x2) */
|
||||||
|
int32_t coef2 = fadpcm_coefs[(coef_index[i] % 0x07)][1];
|
||||||
|
int32_t shift = 0x16 - shift_factor[i];
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
uint32_t nibbles = read_32bitLE(group_offset + 0x04*j, stream->streamfile);
|
||||||
|
|
||||||
|
for (k = 0; k < 8; k++) {
|
||||||
|
int32_t new_sample;
|
||||||
|
|
||||||
|
new_sample = (nibbles >> k*4) & 0x0f;
|
||||||
|
new_sample = (new_sample << 28) >> shift; /* sign extend + scale */
|
||||||
|
new_sample = (new_sample - hist2*coef2 + hist1*coef1);
|
||||||
|
new_sample = new_sample >> 6; /* (new_sample / 64) has minor rounding differences */
|
||||||
|
new_sample = clamp16(new_sample);
|
||||||
|
|
||||||
|
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||||
|
outbuf[samples_done * channelspacing] = new_sample;
|
||||||
|
samples_done++;
|
||||||
|
}
|
||||||
|
sample_count++;
|
||||||
|
|
||||||
|
hist2 = hist1;
|
||||||
|
hist1 = new_sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//stream->adpcm_history1_32 = hist1;
|
||||||
|
//stream->adpcm_history2_32 = hist2;
|
||||||
|
}
|
@ -8,14 +8,7 @@
|
|||||||
* All IMAs are mostly the same with these variations:
|
* All IMAs are mostly the same with these variations:
|
||||||
* - interleave: blocks and channels are handled externally (layouts) or internally (mixed channels)
|
* - interleave: blocks and channels are handled externally (layouts) or internally (mixed channels)
|
||||||
* - block header: none (external), normal (4 bytes of history 16b + step 8b + reserved 8b) or others; per channel/global
|
* - block header: none (external), normal (4 bytes of history 16b + step 8b + reserved 8b) or others; per channel/global
|
||||||
* - expand type: ms-ima style or others; low or high nibble first
|
* - expand type: IMA style or variations; low or high nibble first
|
||||||
*
|
|
||||||
* todo:
|
|
||||||
* MS IMAs have the last sample of the prev block in the block header. In Microsoft's implementation, the header sample
|
|
||||||
* is written first and last sample is skipped (since they match). vgmstream ignores the header sample and
|
|
||||||
* writes the last one instead. This means the very first sample in the first header in a stream is incorrectly skipped.
|
|
||||||
* Header step should be 8 bit.
|
|
||||||
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const int ADPCMTable[89] = {
|
static const int ADPCMTable[89] = {
|
||||||
@ -39,15 +32,15 @@ static const int IMA_IndexTable[16] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Standard IMA (most common) */
|
/* Original IMA expansion, using shift+ADDs to avoid MULs (slow back then) */
|
||||||
static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
|
static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
|
||||||
int sample_nibble, sample_decoded, step, delta;
|
int sample_nibble, sample_decoded, step, delta;
|
||||||
|
|
||||||
/* calculate diff = [signed] (step / 8) + (step / 4) + (step / 2) + (step) [when code = 4+2+1]
|
/* simplified through math from:
|
||||||
* simplified through math, using bitwise ops to avoid rounding:
|
* - diff = (code + 1/2) * (step / 4)
|
||||||
* diff = (code + 1/2) * (step / 4)
|
* > diff = ((step * nibble) + (step / 2)) / 4
|
||||||
* > diff = (step * nibble / 4) + (step / 8)
|
* > diff = (step * nibble / 4) + (step / 8)
|
||||||
* > diff = (((step * nibble) + (step / 2)) / 4) */
|
* final diff = [signed] (step / 8) + (step / 4) + (step / 2) + (step) [when code = 4+2+1] */
|
||||||
|
|
||||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; /* ADPCM code */
|
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; /* ADPCM code */
|
||||||
sample_decoded = *hist1; /* predictor value */
|
sample_decoded = *hist1; /* predictor value */
|
||||||
@ -81,7 +74,33 @@ static void std_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offse
|
|||||||
if (sample_nibble & 8) delta = -delta;
|
if (sample_nibble & 8) delta = -delta;
|
||||||
sample_decoded += delta;
|
sample_decoded += delta;
|
||||||
|
|
||||||
*hist1 = clamp16(sample_decoded); //no need for this actually
|
*hist1 = clamp16(sample_decoded); /* no need for this, actually */
|
||||||
|
*step_index += IMA_IndexTable[sample_nibble];
|
||||||
|
if (*step_index < 0) *step_index=0;
|
||||||
|
if (*step_index > 88) *step_index=88;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Original IMA expansion, but using MULs rather than shift+ADDs (faster for newer processors).
|
||||||
|
* There is minor rounding difference between ADD and MUL expansions, noticeable/propagated in non-headered IMAs. */
|
||||||
|
static void std_ima_expand_nibble_mul(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
|
||||||
|
int sample_nibble, sample_decoded, step, delta;
|
||||||
|
|
||||||
|
/* simplified through math from:
|
||||||
|
* - diff = (code + 1/2) * (step / 4)
|
||||||
|
* > diff = (code + 1/2) * step) / 4) * (2 / 2)
|
||||||
|
* > diff = (code + 1/2) * 2 * step / 8
|
||||||
|
* final diff = [signed] ((code * 2 + 1) * step) / 8 */
|
||||||
|
|
||||||
|
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
|
||||||
|
sample_decoded = *hist1;
|
||||||
|
step = ADPCMTable[*step_index];
|
||||||
|
|
||||||
|
delta = (sample_nibble & 0x7);
|
||||||
|
delta = ((delta * 2 + 1) * step) >> 3;
|
||||||
|
if (sample_nibble & 8) delta = -delta;
|
||||||
|
sample_decoded += delta;
|
||||||
|
|
||||||
|
*hist1 = clamp16(sample_decoded);
|
||||||
*step_index += IMA_IndexTable[sample_nibble];
|
*step_index += IMA_IndexTable[sample_nibble];
|
||||||
if (*step_index < 0) *step_index=0;
|
if (*step_index < 0) *step_index=0;
|
||||||
if (*step_index > 88) *step_index=88;
|
if (*step_index > 88) *step_index=88;
|
||||||
@ -96,7 +115,8 @@ static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
|||||||
step = ADPCMTable[*step_index];
|
step = ADPCMTable[*step_index];
|
||||||
|
|
||||||
sample_decoded = sample_decoded << 3;
|
sample_decoded = sample_decoded << 3;
|
||||||
delta = step * (sample_nibble & 7) * 2 + step; /* custom */
|
delta = (sample_nibble & 0x07);
|
||||||
|
delta = step * delta * 2 + step; /* custom */
|
||||||
if (sample_nibble & 8) delta = -delta;
|
if (sample_nibble & 8) delta = -delta;
|
||||||
sample_decoded += delta;
|
sample_decoded += delta;
|
||||||
sample_decoded = sample_decoded >> 3;
|
sample_decoded = sample_decoded >> 3;
|
||||||
@ -149,24 +169,6 @@ static void otns_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
|||||||
if (*step_index > 88) *step_index=88;
|
if (*step_index > 88) *step_index=88;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ubisoft games, algorithm by Zench (https://bitbucket.org/Zenchreal/decubisnd) */
|
|
||||||
static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int32_t * hist1, int32_t * step_index) {
|
|
||||||
int sample_nibble, sample_decoded, step, delta;
|
|
||||||
|
|
||||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
|
|
||||||
sample_decoded = *hist1;
|
|
||||||
step = ADPCMTable[*step_index];
|
|
||||||
|
|
||||||
delta = (((sample_nibble & 7) * 2 + 1) * step) >> 3; /* custom */
|
|
||||||
if (sample_nibble & 8) delta = -delta;
|
|
||||||
sample_decoded += delta;
|
|
||||||
|
|
||||||
*hist1 = clamp16(sample_decoded);
|
|
||||||
*step_index += IMA_IndexTable[sample_nibble];
|
|
||||||
if (*step_index < 0) *step_index=0;
|
|
||||||
if (*step_index > 88) *step_index=88;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ************************************ */
|
/* ************************************ */
|
||||||
/* DVI/IMA */
|
/* DVI/IMA */
|
||||||
/* ************************************ */
|
/* ************************************ */
|
||||||
@ -176,7 +178,6 @@ static void ubi_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
|||||||
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
|
* For vgmstream, low nibble is called "IMA ADPCM" and high nibble is "DVI IMA ADPCM" (same thing though). */
|
||||||
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
|
void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int is_stereo, int is_high_first) {
|
||||||
int i, sample_count = 0;
|
int i, sample_count = 0;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -186,7 +187,7 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
|||||||
if (step_index < 0) step_index=0;
|
if (step_index < 0) step_index=0;
|
||||||
if (step_index > 88) step_index=88;
|
if (step_index > 88) step_index=88;
|
||||||
|
|
||||||
/* decode nibbles */
|
/* decode nibbles (layout: varies) */
|
||||||
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||||
off_t byte_offset = is_stereo ?
|
off_t byte_offset = is_stereo ?
|
||||||
stream->offset + i : /* stereo: one nibble per channel */
|
stream->offset + i : /* stereo: one nibble per channel */
|
||||||
@ -205,7 +206,6 @@ void decode_standard_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
|||||||
|
|
||||||
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -227,7 +227,6 @@ void decode_3ds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
|||||||
|
|
||||||
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -249,7 +248,6 @@ void decode_snds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||||||
|
|
||||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -275,20 +273,20 @@ void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample *
|
|||||||
/* MS-IMA */
|
/* MS-IMA */
|
||||||
/* ************************************ */
|
/* ************************************ */
|
||||||
|
|
||||||
/* IMA with variable-sized frames, header and custom nibble layout (outputs non-aligned number of samples).
|
/* IMA with custom frame sizes, header and nibble layout. Outputs an odd number of samples per frame,
|
||||||
|
* so to simplify calcs this decodes full frames, thus hist doesn't need to be mantained.
|
||||||
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
|
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf). */
|
||||||
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
int i, samples_read = 0, samples_done = 0, max_samples;
|
int i, samples_read = 0, samples_done = 0, max_samples;
|
||||||
|
|
||||||
int32_t hist1;// = stream->adpcm_history1_32;
|
int32_t hist1;// = stream->adpcm_history1_32;
|
||||||
int step_index;// = stream->adpcm_step_index;
|
int step_index;// = stream->adpcm_step_index;
|
||||||
|
|
||||||
/* internal interleave (configurable size), mixed channels (4 byte per ch) */
|
/* internal interleave (configurable size), mixed channels */
|
||||||
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
||||||
first_sample = first_sample % block_samples;
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
/* normal header (hist+step+reserved per channel) */
|
/* normal header (hist+step+reserved), per channel */
|
||||||
{
|
{ //if (first_sample == 0) {
|
||||||
off_t header_offset = stream->offset + 0x04*channel;
|
off_t header_offset = stream->offset + 0x04*channel;
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
||||||
@ -296,7 +294,7 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
|
|||||||
if (step_index < 0) step_index = 0;
|
if (step_index < 0) step_index = 0;
|
||||||
if (step_index > 88) step_index = 88;
|
if (step_index > 88) step_index = 88;
|
||||||
|
|
||||||
/* write header sample */
|
/* write header sample (odd samples per block) */
|
||||||
if (samples_read >= first_sample && samples_done < samples_to_do) {
|
if (samples_read >= first_sample && samples_done < samples_to_do) {
|
||||||
outbuf[samples_done * channelspacing] = (short)hist1;
|
outbuf[samples_done * channelspacing] = (short)hist1;
|
||||||
samples_done++;
|
samples_done++;
|
||||||
@ -308,12 +306,12 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
|
|||||||
if (max_samples > samples_to_do + first_sample - samples_done)
|
if (max_samples > samples_to_do + first_sample - samples_done)
|
||||||
max_samples = samples_to_do + first_sample - samples_done; /* for smaller last block */
|
max_samples = samples_to_do + first_sample - samples_done; /* for smaller last block */
|
||||||
|
|
||||||
/* decode nibbles (layout: alternates 4*2 nibbles per channel) */
|
/* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel) */
|
||||||
for (i = 0; i < max_samples; i++) {
|
for (i = 0; i < max_samples; i++) {
|
||||||
off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2;
|
off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x04*channel + 0x04*vgmstream->channels*(i/8) + (i%8)/2;
|
||||||
int nibble_shift = (i&1?4:0); /* low nibble first */
|
int nibble_shift = (i&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index); /* original expand */
|
||||||
|
|
||||||
if (samples_read >= first_sample && samples_done < samples_to_do) {
|
if (samples_read >= first_sample && samples_done < samples_to_do) {
|
||||||
outbuf[samples_done * channelspacing] = (short)(hist1);
|
outbuf[samples_done * channelspacing] = (short)(hist1);
|
||||||
@ -331,24 +329,23 @@ void decode_ms_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * ou
|
|||||||
//stream->adpcm_step_index = step_index;
|
//stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reflection's MS-IMA (some layout info from XA2WAV by Deniz Oezmen) */
|
/* Reflection's MS-IMA with custom nibble layout (some info from XA2WAV by Deniz Oezmen) */
|
||||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
int i, samples_read = 0, samples_done = 0, max_samples;
|
int i, samples_read = 0, samples_done = 0, max_samples;
|
||||||
|
|
||||||
int32_t hist1;// = stream->adpcm_history1_32;
|
int32_t hist1;// = stream->adpcm_history1_32;
|
||||||
int step_index;// = stream->adpcm_step_index;
|
int step_index;// = stream->adpcm_step_index;
|
||||||
|
|
||||||
/* internal interleave (configurable size), mixed channels (4 byte per ch) */
|
/* internal interleave (configurable size), mixed channels */
|
||||||
int block_channel_size = (vgmstream->interleave_block_size - 0x04*vgmstream->channels) / vgmstream->channels;
|
int block_channel_size = (vgmstream->interleave_block_size - 0x04*vgmstream->channels) / vgmstream->channels;
|
||||||
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
int block_samples = ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
||||||
first_sample = first_sample % block_samples;
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
/* normal header (hist+step+reserved per channel) */
|
/* normal header (hist+step+reserved), per channel */
|
||||||
{
|
{ //if (first_sample == 0) {
|
||||||
off_t header_offset = stream->offset + 0x04*channel;
|
off_t header_offset = stream->offset + 0x04*channel;
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
||||||
step_index = read_8bit(header_offset+0x02,stream->streamfile); /* 0x03: reserved */
|
step_index = read_8bit(header_offset+0x02,stream->streamfile);
|
||||||
if (step_index < 0) step_index = 0;
|
if (step_index < 0) step_index = 0;
|
||||||
if (step_index > 88) step_index = 88;
|
if (step_index > 88) step_index = 88;
|
||||||
|
|
||||||
@ -391,90 +388,92 @@ void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * o
|
|||||||
/* XBOX-IMA */
|
/* XBOX-IMA */
|
||||||
/* ************************************ */
|
/* ************************************ */
|
||||||
|
|
||||||
/* MS-IMA with fixed frame size, skips last sample per channel (for aligment) and custom multichannel nibble layout.
|
/* MS-IMA with fixed frame size, and outputs an even number of samples per frame (skips last nibble).
|
||||||
* For multichannel the layout is (I think) mixed stereo channels (ex. 6ch: 2ch + 2ch + 2ch) */
|
* Defined in Xbox's SDK. Multichannel interleaves 2ch*N/2, or 1ch*N with odd num_channels. */
|
||||||
void decode_xbox_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
void decode_xbox_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
int i, sample_count;
|
int i, sample_count = 0;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
off_t offset = stream->offset;
|
/* internal interleave (fixed size), mixed channels */
|
||||||
|
int block_samples = (0x24-0x4) * 2;
|
||||||
//internal interleave (0x20+4 size), mixed channels (4 byte per ch, mixed stereo)
|
|
||||||
int block_samples = (vgmstream->channels==1) ?
|
|
||||||
32 :
|
|
||||||
32*(vgmstream->channels&2);//todo this can be zero in 4/5/8ch = SEGFAULT using % below
|
|
||||||
first_sample = first_sample % block_samples;
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
//normal header (per channel)
|
/* normal header (hist+step+reserved), per stereo/mono channel in blocks */
|
||||||
if (first_sample == 0) {
|
if (first_sample == 0) {
|
||||||
off_t header_offset;
|
off_t header_offset = (channelspacing & 1) ?
|
||||||
header_offset = stream->offset + 4*(channel%2);
|
stream->offset + 0x24*(channel) + 0x00:
|
||||||
|
stream->offset + 0x48*(channel/2) + 0x04*(channel%2);
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset,stream->streamfile);
|
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
||||||
step_index = read_16bitLE(header_offset+2,stream->streamfile);
|
step_index = read_8bit(header_offset+0x02,stream->streamfile);
|
||||||
if (step_index < 0) step_index=0;
|
|
||||||
if (step_index > 88) step_index=88;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
|
||||||
int nibble_shift;
|
|
||||||
|
|
||||||
offset = (channelspacing==1) ?
|
|
||||||
stream->offset + 4*(channel%2) + 4 + i/8*4 + (i%8)/2 :
|
|
||||||
stream->offset + 4*(channel%2) + 4*2 + i/8*4*2 + (i%8)/2;
|
|
||||||
nibble_shift = (i&1?4:0); //low nibble first
|
|
||||||
|
|
||||||
std_ima_expand_nibble(stream, offset,nibble_shift, &hist1, &step_index);
|
|
||||||
outbuf[sample_count] = (short)(hist1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//internal interleave: increment offset on complete frame
|
|
||||||
if (channelspacing==1) { /* mono */
|
|
||||||
if (offset-stream->offset == 32+3) // ??
|
|
||||||
stream->offset += 0x24;
|
|
||||||
} else {
|
|
||||||
if (offset-stream->offset == 64+(4*(channel%2))+3) // ??
|
|
||||||
stream->offset += 0x24*channelspacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->adpcm_history1_32 = hist1;
|
|
||||||
stream->adpcm_step_index = step_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* mono XBOX-IMA ADPCM for interleave */
|
|
||||||
void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
|
||||||
int i, sample_count = 0, num_frame;
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
|
||||||
int step_index = stream->adpcm_step_index;
|
|
||||||
|
|
||||||
//external interleave
|
|
||||||
int block_samples = (0x24 - 0x4) * 2; /* block size - header, 2 samples per byte */
|
|
||||||
num_frame = first_sample / block_samples;
|
|
||||||
first_sample = first_sample % block_samples;
|
|
||||||
|
|
||||||
//normal header
|
|
||||||
if (first_sample == 0) {
|
|
||||||
off_t header_offset = stream->offset + 0x24*num_frame;
|
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset,stream->streamfile);
|
|
||||||
step_index = read_8bit(header_offset+2,stream->streamfile);
|
|
||||||
if (step_index < 0) step_index=0;
|
if (step_index < 0) step_index=0;
|
||||||
if (step_index > 88) step_index=88;
|
if (step_index > 88) step_index=88;
|
||||||
|
|
||||||
//must write history from header as last nibble/sample in block is almost always 0 / not encoded
|
/* write header sample (even samples per block, skips last nibble) */
|
||||||
outbuf[sample_count] = (short)(hist1);
|
outbuf[sample_count] = (short)(hist1);
|
||||||
sample_count += channelspacing;
|
sample_count += channelspacing;
|
||||||
first_sample += 1;
|
first_sample += 1;
|
||||||
samples_to_do -= 1;
|
samples_to_do -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
|
/* decode nibbles (layout: alternates 4 bytes/4*2 nibbles per channel, in stereo blocks) */
|
||||||
off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||||
int nibble_shift = ((i-1)&1?4:0); //low nibble first
|
off_t byte_offset = (channelspacing & 1) ?
|
||||||
|
(stream->offset + 0x24*(channel) + 0x04) + (i-1)/2:
|
||||||
|
(stream->offset + 0x48*(channel/2) + 0x04*2) + 0x04*(channel%2) + 0x04*2*((i-1)/8) + ((i-1)%8)/2;
|
||||||
|
int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
//last nibble/sample in block is ignored (next header sample contains it)
|
/* must skip last nibble per official decoder, probably not needed though */
|
||||||
|
if (i < block_samples) {
|
||||||
|
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
|
outbuf[sample_count] = (short)(hist1);
|
||||||
|
sample_count += channelspacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* internal interleave: increment offset on complete frame */
|
||||||
|
if (i == block_samples) {
|
||||||
|
stream->offset += 0x24*vgmstream->channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->adpcm_history1_32 = hist1;
|
||||||
|
stream->adpcm_step_index = step_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mono XBOX-IMA ADPCM, used for interleave. Also defined in Xbox's SDK. */
|
||||||
|
void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
|
int i, sample_count = 0, num_frame;
|
||||||
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
|
/* external interleave (fixed size), mono */
|
||||||
|
int block_samples = (0x24 - 0x4) * 2;
|
||||||
|
num_frame = first_sample / block_samples;
|
||||||
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
|
/* normal header (hist+step+reserved), single channel */
|
||||||
|
if (first_sample == 0) {
|
||||||
|
off_t header_offset = stream->offset + 0x24*num_frame;
|
||||||
|
|
||||||
|
hist1 = read_16bitLE(header_offset+0x00,stream->streamfile);
|
||||||
|
step_index = read_8bit(header_offset+0x02,stream->streamfile);
|
||||||
|
if (step_index < 0) step_index=0;
|
||||||
|
if (step_index > 88) step_index=88;
|
||||||
|
|
||||||
|
/* write header sample (even samples per block, skips last nibble) */
|
||||||
|
outbuf[sample_count] = (short)(hist1);
|
||||||
|
sample_count += channelspacing;
|
||||||
|
first_sample += 1;
|
||||||
|
samples_to_do -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode nibbles (layout: all nibbles from one channel) */
|
||||||
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||||
|
off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
|
||||||
|
int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
|
/* must skip last nibble per spec, rarely needed though (ex. Gauntlet Dark Legacy) */
|
||||||
if (i < block_samples) {
|
if (i < block_samples) {
|
||||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
outbuf[sample_count] = (short)(hist1);
|
outbuf[sample_count] = (short)(hist1);
|
||||||
@ -486,39 +485,42 @@ void decode_xbox_ima_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
|||||||
stream->adpcm_step_index = step_index;
|
stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similar to MS-IMA with even number of samples, header sample is not written (setup only).
|
||||||
|
* Apparently clamps to -32767 unlike standard's -32768 (probably not noticeable).
|
||||||
|
* Info here: http://problemkaputt.de/gbatek.htm#dssoundnotes */
|
||||||
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
void decode_nds_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
|
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
//external interleave
|
/* external interleave (configurable size), mono */
|
||||||
|
|
||||||
//normal header
|
/* normal header (hist+step+reserved), single channel */
|
||||||
if (first_sample == 0) {
|
if (first_sample == 0) {
|
||||||
off_t header_offset = stream->offset;
|
off_t header_offset = stream->offset;
|
||||||
|
|
||||||
hist1 = read_16bitLE(header_offset,stream->streamfile);
|
hist1 = read_16bitLE(header_offset,stream->streamfile);
|
||||||
step_index = read_16bitLE(header_offset+2,stream->streamfile);
|
step_index = read_16bitLE(header_offset+2,stream->streamfile);
|
||||||
|
if (step_index < 0) step_index=0; /* probably pre-adjusted */
|
||||||
//todo clip step_index?
|
if (step_index > 88) step_index=88;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* decode nibbles (layout: all nibbles from the channel) */
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||||
off_t byte_offset = stream->offset + 4 + i/2;
|
off_t byte_offset = stream->offset + 0x04 + i/2;
|
||||||
int nibble_shift = (i&1?4:0); //low nibble first
|
int nibble_shift = (i&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
|
//todo waveform has minor deviations using known expands
|
||||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
outbuf[sample_count] = (short)(hist1);
|
outbuf[sample_count] = (short)(hist1);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->adpcm_history1_16 = hist1;
|
stream->adpcm_history1_32 = hist1;
|
||||||
stream->adpcm_step_index = step_index;
|
stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
|
int32_t hist1 = stream->adpcm_history1_16;//todo unneeded 16?
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -548,7 +550,6 @@ void decode_dat4_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||||||
|
|
||||||
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -583,7 +584,6 @@ void decode_rad_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
|
|||||||
|
|
||||||
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
void decode_rad_ima_mono(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
@ -647,91 +647,99 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelsp
|
|||||||
|
|
||||||
/* XBOX-IMA with modified data layout */
|
/* XBOX-IMA with modified data layout */
|
||||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
||||||
int i, sample_count;
|
int i, sample_count = 0;
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
int step_index = stream->adpcm_step_index;
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
//internal interleave
|
/* internal interleave (configurable size), mixed channels */
|
||||||
int block_samples = (0x24 - 4) * 2; /* block size - header, 2 samples per byte */
|
int block_samples = (0x24 - 0x4) * 2;
|
||||||
first_sample = first_sample % block_samples;
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
//interleaved header (all hist per channel + all step_index per channel)
|
/* interleaved header (all hist per channel + all step_index+reserved per channel) */
|
||||||
if (first_sample == 0) {
|
if (first_sample == 0) {
|
||||||
off_t hist_offset = stream->offset + 2*channel;
|
off_t hist_offset = stream->offset + 0x02*channel + 0x00;
|
||||||
off_t step_offset = stream->offset + 2*channel + 2*vgmstream->channels;
|
off_t step_offset = stream->offset + 0x02*channel + 0x02*vgmstream->channels;
|
||||||
|
|
||||||
hist1 = read_16bitLE(hist_offset,stream->streamfile);
|
hist1 = read_16bitLE(hist_offset,stream->streamfile);
|
||||||
step_index = read_8bit(step_offset,stream->streamfile);
|
step_index = read_8bit(step_offset,stream->streamfile);
|
||||||
if (step_index < 0) step_index=0;
|
if (step_index < 0) step_index=0;
|
||||||
if (step_index > 88) step_index=88;
|
if (step_index > 88) step_index=88;
|
||||||
}
|
|
||||||
|
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
/* write header sample (even samples per block, skips last nibble) */
|
||||||
off_t byte_offset = stream->offset + 4*vgmstream->channels + 2*channel + i/4*2*vgmstream->channels + (i%4)/2;//2-byte per channel
|
|
||||||
int nibble_shift = (i&1?4:0); //low nibble first
|
|
||||||
|
|
||||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
|
||||||
outbuf[sample_count] = (short)(hist1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//internal interleave: increment offset on complete frame
|
|
||||||
if (i == block_samples) stream->offset += 36*vgmstream->channels;
|
|
||||||
|
|
||||||
stream->adpcm_history1_32 = hist1;
|
|
||||||
stream->adpcm_step_index = step_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* XBOX-IMA with modified data layout */
|
|
||||||
void decode_wwise_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
|
||||||
int i, sample_count = 0;
|
|
||||||
|
|
||||||
int32_t hist1 = stream->adpcm_history1_32;
|
|
||||||
int step_index = stream->adpcm_step_index;
|
|
||||||
|
|
||||||
//internal interleave (configurable size), block-interleave multichannel (ex. if block is 0xD8 in 6ch: 6 blocks of 4+0x20)
|
|
||||||
int block_samples = (vgmstream->interleave_block_size - 4*vgmstream->channels) * 2 / vgmstream->channels;
|
|
||||||
first_sample = first_sample % block_samples;
|
|
||||||
|
|
||||||
//block-interleaved header (1 header per channel block); can be LE or BE
|
|
||||||
if (first_sample == 0) {
|
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
|
|
||||||
off_t header_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel;
|
|
||||||
|
|
||||||
hist1 = read_16bit(header_offset,stream->streamfile);
|
|
||||||
step_index = read_8bit(header_offset+2,stream->streamfile);
|
|
||||||
if (step_index < 0) step_index=0;
|
|
||||||
if (step_index > 88) step_index=88;
|
|
||||||
|
|
||||||
//must write history from header as last nibble/sample in block is almost always 0 / not encoded
|
|
||||||
outbuf[sample_count] = (short)(hist1);
|
outbuf[sample_count] = (short)(hist1);
|
||||||
sample_count += channelspacing;
|
sample_count += channelspacing;
|
||||||
first_sample += 1;
|
first_sample += 1;
|
||||||
samples_to_do -= 1;
|
samples_to_do -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=first_sample; i < first_sample + samples_to_do; i++) { /* first_sample + samples_to_do should be block_samples at most */
|
/* decode nibbles (layout: 2 bytes/2*2 nibbles per channel) */
|
||||||
off_t byte_offset = stream->offset + (vgmstream->interleave_block_size / vgmstream->channels)*channel + 4 + (i-1)/2;
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||||
int nibble_shift = ((i-1)&1?4:0); //low nibble first
|
off_t byte_offset = stream->offset + 0x04*vgmstream->channels + 0x02*channel + (i-1)/4*2*vgmstream->channels + ((i-1)%4)/2;
|
||||||
|
int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
//last nibble/sample in block is ignored (next header sample contains it)
|
/* must skip last nibble per official decoder, probably not needed though */
|
||||||
if (i < block_samples) {
|
if (i < block_samples) {
|
||||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
outbuf[sample_count] = (short)(hist1);
|
outbuf[sample_count] = (short)(hist1);
|
||||||
sample_count+=channelspacing;
|
sample_count += channelspacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//internal interleave: increment offset on complete frame
|
/* internal interleave: increment offset on complete frame */
|
||||||
if (i == block_samples) stream->offset += vgmstream->interleave_block_size;
|
if (i == block_samples) {
|
||||||
|
stream->offset += 0x24*vgmstream->channels;
|
||||||
|
}
|
||||||
|
|
||||||
stream->adpcm_history1_32 = hist1;
|
stream->adpcm_history1_32 = hist1;
|
||||||
stream->adpcm_step_index = step_index;
|
stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
//todo atenuation: apparently from hcs's analysis Wwise IMA expands nibbles slightly different, reducing clipping/dbs
|
|
||||||
/*
|
/* mono XBOX-IMA with header endianness and alt nibble expand (per hcs's decompilation) */
|
||||||
From Wwise_v2015.1.6_Build5553_SDK.Linux
|
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||||
<_ZN13CAkADPCMCodec12DecodeSampleEiii>:
|
int i, sample_count = 0, num_frame;
|
||||||
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
|
/* external interleave (fixed size), mono */
|
||||||
|
int block_samples = (0x24 - 0x4) * 2;
|
||||||
|
num_frame = first_sample / block_samples;
|
||||||
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
|
/* normal header (hist+step+reserved), single channel */
|
||||||
|
if (first_sample == 0) {
|
||||||
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
|
||||||
|
off_t header_offset = stream->offset + 0x24*num_frame;
|
||||||
|
|
||||||
|
hist1 = read_16bit(header_offset,stream->streamfile);
|
||||||
|
step_index = read_8bit(header_offset+2,stream->streamfile);
|
||||||
|
if (step_index < 0) step_index=0;
|
||||||
|
if (step_index > 88) step_index=88;
|
||||||
|
|
||||||
|
/* write header sample (even samples per block, skips last nibble) */
|
||||||
|
outbuf[sample_count] = (short)(hist1);
|
||||||
|
sample_count += channelspacing;
|
||||||
|
first_sample += 1;
|
||||||
|
samples_to_do -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode nibbles (layout: all nibbles from one channel) */
|
||||||
|
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||||
|
off_t byte_offset = (stream->offset + 0x24*num_frame + 0x4) + (i-1)/2;
|
||||||
|
int nibble_shift = ((i-1)&1?4:0); /* low nibble first */
|
||||||
|
|
||||||
|
/* must skip last nibble like other XBOX-IMAs, often needed (ex. Bayonetta 2 sfx) */
|
||||||
|
if (i < block_samples) {
|
||||||
|
std_ima_expand_nibble_mul(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
|
outbuf[sample_count] = (short)(hist1);
|
||||||
|
sample_count += channelspacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->adpcm_history1_32 = hist1;
|
||||||
|
stream->adpcm_step_index = step_index;
|
||||||
|
}
|
||||||
|
/* from hcs's analysis Wwise IMA expands nibbles slightly different, reducing dbs. Just "MUL" expand?
|
||||||
|
<_ZN13CAkADPCMCodec12DecodeSampleEiii>: //From Wwise_v2015.1.6_Build5553_SDK.Linux
|
||||||
10: 83 e0 07 and $0x7,%eax ; sample
|
10: 83 e0 07 and $0x7,%eax ; sample
|
||||||
13: 01 c0 add %eax,%eax ; sample*2
|
13: 01 c0 add %eax,%eax ; sample*2
|
||||||
15: 83 c0 01 add $0x1,%eax ; sample*2+1
|
15: 83 c0 01 add $0x1,%eax ; sample*2+1
|
||||||
@ -740,8 +748,6 @@ From Wwise_v2015.1.6_Build5553_SDK.Linux
|
|||||||
1f: 85 c0 test %eax,%eax ; result negative?
|
1f: 85 c0 test %eax,%eax ; result negative?
|
||||||
21: 0f 48 c2 cmovs %edx,%eax ; adjust if negative to fix rounding for below division
|
21: 0f 48 c2 cmovs %edx,%eax ; adjust if negative to fix rounding for below division
|
||||||
24: c1 f8 03 sar $0x3,%eax ; (sample*2+1)*scale/8
|
24: c1 f8 03 sar $0x3,%eax ; (sample*2+1)*scale/8
|
||||||
|
|
||||||
Different rounding model vs IMA's shift-and-add (also "adjust" step may be unnecessary).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
|
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
|
||||||
@ -832,7 +838,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
|||||||
(!(i%2) ? 4:0) : /* mono mode (high first) */
|
(!(i%2) ? 4:0) : /* mono mode (high first) */
|
||||||
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
|
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
|
||||||
|
|
||||||
ubi_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
std_ima_expand_nibble_mul(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
outbuf[sample_count] = (short)(hist1); /* all samples are written */
|
outbuf[sample_count] = (short)(hist1); /* all samples are written */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,7 +855,7 @@ size_t ima_bytes_to_samples(size_t bytes, int channels) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
|
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
|
||||||
/* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
/* MS-IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
||||||
return (bytes / block_align) * ((block_align - 0x04*channels) * 2 / channels + 1)
|
return (bytes / block_align) * ((block_align - 0x04*channels) * 2 / channels + 1)
|
||||||
+ ((bytes % block_align) ? (((bytes % block_align) - 0x04*channels) * 2 / channels + 1) : 0);
|
+ ((bytes % block_align) ? (((bytes % block_align) - 0x04*channels) * 2 / channels + 1) : 0);
|
||||||
}
|
}
|
||||||
@ -858,7 +864,7 @@ size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
|
|||||||
int block_align = 0x24 * channels;
|
int block_align = 0x24 * channels;
|
||||||
/* XBOX IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
/* XBOX IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
||||||
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels
|
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels
|
||||||
+ ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); //todo probably not possible (aligned)
|
+ ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset) {
|
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset) {
|
||||||
|
@ -105,6 +105,7 @@ static const char* extension_list[] = {
|
|||||||
"dvi",
|
"dvi",
|
||||||
"dxh",
|
"dxh",
|
||||||
|
|
||||||
|
"e4x",
|
||||||
"eam",
|
"eam",
|
||||||
"emff",
|
"emff",
|
||||||
"enth",
|
"enth",
|
||||||
@ -379,7 +380,7 @@ static const char* extension_list[] = {
|
|||||||
"xss",
|
"xss",
|
||||||
"xvag",
|
"xvag",
|
||||||
"xvas",
|
"xvas",
|
||||||
"xwav",
|
"xwav",//fake, to be removed
|
||||||
"xwb",
|
"xwb",
|
||||||
"xwc",
|
"xwc",
|
||||||
"xwm", //FFmpeg, not parsed (XWMA)
|
"xwm", //FFmpeg, not parsed (XWMA)
|
||||||
@ -495,6 +496,7 @@ static const coding_info coding_info_list[] = {
|
|||||||
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
|
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
|
||||||
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
|
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
|
||||||
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
|
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
|
||||||
|
{coding_FADPCM, "FMOD FADPCM 4-bit ADCPM"},
|
||||||
|
|
||||||
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
|
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
|
||||||
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
|
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
|
||||||
@ -565,13 +567,13 @@ static const layout_info layout_info_list[] = {
|
|||||||
{layout_thp_blocked, "THP Movie Audio blocked"},
|
{layout_thp_blocked, "THP Movie Audio blocked"},
|
||||||
{layout_filp_blocked, "FILp blocked"},
|
{layout_filp_blocked, "FILp blocked"},
|
||||||
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
|
{layout_blocked_ea_swvr, "blocked (EA SWVR)"},
|
||||||
{layout_ps2_adm_blocked, "ADM blocked"},
|
{layout_blocked_adm, "blocked (ADM)"},
|
||||||
{layout_dsp_bdsp_blocked, "DSP blocked"},
|
{layout_dsp_bdsp_blocked, "DSP blocked"},
|
||||||
{layout_blocked_ivaud, "blocked (IVAUD)"},
|
{layout_blocked_ivaud, "blocked (IVAUD)"},
|
||||||
{layout_ps2_iab_blocked, "IAB blocked"},
|
{layout_ps2_iab_blocked, "IAB blocked"},
|
||||||
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
|
{layout_ps2_strlr_blocked, "The Bouncer STR blocked"},
|
||||||
{layout_rws_blocked, "RWS blocked"},
|
{layout_blocked_rws, "blocked (RWS)"},
|
||||||
{layout_hwas_blocked, "HWAS blocked"},
|
{layout_blocked_hwas, "blocked (HWAS)"},
|
||||||
{layout_tra_blocked, "TRA blocked"},
|
{layout_tra_blocked, "TRA blocked"},
|
||||||
{layout_acm, "ACM blocked"},
|
{layout_acm, "ACM blocked"},
|
||||||
{layout_mus_acm, "multiple ACM files, ACM blocked"},
|
{layout_mus_acm, "multiple ACM files, ACM blocked"},
|
||||||
@ -642,7 +644,6 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_PS2_ILD, "ILD header"},
|
{meta_PS2_ILD, "ILD header"},
|
||||||
{meta_PS2_PNB, "assumed PNB (PsychoNauts Bgm File) by .pnb extension"},
|
{meta_PS2_PNB, "assumed PNB (PsychoNauts Bgm File) by .pnb extension"},
|
||||||
{meta_XBOX_WAVM, "Xbox WAVM raw header"},
|
{meta_XBOX_WAVM, "Xbox WAVM raw header"},
|
||||||
{meta_XBOX_RIFF, "Microsoft XWAV RIFF header"},
|
|
||||||
{meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"},
|
{meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"},
|
||||||
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
|
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
|
||||||
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
|
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
|
||||||
@ -700,6 +701,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
|
{meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
|
||||||
{meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"},
|
{meta_RIFF_WAVE_labl, "RIFF WAVE header with loop markers"},
|
||||||
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
{meta_RIFF_WAVE_smpl, "RIFF WAVE header with sample looping info"},
|
||||||
|
{meta_RIFF_WAVE_wsmp, "RIFF WAVE header with wsmp looping info"},
|
||||||
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
{meta_RIFX_WAVE, "RIFX WAVE header"},
|
||||||
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
{meta_RIFX_WAVE_smpl, "RIFX WAVE header with sample looping info"},
|
||||||
{meta_XNB, "Microsoft XNA Game Studio 4.0 header"},
|
{meta_XNB, "Microsoft XNA Game Studio 4.0 header"},
|
||||||
@ -844,6 +846,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_DSP_XIII, "XIII dsp header"},
|
{meta_DSP_XIII, "XIII dsp header"},
|
||||||
{meta_NGC_DSP_STH_STR, "STH dsp header"},
|
{meta_NGC_DSP_STH_STR, "STH dsp header"},
|
||||||
{meta_DSP_CABELAS, "Cabelas games dsp header"},
|
{meta_DSP_CABELAS, "Cabelas games dsp header"},
|
||||||
|
{meta_PS2_ADM, "Dragon Quest V .ADM raw header"},
|
||||||
{meta_PS2_LPCM, "LPCM header"},
|
{meta_PS2_LPCM, "LPCM header"},
|
||||||
{meta_PS2_VMS, "VMS Header"},
|
{meta_PS2_VMS, "VMS Header"},
|
||||||
{meta_XAU, "XPEC XAU header"},
|
{meta_XAU, "XPEC XAU header"},
|
||||||
|
@ -131,8 +131,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
|||||||
case layout_blocked_ea_swvr:
|
case layout_blocked_ea_swvr:
|
||||||
block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
|
block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_ps2_adm_blocked:
|
case layout_blocked_adm:
|
||||||
ps2_adm_block_update(vgmstream->next_block_offset,vgmstream);
|
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_dsp_bdsp_blocked:
|
case layout_dsp_bdsp_blocked:
|
||||||
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
dsp_bdsp_block_update(vgmstream->next_block_offset,vgmstream);
|
||||||
@ -146,11 +146,11 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
|||||||
case layout_ps2_strlr_blocked:
|
case layout_ps2_strlr_blocked:
|
||||||
ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
|
ps2_strlr_block_update(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_rws_blocked:
|
case layout_blocked_rws:
|
||||||
rws_block_update(vgmstream->next_block_offset,vgmstream);
|
block_update_rws(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_hwas_blocked:
|
case layout_blocked_hwas:
|
||||||
hwas_block_update(vgmstream->next_block_offset,vgmstream);
|
block_update_hwas(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_blocked_ea_sns:
|
case layout_blocked_ea_sns:
|
||||||
block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
|
block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
|
||||||
|
48
src/layout/blocked_adm.c
Normal file
48
src/layout/blocked_adm.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "layout.h"
|
||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
/* blocks of 0x1000 with interleave 0x400 but also smaller last interleave */
|
||||||
|
void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||||
|
int i, new_full_block;
|
||||||
|
size_t block_size, interleave_size, interleave_data;
|
||||||
|
|
||||||
|
/* no header */
|
||||||
|
interleave_size = 0x400;
|
||||||
|
interleave_data = 0x400;
|
||||||
|
block_size = interleave_size * vgmstream->channels;
|
||||||
|
|
||||||
|
/* every 0x1000 is a full block, signaled by PS-ADPCM flags */
|
||||||
|
new_full_block = (read_8bit(block_offset+0x01, streamFile) == 0x06);
|
||||||
|
|
||||||
|
/* try to autodetect usable interleave data size as can be smaller when a discrete block ends (ex. 0x10~0x50, varies with file) */
|
||||||
|
if (!new_full_block) {
|
||||||
|
off_t next_block_offset = block_offset + block_size;
|
||||||
|
|
||||||
|
while (next_block_offset > block_offset) {
|
||||||
|
next_block_offset -= 0x10;
|
||||||
|
|
||||||
|
/* check if unused line (all blocks should only use flags 0x06/0x03/0x02) */
|
||||||
|
if (read_32bitLE(next_block_offset, streamFile) == 0x00000000) {
|
||||||
|
interleave_data -= 0x10;
|
||||||
|
next_block_offset -= 0x10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vgmstream->current_block_offset = block_offset;
|
||||||
|
vgmstream->next_block_offset = block_offset + block_size;
|
||||||
|
vgmstream->current_block_size = interleave_data;
|
||||||
|
|
||||||
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
|
vgmstream->ch[i].offset = block_offset + interleave_size*i;
|
||||||
|
|
||||||
|
//if (new_full_block) { /* blocks are not discrete */
|
||||||
|
// vgmstream->ch[i].adpcm_history1_32 = 0;
|
||||||
|
// vgmstream->ch[i].adpcm_step_index = 0;
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
#include "../vgmstream.h"
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
/* a simple headerless block with special adpcm history handling */
|
/* a simple headerless block with special adpcm history handling */
|
||||||
void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
int i;
|
int i;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
#include "../vgmstream.h"
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
/* a simple headerless block with padding; configured in the main header */
|
/* a simple headerless block with padding; configured in the main header */
|
||||||
void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
int i;
|
int i;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
size_t interleave;
|
size_t interleave;
|
@ -45,10 +45,8 @@ void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|||||||
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
void filp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_ivaud(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|
||||||
|
|
||||||
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
void dsp_bdsp_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
@ -58,10 +56,8 @@ void ps2_iab_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|||||||
|
|
||||||
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
void ps2_strlr_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
void rws_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|
||||||
|
|
||||||
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
#include "layout.h"
|
|
||||||
#include "../vgmstream.h"
|
|
||||||
|
|
||||||
/* set up for the block at the given offset */
|
|
||||||
void ps2_adm_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
vgmstream->current_block_offset = block_offset;
|
|
||||||
vgmstream->current_block_size = 0x1000; /*read_32bitLE(
|
|
||||||
vgmstream->current_block_offset+0x10,
|
|
||||||
vgmstream->ch[0].streamfile); */
|
|
||||||
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size;
|
|
||||||
//vgmstream->current_block_size/=vgmstream->channels;
|
|
||||||
|
|
||||||
for (i=0;i<vgmstream->channels;i++) {
|
|
||||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+(0x400*i);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1366,10 +1366,6 @@
|
|||||||
RelativePath=".\meta\xbox_xvas.c"
|
RelativePath=".\meta\xbox_xvas.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath=".\meta\xbox_xwav.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath=".\meta\xma.c"
|
RelativePath=".\meta\xma.c"
|
||||||
>
|
>
|
||||||
@ -1482,6 +1478,10 @@
|
|||||||
RelativePath=".\coding\ea_xas_decoder.c"
|
RelativePath=".\coding\ea_xas_decoder.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\fadpcm_decoder.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\coding\ffmpeg_decoder.c"
|
RelativePath=".\coding\ffmpeg_decoder.c"
|
||||||
>
|
>
|
||||||
@ -1759,7 +1759,7 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\layout\ps2_adm_blocked.c"
|
RelativePath=".\layout\blocked_adm.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
@ -1775,11 +1775,11 @@
|
|||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\layout\rws_blocked.c"
|
RelativePath=".\layout\blocked_rws.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\layout\hwas_blocked.c"
|
RelativePath=".\layout\blocked_hwas.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
@ -413,7 +413,6 @@
|
|||||||
<ClCompile Include="meta\xbox_wavm.c" />
|
<ClCompile Include="meta\xbox_wavm.c" />
|
||||||
<ClCompile Include="meta\xbox_xmu.c" />
|
<ClCompile Include="meta\xbox_xmu.c" />
|
||||||
<ClCompile Include="meta\xbox_xvas.c" />
|
<ClCompile Include="meta\xbox_xvas.c" />
|
||||||
<ClCompile Include="meta\xbox_xwav.c" />
|
|
||||||
<ClCompile Include="meta\x360_pasx.c" />
|
<ClCompile Include="meta\x360_pasx.c" />
|
||||||
<ClCompile Include="meta\xma.c" />
|
<ClCompile Include="meta\xma.c" />
|
||||||
<ClCompile Include="meta\xnb.c" />
|
<ClCompile Include="meta\xnb.c" />
|
||||||
@ -430,6 +429,7 @@
|
|||||||
<ClCompile Include="coding\ea_mt_decoder.c" />
|
<ClCompile Include="coding\ea_mt_decoder.c" />
|
||||||
<ClCompile Include="coding\ea_xa_decoder.c" />
|
<ClCompile Include="coding\ea_xa_decoder.c" />
|
||||||
<ClCompile Include="coding\ea_xas_decoder.c" />
|
<ClCompile Include="coding\ea_xas_decoder.c" />
|
||||||
|
<ClCompile Include="coding\fadpcm_decoder.c" />
|
||||||
<ClCompile Include="coding\g719_decoder.c" />
|
<ClCompile Include="coding\g719_decoder.c" />
|
||||||
<ClCompile Include="coding\g721_decoder.c" />
|
<ClCompile Include="coding\g721_decoder.c" />
|
||||||
<ClCompile Include="coding\g7221_decoder.c" />
|
<ClCompile Include="coding\g7221_decoder.c" />
|
||||||
@ -486,10 +486,10 @@
|
|||||||
<ClCompile Include="layout\mus_acm_layout.c" />
|
<ClCompile Include="layout\mus_acm_layout.c" />
|
||||||
<ClCompile Include="layout\mxch_blocked.c" />
|
<ClCompile Include="layout\mxch_blocked.c" />
|
||||||
<ClCompile Include="layout\nolayout.c" />
|
<ClCompile Include="layout\nolayout.c" />
|
||||||
<ClCompile Include="layout\ps2_adm_blocked.c" />
|
<ClCompile Include="layout\blocked_adm.c" />
|
||||||
<ClCompile Include="layout\blocked_ea_swvr.c" />
|
<ClCompile Include="layout\blocked_ea_swvr.c" />
|
||||||
<ClCompile Include="layout\rws_blocked.c" />
|
<ClCompile Include="layout\blocked_rws.c" />
|
||||||
<ClCompile Include="layout\hwas_blocked.c" />
|
<ClCompile Include="layout\blocked_hwas.c" />
|
||||||
<ClCompile Include="layout\str_snds_blocked.c" />
|
<ClCompile Include="layout\str_snds_blocked.c" />
|
||||||
<ClCompile Include="layout\thp_blocked.c" />
|
<ClCompile Include="layout\thp_blocked.c" />
|
||||||
<ClCompile Include="layout\vs_blocked.c" />
|
<ClCompile Include="layout\vs_blocked.c" />
|
||||||
|
@ -832,9 +832,6 @@
|
|||||||
<ClCompile Include="meta\xbox_xvas.c">
|
<ClCompile Include="meta\xbox_xvas.c">
|
||||||
<Filter>meta\Source Files</Filter>
|
<Filter>meta\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="meta\xbox_xwav.c">
|
|
||||||
<Filter>meta\Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="meta\xss.c">
|
<ClCompile Include="meta\xss.c">
|
||||||
<Filter>meta\Source Files</Filter>
|
<Filter>meta\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -874,6 +871,9 @@
|
|||||||
<ClCompile Include="coding\ea_xas_decoder.c">
|
<ClCompile Include="coding\ea_xas_decoder.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="coding\fadpcm_decoder.c">
|
||||||
|
<Filter>coding\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="coding\g721_decoder.c">
|
<ClCompile Include="coding\g721_decoder.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -1021,7 +1021,7 @@
|
|||||||
<ClCompile Include="layout\halpst_blocked.c">
|
<ClCompile Include="layout\halpst_blocked.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\hwas_blocked.c">
|
<ClCompile Include="layout\blocked_hwas.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\ims_block.c">
|
<ClCompile Include="layout\ims_block.c">
|
||||||
@ -1042,13 +1042,13 @@
|
|||||||
<ClCompile Include="layout\nolayout.c">
|
<ClCompile Include="layout\nolayout.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\ps2_adm_blocked.c">
|
<ClCompile Include="layout\blocked_adm.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\blocked_ea_swvr.c">
|
<ClCompile Include="layout\blocked_ea_swvr.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\rws_blocked.c">
|
<ClCompile Include="layout\blocked_rws.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="layout\str_snds_blocked.c">
|
<ClCompile Include="layout\str_snds_blocked.c">
|
||||||
|
@ -110,7 +110,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
case 0x03: /* Loop Info */
|
case 0x03: /* Loop Info */
|
||||||
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||||
if (ExtraFlagSize > 0x04) /* probably no needed */
|
if (ExtraFlagSize > 0x04) /* probably not needed */
|
||||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||||
|
|
||||||
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
||||||
@ -118,9 +118,9 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
case 0x04: /* free comment, or maybe SFX info */
|
case 0x04: /* free comment, or maybe SFX info */
|
||||||
break;
|
break;
|
||||||
//case 0x05: /* Unknown (32b) */
|
//case 0x05: /* Unknown (32b) */
|
||||||
// /* found in Tearaway Vita, value 0, first stream only */
|
// /* found in Tearaway Vita, value 0, first stream only */
|
||||||
// break;
|
// break;
|
||||||
case 0x06: /* XMA seek table */
|
case 0x06: /* XMA seek table */
|
||||||
/* no need for it */
|
/* no need for it */
|
||||||
break;
|
break;
|
||||||
@ -142,11 +142,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
|||||||
* (xN entries)
|
* (xN entries)
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
//case 0x0d: /* Unknown (32b) */
|
//case 0x0d: /* Unknown (32b) */
|
||||||
// /* found in some XMA2 and Vorbis */
|
// /* found in some XMA2/Vorbis/FADPCM */
|
||||||
// break;
|
// break;
|
||||||
default:
|
default:
|
||||||
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x + 0x04 (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +336,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
case 0x10: /* FMOD_SOUND_FORMAT_FADPCM */
|
case 0x10: /* FMOD_SOUND_FORMAT_FADPCM */
|
||||||
goto fail;
|
vgmstream->coding_type = coding_FADPCM;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x8c;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -63,6 +63,9 @@ static const uint8_t key_inv[] = { 0x6D,0x69,0x6E,0x74,0x37,0x38,0x72,0x75,0x6E,
|
|||||||
/* Guitar Hero 3 */ //"5atu6w4zaw"
|
/* Guitar Hero 3 */ //"5atu6w4zaw"
|
||||||
static const uint8_t key_gh3[] = { 0x35,0x61,0x74,0x75,0x36,0x77,0x34,0x7A,0x61,0x77 };
|
static const uint8_t key_gh3[] = { 0x35,0x61,0x74,0x75,0x36,0x77,0x34,0x7A,0x61,0x77 };
|
||||||
|
|
||||||
|
/* Supreme Commander 2 */ //"B2A7BB00"
|
||||||
|
static const uint8_t key_sc2[] = { 0x42,0x32,0x41,0x37,0x42,0x42,0x30,0x30 };
|
||||||
|
|
||||||
// Unknown:
|
// Unknown:
|
||||||
// - Battle: Los Angeles
|
// - Battle: Los Angeles
|
||||||
// - Guitar Hero: Warriors of Rock, DJ hero FSB
|
// - Guitar Hero: Warriors of Rock, DJ hero FSB
|
||||||
@ -118,6 +121,10 @@ static const fsbkey_info fsbkey_list[] = {
|
|||||||
{ 0,1, sizeof(key_gh3),key_gh3 },//untested
|
{ 0,1, sizeof(key_gh3),key_gh3 },//untested
|
||||||
{ 1,0, sizeof(key_gh3),key_gh3 },//untested
|
{ 1,0, sizeof(key_gh3),key_gh3 },//untested
|
||||||
{ 1,1, sizeof(key_gh3),key_gh3 },//untested
|
{ 1,1, sizeof(key_gh3),key_gh3 },//untested
|
||||||
|
{ 0,0, sizeof(key_sc2),key_sc2 },//untested
|
||||||
|
{ 0,1, sizeof(key_sc2),key_sc2 },//untested
|
||||||
|
{ 1,0, sizeof(key_sc2),key_sc2 },//untested
|
||||||
|
{ 1,1, sizeof(key_sc2),key_sc2 },//untested
|
||||||
|
|
||||||
};
|
};
|
||||||
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
static const int fsbkey_list_count = sizeof(fsbkey_list) / sizeof(fsbkey_list[0]);
|
||||||
|
@ -76,8 +76,6 @@ VGMSTREAM * init_vgmstream_ps2_pnb(STREAMFILE *streamFile);
|
|||||||
|
|
||||||
VGMSTREAM * init_vgmstream_xbox_wavm(STREAMFILE *streamFile);
|
VGMSTREAM * init_vgmstream_xbox_wavm(STREAMFILE *streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile);
|
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile);
|
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile);
|
||||||
|
|
||||||
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile);
|
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile);
|
||||||
|
@ -18,7 +18,7 @@ VGMSTREAM * init_vgmstream_mss(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
channel_count = read_16bitLE(0x16,streamFile);
|
channel_count = read_16bitLE(0x16,streamFile);
|
||||||
if (read_32bitLE(0x18,streamFile) == 0x4800 && vgmstream->channels > 2)
|
if (read_32bitLE(0x18,streamFile) == 0x4800 && channel_count > 2)
|
||||||
channel_count = 2; //todo add support for interleave stereo streams
|
channel_count = 2; //todo add support for interleave stereo streams
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
@ -34,14 +34,14 @@ VGMSTREAM * init_vgmstream_nds_hwas(STREAMFILE *streamFile) {
|
|||||||
vgmstream->meta_type = meta_NDS_HWAS;
|
vgmstream->meta_type = meta_NDS_HWAS;
|
||||||
|
|
||||||
vgmstream->coding_type = coding_IMA_int;
|
vgmstream->coding_type = coding_IMA_int;
|
||||||
vgmstream->layout_type = layout_hwas_blocked;
|
vgmstream->layout_type = layout_blocked_hwas;
|
||||||
vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */
|
vgmstream->full_block_size = read_32bitLE(0x04,streamFile); /* usually 0x2000, 0x4000 or 0x8000 */
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
/* open the file for reading by each channel */
|
||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
hwas_block_update(start_offset, vgmstream);
|
block_update_hwas(start_offset, vgmstream);
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
@ -1,37 +1,36 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
|
|
||||||
/* XA30 - found in Driver: Parallel Lines (PC) */
|
/* XA30 - found in Reflections games [Driver: Parallel Lines (PC), Driver 3 (PC)] */
|
||||||
VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int loop_flag, channel_count, codec;
|
int loop_flag, channel_count, codec;
|
||||||
size_t file_size, data_size;
|
size_t stream_size;
|
||||||
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||||
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
/* ".xa30" is just the ID, the real filename should be .XA */
|
/* ".xa30/e4x" is just the ID, the real filename should be .XA */
|
||||||
if (!check_extensions(streamFile,"xa,xa30"))
|
if (!check_extensions(streamFile,"xa,xa30,e4x"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x58413330) /* "XA30" */
|
if (read_32bitBE(0x00,streamFile) != 0x58413330 && /* "XA30" [Driver: Parallel Lines (PC)]*/
|
||||||
|
read_32bitBE(0x00,streamFile) != 0x65347892) /* "e4x\92" [Driver 3 (PC)]*/
|
||||||
|
goto fail;
|
||||||
|
if (read_32bitLE(0x04,streamFile) != 2) /* channels?, also extra check to avoid PS2/PC XA30 mixup */
|
||||||
goto fail;
|
goto fail;
|
||||||
if (read_32bitLE(0x04,streamFile) > 2) goto fail; /* extra check to avoid PS2/PC XA30 mixup */
|
|
||||||
|
|
||||||
|
total_subsongs = read_32bitLE(0x14,streamFile) != 0 ? 2 : 1; /* second stream offset (only in Driver 3) */
|
||||||
/* reportedly from XA2WAV those are offset+data from a second stream (not seen) */
|
if (target_subsong == 0) target_subsong = 1;
|
||||||
if (read_32bitLE(0x14,streamFile) != 0 || read_32bitLE(0x1c,streamFile) != 0) goto fail;
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||||
|
|
||||||
loop_flag = 0;
|
loop_flag = 0;
|
||||||
channel_count = 2; /* 0x04: channels? (always 2 in practice) */
|
channel_count = 2; /* 0x04: channels? (always 2 in practice) */
|
||||||
|
codec = read_32bitLE(0x0c,streamFile);
|
||||||
codec = read_32bitLE(0x0c,streamFile); /* reportedly from XA2WAV (not seen) */
|
start_offset = read_32bitLE(0x10 + 0x04*(target_subsong-1),streamFile);
|
||||||
start_offset = read_32bitLE(0x10,streamFile);
|
stream_size = read_32bitLE(0x18 + 0x04*(target_subsong-1),streamFile);
|
||||||
|
|
||||||
file_size = get_streamfile_size(streamFile);
|
|
||||||
data_size = read_32bitLE(0x18,streamFile);
|
|
||||||
if (data_size+start_offset != file_size) goto fail;
|
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
@ -39,19 +38,26 @@ VGMSTREAM * init_vgmstream_pc_xa30(STREAMFILE *streamFile) {
|
|||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||||
/* 0x20: always 00016000?, rest of the header is null */
|
/* 0x20: always IMA=00016000, PCM=00056000 PCM?, rest of the header is null */
|
||||||
|
vgmstream->num_streams = total_subsongs;
|
||||||
|
vgmstream->stream_size = stream_size;
|
||||||
vgmstream->meta_type = meta_PC_XA30;
|
vgmstream->meta_type = meta_PC_XA30;
|
||||||
|
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
|
case 0x00: /* PCM (rare, seen in Driver 3) */
|
||||||
|
vgmstream->coding_type = coding_PCM16LE;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile) / 2;
|
||||||
|
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x01: /* MS-IMA variation */
|
case 0x01: /* MS-IMA variation */
|
||||||
vgmstream->coding_type = coding_REF_IMA;
|
vgmstream->coding_type = coding_REF_IMA;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
|
vgmstream->interleave_block_size = read_32bitLE(0x24,streamFile);
|
||||||
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, vgmstream->interleave_block_size, channel_count);
|
vgmstream->num_samples = ms_ima_bytes_to_samples(stream_size, vgmstream->interleave_block_size, channel_count);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x00: /* PCM? */
|
|
||||||
default:
|
default:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -1,75 +1,109 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../layout/layout.h"
|
#include "../layout/layout.h"
|
||||||
#include "../util.h"
|
#include "../coding/coding.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* WAD (from The golden Compass) */
|
static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset);
|
||||||
|
|
||||||
|
/* .adm - from Dragon Quest V (PS2) */
|
||||||
VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
int channel_count, loop_flag = 0;
|
||||||
int loop_flag = 0;
|
off_t start_offset, loop_start_offset = 0;
|
||||||
int channel_count;
|
|
||||||
int i;
|
|
||||||
off_t start_offset;
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
if (!check_extensions(streamFile,"adm"))
|
||||||
if (strcasecmp("adm",filename_extension(filename))) goto fail;
|
goto fail;
|
||||||
|
|
||||||
loop_flag = 0;
|
/* raw data, but test some .ADM blocks as they always start with PS-ADPCM flag 0x06 every 0x1000 */
|
||||||
channel_count = 2;
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
|
||||||
if (!vgmstream) goto fail;
|
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
start_offset = 0x0;
|
|
||||||
vgmstream->channels = channel_count;
|
|
||||||
vgmstream->sample_rate = 44100;
|
|
||||||
vgmstream->coding_type = coding_PSX;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
vgmstream->num_samples = read_32bitLE(0x0,streamFile)/channel_count/16*28;
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = 0;
|
|
||||||
vgmstream->loop_end_sample = read_32bitLE(0x0,streamFile)/channel_count/16*28;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vgmstream->layout_type = layout_ps2_adm_blocked;
|
|
||||||
vgmstream->interleave_block_size = 0x400;
|
|
||||||
|
|
||||||
|
|
||||||
vgmstream->meta_type = meta_PS2_ADM;
|
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
|
||||||
{
|
{
|
||||||
for (i=0;i<channel_count;i++) {
|
int i;
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,vgmstream->interleave_block_size);
|
for (i = 0; i < 10; i++) {
|
||||||
|
if (read_8bit(0x1000*i + 0x01, streamFile) != 0x06)
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
goto fail;
|
||||||
vgmstream->ch[i].channel_start_offset=
|
|
||||||
vgmstream->ch[i].offset=i*vgmstream->interleave_block_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_offset = 0x00;
|
||||||
|
loop_flag = get_adm_loop_info(streamFile, &loop_start_offset);
|
||||||
|
channel_count = 2;
|
||||||
|
|
||||||
/* Calc num_samples */
|
/* build the VGMSTREAM */
|
||||||
ps2_adm_block_update(start_offset,vgmstream);
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
vgmstream->num_samples=0; //(get_streamfile_size(streamFile)/0x1000*0xFE0)/32*28;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
do {
|
vgmstream->sample_rate = 44100;
|
||||||
|
vgmstream->meta_type = meta_PS2_ADM;
|
||||||
vgmstream->num_samples += 0xFE0*14/16;
|
|
||||||
ps2_adm_block_update(vgmstream->next_block_offset,vgmstream);
|
|
||||||
} while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
|
|
||||||
|
|
||||||
ps2_adm_block_update(start_offset,vgmstream);
|
vgmstream->coding_type = coding_PSX;
|
||||||
|
vgmstream->layout_type = layout_blocked_adm;
|
||||||
|
|
||||||
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* calc num_samples as playable data size varies between files/blocks */
|
||||||
|
vgmstream->num_samples = 0; //ps_bytes_to_samples(get_streamfile_size(streamFile), channel_count);
|
||||||
|
block_update_adm(start_offset,vgmstream);
|
||||||
|
while (vgmstream->next_block_offset < get_streamfile_size(streamFile)) {
|
||||||
|
if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
|
||||||
|
vgmstream->loop_start_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
|
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size * channel_count, channel_count);
|
||||||
|
|
||||||
|
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (loop_flag)
|
||||||
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
|
||||||
|
|
||||||
|
block_update_adm(start_offset,vgmstream);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* loops are not in the .ADM or .DAT bigfile containing them but in the exe; manually get them (a bit meh but whatevs) */
|
||||||
|
static int get_adm_loop_info(STREAMFILE *streamFile, off_t *loop_start_offset) {
|
||||||
|
char file_name[PATH_LIMIT];
|
||||||
|
char index_name[PATH_LIMIT];
|
||||||
|
STREAMFILE *streamExe = NULL;
|
||||||
|
int i, name_index = -1, loop_flag;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
streamExe = open_stream_name(streamFile, "SLPM_655.55");
|
||||||
|
if (!streamExe) goto fail;
|
||||||
|
|
||||||
|
get_streamfile_filename(streamFile, file_name, PATH_LIMIT);
|
||||||
|
|
||||||
|
/* get file index from name list (file_name == index_name = index number */
|
||||||
|
offset = 0x23B3c0;
|
||||||
|
for (i = 0; i < 51; i++) {
|
||||||
|
read_string(index_name,0x20+1, offset,streamExe);
|
||||||
|
|
||||||
|
if (strcmp(index_name, file_name)==0) {
|
||||||
|
name_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += 0x20;
|
||||||
|
}
|
||||||
|
if (name_index < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* get file info using index */
|
||||||
|
offset = 0x23BAEC + 0x1c*name_index;
|
||||||
|
loop_flag = (read_32bitLE(offset + 0x10, streamExe) == 0); /* 1: don't loop, 0: loop */
|
||||||
|
if (loop_flag) { /* loop flag */
|
||||||
|
*loop_start_offset = read_32bitLE(offset + 0x04, streamExe);
|
||||||
|
}
|
||||||
|
/* 0x08: num_samples/loop_end, 0x0c: sample rate (always 44100), 0x14/18: some size? */
|
||||||
|
|
||||||
|
close_streamfile(streamExe);
|
||||||
|
return loop_flag;
|
||||||
|
fail:
|
||||||
|
close_streamfile(streamExe);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
116
src/meta/riff.c
116
src/meta/riff.c
@ -131,7 +131,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
|||||||
fmt->coding_type = coding_MS_IMA;
|
fmt->coding_type = coding_MS_IMA;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x69: /* XBOX IMA ADPCM [Rayman Raving Rabbids 2 (PC) --maybe waa/wac/wam/wad?] */
|
case 0x69: /* XBOX IMA ADPCM [Dynasty Warriors 5 (Xbox), Rayman Raving Rabbids 2 (PC) --maybe waa/wac/wam/wad?] */
|
||||||
if (fmt->bps != 4) goto fail;
|
if (fmt->bps != 4) goto fail;
|
||||||
fmt->coding_type = coding_XBOX_IMA;
|
fmt->coding_type = coding_XBOX_IMA;
|
||||||
break;
|
break;
|
||||||
@ -232,10 +232,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
int fact_sample_skip = 0;
|
int fact_sample_skip = 0;
|
||||||
|
|
||||||
int loop_flag = 0;
|
int loop_flag = 0;
|
||||||
long loop_start_ms = -1;
|
int loop_start_sample = 0, loop_end_sample = 0;
|
||||||
long loop_end_ms = -1;
|
long loop_start_ms = -1, loop_end_ms = -1;
|
||||||
off_t loop_start_offset = -1;
|
off_t loop_start_offset = -1, loop_end_offset = -1;
|
||||||
off_t loop_end_offset = -1;
|
|
||||||
|
|
||||||
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
|
int FormatChunkFound = 0, DataChunkFound = 0, JunkFound = 0;
|
||||||
|
|
||||||
@ -248,8 +247,9 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
|
|
||||||
/* check extension */
|
/* check extension */
|
||||||
|
/* .lwav: to avoid hijacking .wav, .xwav: fake for Xbox games (unneded anymore) */
|
||||||
/* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android) */
|
/* .da: The Great Battle VI (PS), .cd: Exector (PS), .med: Psi Ops (PC), .snd: Layton Brothers (iOS/Android) */
|
||||||
if ( check_extensions(streamFile, "wav,lwav,da,cd,med,snd") ) {
|
if ( check_extensions(streamFile, "wav,lwav,xwav,da,cd,med,snd") ) {
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
else if ( check_extensions(streamFile, "mwv") ) {
|
else if ( check_extensions(streamFile, "mwv") ) {
|
||||||
@ -282,6 +282,10 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
if (riff_size+0x08+0x01 == file_size)
|
if (riff_size+0x08+0x01 == file_size)
|
||||||
riff_size += 0x01;
|
riff_size += 0x01;
|
||||||
|
|
||||||
|
/* some Xbox games do this [Dynasty Warriors 3 (Xbox), BloodRayne (Xbox)] */
|
||||||
|
if (riff_size == file_size && read_16bitLE(0x14,streamFile)==0x0069)
|
||||||
|
riff_size -= 0x08;
|
||||||
|
|
||||||
/* check for truncated RIFF */
|
/* check for truncated RIFF */
|
||||||
if (file_size < riff_size+0x08) goto fail;
|
if (file_size < riff_size+0x08) goto fail;
|
||||||
|
|
||||||
@ -296,12 +300,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
if (fmt.codec == 0x6771 && chunk_type == 0x64617461) /* Liar-soft again */
|
||||||
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
chunk_size += (chunk_size%2) ? 0x01 : 0x00;
|
||||||
|
|
||||||
if (current_chunk+8+chunk_size > file_size) goto fail;
|
if (current_chunk+0x08+chunk_size > file_size) goto fail;
|
||||||
|
|
||||||
switch(chunk_type) {
|
switch(chunk_type) {
|
||||||
case 0x666d7420: /* "fmt " */
|
case 0x666d7420: /* "fmt " */
|
||||||
/* only one per file */
|
if (FormatChunkFound) goto fail; /* only one per file */
|
||||||
if (FormatChunkFound) goto fail;
|
|
||||||
FormatChunkFound = 1;
|
FormatChunkFound = 1;
|
||||||
|
|
||||||
if (-1 == read_fmt(0, /* big endian == false*/
|
if (-1 == read_fmt(0, /* big endian == false*/
|
||||||
@ -311,20 +314,20 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
sns,
|
sns,
|
||||||
mwv))
|
mwv))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x64617461: /* data */
|
|
||||||
/* at most one per file */
|
case 0x64617461: /* "data" */
|
||||||
if (DataChunkFound) goto fail;
|
if (DataChunkFound) goto fail; /* only one per file */
|
||||||
DataChunkFound = 1;
|
DataChunkFound = 1;
|
||||||
|
|
||||||
start_offset = current_chunk + 8;
|
start_offset = current_chunk + 0x08;
|
||||||
data_size = chunk_size;
|
data_size = chunk_size;
|
||||||
break;
|
break;
|
||||||
case 0x4C495354: /* LIST */
|
|
||||||
|
case 0x4C495354: /* "LIST" */
|
||||||
/* what lurks within?? */
|
/* what lurks within?? */
|
||||||
switch (read_32bitBE(current_chunk + 8, streamFile)) {
|
switch (read_32bitBE(current_chunk+0x08, streamFile)) {
|
||||||
case 0x6164746C: /* adtl */
|
case 0x6164746C: /* "adtl" */
|
||||||
/* yay, atdl is its own little world */
|
/* yay, atdl is its own little world */
|
||||||
parse_adtl(current_chunk + 8, chunk_size,
|
parse_adtl(current_chunk + 8, chunk_size,
|
||||||
streamFile,
|
streamFile,
|
||||||
@ -334,28 +337,40 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x736D706C: /* smpl */
|
|
||||||
/* check loop count and loop info */
|
case 0x736D706C: /* "smpl" (RIFFMIDISample + MIDILoop chunk) */
|
||||||
if (read_32bitLE(current_chunk+0x24, streamFile)==1) {
|
/* check loop count/loop info (most common) *///todo double check values
|
||||||
if (read_32bitLE(current_chunk+0x2c+4, streamFile)==0) {
|
/* 0x00: manufacturer id, 0x04: product id, 0x08: sample period, 0x0c: unity node,
|
||||||
|
* 0x10: pitch fraction, 0x14: SMPTE format, 0x18: SMPTE offset, 0x1c: loop count, 0x20: sampler data */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x1c, streamFile)==1) {
|
||||||
|
/* 0x24: cue point id, 0x28: type (0=forward, 1=alternating, 2=backward)
|
||||||
|
* 0x2c: start, 0x30: end, 0x34: fraction, 0x38: play count */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x28, streamFile)==0) {
|
||||||
loop_flag = 1;
|
loop_flag = 1;
|
||||||
loop_start_offset = read_32bitLE(current_chunk+0x2c+8, streamFile);
|
loop_start_offset = read_32bitLE(current_chunk+0x08+0x2c, streamFile);
|
||||||
loop_end_offset = read_32bitLE(current_chunk+0x2c+0xc,streamFile);
|
loop_end_offset = read_32bitLE(current_chunk+0x08+0x30, streamFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x70666c74: /* pflt */
|
|
||||||
if (!mwv) break; /* ignore if not in an mwv */
|
|
||||||
|
|
||||||
mwv_pflt_offset = current_chunk; /* predictor filters */
|
case 0x77736D70: /* "wsmp" (RIFFDLSSample + DLSLoop chunk) */
|
||||||
|
/* check loop count/info (found in some Xbox games: Halo (non-looping), Dynasty Warriors 3, Crimson Sea) */
|
||||||
|
/* 0x00: size, 0x04: unity note, 0x06: fine tune, 0x08: gain, 0x10: loop count */
|
||||||
|
if (chunk_size >= 0x24
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x00, streamFile) == 0x14
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x10, streamFile) > 0
|
||||||
|
&& read_32bitLE(current_chunk+0x08+0x14, streamFile) == 0x10) {
|
||||||
|
/* 0x14: size, 0x18: loop type (0=forward, 1=release), 0x1c: loop start, 0x20: loop length */
|
||||||
|
if (read_32bitLE(current_chunk+0x08+0x18, streamFile)==0) {
|
||||||
|
loop_flag = 1;
|
||||||
|
loop_start_sample = read_32bitLE(current_chunk+0x08+0x1c, streamFile);
|
||||||
|
loop_end_sample = read_32bitLE(current_chunk+0x08+0x20, streamFile);
|
||||||
|
loop_end_sample += loop_start_sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x6374726c: /* ctrl */
|
|
||||||
if (!mwv) break;
|
|
||||||
|
|
||||||
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
|
case 0x66616374: /* "fact" */
|
||||||
mwv_ctrl_offset = current_chunk;
|
|
||||||
break;
|
|
||||||
case 0x66616374: /* fact */
|
|
||||||
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
||||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
} else if (sns && chunk_size == 0x10) {
|
} else if (sns && chunk_size == 0x10) {
|
||||||
@ -367,11 +382,22 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
|
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 0x4A554E4B: /* JUNK */
|
|
||||||
|
case 0x70666c74: /* "pflt" (.mwv extension) */
|
||||||
|
if (!mwv) break; /* ignore if not in an mwv */
|
||||||
|
mwv_pflt_offset = current_chunk; /* predictor filters */
|
||||||
|
break;
|
||||||
|
case 0x6374726c: /* "ctrl" (.mwv extension) */
|
||||||
|
if (!mwv) break;
|
||||||
|
loop_flag = read_32bitLE(current_chunk+0x08, streamFile);
|
||||||
|
mwv_ctrl_offset = current_chunk;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x4A554E4B: /* "JUNK" */
|
||||||
JunkFound = 1;
|
JunkFound = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* ignorance is bliss */
|
/* ignorance is bliss */
|
||||||
break;
|
break;
|
||||||
@ -383,7 +409,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
if (!FormatChunkFound || !DataChunkFound) goto fail;
|
||||||
|
|
||||||
//todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
|
//todo improve detection using fmt sizes/values as Wwise's don't match the RIFF standard
|
||||||
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
|
/* JUNK is an optional Wwise chunk, and Wwise hijacks the MSADPCM/MS_IMA/XBOX IMA ids (how nice).
|
||||||
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
|
* To ensure their stuff is parsed in wwise.c we reject their JUNK, which they put almost always.
|
||||||
* As JUNK is legal (if unusual) we only reject those codecs.
|
* As JUNK is legal (if unusual) we only reject those codecs.
|
||||||
@ -445,18 +471,21 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case coding_MSADPCM:
|
case coding_MSADPCM:
|
||||||
vgmstream->num_samples = fact_sample_count ? fact_sample_count :
|
vgmstream->num_samples = msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
||||||
msadpcm_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = fact_sample_count;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case coding_MS_IMA:
|
case coding_MS_IMA:
|
||||||
vgmstream->num_samples = fact_sample_count ? fact_sample_count :
|
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
||||||
ms_ima_bytes_to_samples(data_size, fmt.block_size, fmt.channel_count);
|
if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = fact_sample_count;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case coding_XBOX_IMA:
|
case coding_XBOX_IMA:
|
||||||
vgmstream->num_samples = fact_sample_count ? fact_sample_count :
|
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, fmt.channel_count);
|
||||||
xbox_ima_bytes_to_samples(data_size, fmt.channel_count);
|
if (fact_sample_count && fact_sample_count < vgmstream->num_samples)
|
||||||
|
vgmstream->num_samples = fact_sample_count; /* some (converted?) Xbox games have bigger fact_samples */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case coding_NGC_DSP:
|
case coding_NGC_DSP:
|
||||||
@ -579,6 +608,11 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
|||||||
vgmstream->loop_end_sample = loop_end_offset;
|
vgmstream->loop_end_sample = loop_end_offset;
|
||||||
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
|
vgmstream->meta_type = meta_RIFF_WAVE_smpl;
|
||||||
}
|
}
|
||||||
|
else if (loop_start_sample >= 0) {
|
||||||
|
vgmstream->loop_start_sample = loop_start_sample;
|
||||||
|
vgmstream->loop_end_sample = loop_end_sample;
|
||||||
|
vgmstream->meta_type = meta_RIFF_WAVE_wsmp;
|
||||||
|
}
|
||||||
else if (mwv && mwv_ctrl_offset != -1) {
|
else if (mwv && mwv_ctrl_offset != -1) {
|
||||||
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile);
|
vgmstream->loop_start_sample = read_32bitLE(mwv_ctrl_offset+12, streamFile);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
|
@ -155,7 +155,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
|||||||
if (name_offset)
|
if (name_offset)
|
||||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
||||||
|
|
||||||
vgmstream->layout_type = layout_rws_blocked;
|
vgmstream->layout_type = layout_blocked_rws;
|
||||||
vgmstream->current_block_size = block_size / vgmstream->channels;
|
vgmstream->current_block_size = block_size / vgmstream->channels;
|
||||||
vgmstream->full_block_size = block_size_total;
|
vgmstream->full_block_size = block_size_total;
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
|||||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
rws_block_update(start_offset, vgmstream); /* block init */
|
block_update_rws(start_offset, vgmstream); /* block init */
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
|
@ -123,9 +123,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||||||
//todo fix repeat looping
|
//todo fix repeat looping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
|
//else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
|
||||||
//todo parse "adtl" (does it ever contain loop info in Wwise?)
|
// /* usually contains "cue"s with sample positions for events (ex. Platinum Games) but no real looping info */
|
||||||
}
|
//}
|
||||||
|
|
||||||
/* other Wwise specific: */
|
/* other Wwise specific: */
|
||||||
//"JUNK": optional padding for usually aligment (0-size JUNK exists too)
|
//"JUNK": optional padding for usually aligment (0-size JUNK exists too)
|
||||||
@ -194,15 +194,14 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IMA: /* common */
|
case IMA: /* common */
|
||||||
/* slightly modified XBOX-IMA with interleaved sub-blocks and LE/BE header */
|
/* slightly modified XBOX-IMA */
|
||||||
|
/* Wwise reuses common codec ids (ex. 0x0002 MSADPCM) for IMA so this parser should go AFTER riff.c avoid misdetection */
|
||||||
/* Wwise uses common codecs (ex. 0x0002 MSADPCM) so this parser should go AFTER riff.c avoid misdetection */
|
|
||||||
|
|
||||||
if (ww.bits_per_sample != 4) goto fail;
|
if (ww.bits_per_sample != 4) goto fail;
|
||||||
if (ww.block_align != 0x24 * ww.channels) goto fail;
|
if (ww.block_align != 0x24 * ww.channels) goto fail;
|
||||||
vgmstream->coding_type = coding_WWISE_IMA;
|
vgmstream->coding_type = coding_WWISE_IMA;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = ww.block_align;
|
vgmstream->interleave_block_size = ww.block_align / ww.channels;
|
||||||
vgmstream->codec_endian = ww.big_endian;
|
vgmstream->codec_endian = ww.big_endian;
|
||||||
|
|
||||||
if (ww.truncated) /* enough to get real samples */
|
if (ww.truncated) /* enough to get real samples */
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
#include "meta.h"
|
|
||||||
#include "../coding/coding.h"
|
|
||||||
|
|
||||||
/* XWAV - renamed WAV with XBOX-IMA
|
|
||||||
* (could be parsed as RIFF/.lwav but has a custom loop chunk and multichannel) */
|
|
||||||
VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile) {
|
|
||||||
VGMSTREAM * vgmstream = NULL;
|
|
||||||
int loop_flag, channel_count;
|
|
||||||
off_t start_offset;
|
|
||||||
|
|
||||||
/* check extension */
|
|
||||||
if (!check_extensions(streamFile,"xwav"))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* check for headers */
|
|
||||||
if(!((read_32bitBE(0x00,streamFile) == 0x52494646) && /* "RIFF" */
|
|
||||||
(read_32bitBE(0x08,streamFile) == 0x57415645) && /* "WAVE" */
|
|
||||||
(read_32bitBE(0x0C,streamFile) == 0x666D7420) && /* "fmt " */
|
|
||||||
(read_16bitLE(0x14,streamFile) == 0x0069))) /* codec */
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* loop chunk found on Koei/Omega Force games [Crimson Sea, Dynasty Warriors 5] */
|
|
||||||
loop_flag = (read_32bitBE(0x28,streamFile) == 0x77736D70); /* "wsmp" */
|
|
||||||
channel_count = read_16bitLE(0x16,streamFile);
|
|
||||||
|
|
||||||
/* search for "data" */
|
|
||||||
start_offset = 0x1C;
|
|
||||||
do {
|
|
||||||
if (read_32bitBE(start_offset,streamFile)==0x64617461)
|
|
||||||
break;
|
|
||||||
start_offset += 0x04;
|
|
||||||
} while (start_offset < (off_t)get_streamfile_size(streamFile));
|
|
||||||
|
|
||||||
if (start_offset >= (off_t)get_streamfile_size(streamFile))
|
|
||||||
goto fail;
|
|
||||||
start_offset += 0x04;
|
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
|
||||||
if (!vgmstream) goto fail;
|
|
||||||
|
|
||||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(read_32bitLE(start_offset,streamFile), vgmstream->channels);
|
|
||||||
vgmstream->sample_rate = read_32bitLE(0x18,streamFile);
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = read_32bitLE(0x4C,streamFile);
|
|
||||||
vgmstream->loop_end_sample = vgmstream->loop_start_sample + read_32bitLE(0x50,streamFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
vgmstream->coding_type = coding_XBOX_IMA;
|
|
||||||
vgmstream->layout_type = layout_none;
|
|
||||||
vgmstream->meta_type = meta_XBOX_RIFF;
|
|
||||||
|
|
||||||
//if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
|
||||||
// goto fail;
|
|
||||||
|
|
||||||
//custom init
|
|
||||||
{
|
|
||||||
int i, ch;
|
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
||||||
|
|
||||||
if (channel_count > 2) { /* multichannel interleaved init */
|
|
||||||
for (i=0, ch=0;i<channel_count;i++,ch++) {
|
|
||||||
if ((ch&2) && (i!=0)) {
|
|
||||||
ch = 0;
|
|
||||||
start_offset += 0x24*2;
|
|
||||||
}
|
|
||||||
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x24);
|
|
||||||
vgmstream->ch[i].offset = start_offset + 0x04;
|
|
||||||
|
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for (i=0; i < channel_count; i++) {
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x24);
|
|
||||||
vgmstream->ch[i].offset = start_offset + 0x04;
|
|
||||||
|
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vgmstream;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
close_vgmstream(vgmstream);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
@ -993,6 +993,27 @@ int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size) {
|
|||||||
streamFile->get_name(streamFile,buffer,size);
|
streamFile->get_name(streamFile,buffer,size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
int get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||||
|
char foldername[PATH_LIMIT];
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
streamFile->get_name(streamFile,foldername,sizeof(foldername));
|
||||||
|
|
||||||
|
//todo Windows CMD accepts both \\ and /, better way to handle this?
|
||||||
|
path = strrchr(foldername,'\\');
|
||||||
|
if (!path)
|
||||||
|
path = strrchr(foldername,'/');
|
||||||
|
if (path != NULL)
|
||||||
|
path = path+1;
|
||||||
|
|
||||||
|
//todo validate sizes and copy sensible max
|
||||||
|
if (path) {
|
||||||
|
strcpy(buffer, path);
|
||||||
|
} else {
|
||||||
|
strcpy(buffer, foldername);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size) {
|
||||||
const char *path;
|
const char *path;
|
||||||
|
|
||||||
|
@ -179,6 +179,7 @@ int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset,
|
|||||||
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int size_big_endian, int zero_size_end);
|
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int size_big_endian, int zero_size_end);
|
||||||
|
|
||||||
int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
|
int get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
|
||||||
|
int get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size);
|
||||||
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
|
int get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
|
||||||
int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
|
int get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
@ -55,7 +55,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||||||
init_vgmstream_ps2_ild,
|
init_vgmstream_ps2_ild,
|
||||||
init_vgmstream_ps2_pnb,
|
init_vgmstream_ps2_pnb,
|
||||||
init_vgmstream_xbox_wavm,
|
init_vgmstream_xbox_wavm,
|
||||||
init_vgmstream_xbox_xwav,
|
|
||||||
init_vgmstream_ngc_str,
|
init_vgmstream_ngc_str,
|
||||||
init_vgmstream_ea_schl,
|
init_vgmstream_ea_schl,
|
||||||
init_vgmstream_caf,
|
init_vgmstream_caf,
|
||||||
@ -628,7 +627,9 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) {
|
|||||||
VGMSTREAMCHANNEL * start_channels;
|
VGMSTREAMCHANNEL * start_channels;
|
||||||
VGMSTREAMCHANNEL * loop_channels;
|
VGMSTREAMCHANNEL * loop_channels;
|
||||||
|
|
||||||
if (channel_count <= 0) return NULL;
|
/* up to ~16 aren't too rare for multilayered files, more is probably a bug */
|
||||||
|
if (channel_count <= 0 || channel_count > 64)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
vgmstream = calloc(1,sizeof(VGMSTREAM));
|
vgmstream = calloc(1,sizeof(VGMSTREAM));
|
||||||
if (!vgmstream) return NULL;
|
if (!vgmstream) return NULL;
|
||||||
@ -969,13 +970,13 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
|||||||
case layout_filp_blocked:
|
case layout_filp_blocked:
|
||||||
case layout_blocked_ivaud:
|
case layout_blocked_ivaud:
|
||||||
case layout_blocked_ea_swvr:
|
case layout_blocked_ea_swvr:
|
||||||
case layout_ps2_adm_blocked:
|
case layout_blocked_adm:
|
||||||
case layout_dsp_bdsp_blocked:
|
case layout_dsp_bdsp_blocked:
|
||||||
case layout_tra_blocked:
|
case layout_tra_blocked:
|
||||||
case layout_ps2_iab_blocked:
|
case layout_ps2_iab_blocked:
|
||||||
case layout_ps2_strlr_blocked:
|
case layout_ps2_strlr_blocked:
|
||||||
case layout_rws_blocked:
|
case layout_blocked_rws:
|
||||||
case layout_hwas_blocked:
|
case layout_blocked_hwas:
|
||||||
case layout_blocked_ea_sns:
|
case layout_blocked_ea_sns:
|
||||||
case layout_blocked_awc:
|
case layout_blocked_awc:
|
||||||
case layout_blocked_vgs:
|
case layout_blocked_vgs:
|
||||||
@ -1072,6 +1073,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
case coding_XBOX_IMA:
|
case coding_XBOX_IMA:
|
||||||
case coding_XBOX_IMA_int:
|
case coding_XBOX_IMA_int:
|
||||||
case coding_FSB_IMA:
|
case coding_FSB_IMA:
|
||||||
|
case coding_WWISE_IMA:
|
||||||
return 64;
|
return 64;
|
||||||
case coding_APPLE_IMA4:
|
case coding_APPLE_IMA4:
|
||||||
return 64;
|
return 64;
|
||||||
@ -1079,7 +1081,6 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
case coding_REF_IMA:
|
case coding_REF_IMA:
|
||||||
return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
return ((vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels) + 1;
|
||||||
case coding_RAD_IMA:
|
case coding_RAD_IMA:
|
||||||
case coding_WWISE_IMA:
|
|
||||||
return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels;
|
return (vgmstream->interleave_block_size - 0x04*vgmstream->channels) * 2 / vgmstream->channels;
|
||||||
case coding_NDS_IMA:
|
case coding_NDS_IMA:
|
||||||
case coding_DAT4_IMA:
|
case coding_DAT4_IMA:
|
||||||
@ -1146,6 +1147,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
return 128*2;
|
return 128*2;
|
||||||
case coding_MC3:
|
case coding_MC3:
|
||||||
return 10;
|
return 10;
|
||||||
|
case coding_FADPCM:
|
||||||
|
return 256; /* (0x8c - 0xc) * 2 */
|
||||||
case coding_EA_MT:
|
case coding_EA_MT:
|
||||||
return 432;
|
return 432;
|
||||||
case coding_CRI_HCA:
|
case coding_CRI_HCA:
|
||||||
@ -1227,7 +1230,6 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
case coding_RAD_IMA:
|
case coding_RAD_IMA:
|
||||||
case coding_NDS_IMA:
|
case coding_NDS_IMA:
|
||||||
case coding_DAT4_IMA:
|
case coding_DAT4_IMA:
|
||||||
case coding_WWISE_IMA:
|
|
||||||
case coding_REF_IMA:
|
case coding_REF_IMA:
|
||||||
return vgmstream->interleave_block_size;
|
return vgmstream->interleave_block_size;
|
||||||
case coding_AWC_IMA:
|
case coding_AWC_IMA:
|
||||||
@ -1240,8 +1242,11 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
case coding_UBI_IMA: /* variable (PCM then IMA) */
|
case coding_UBI_IMA: /* variable (PCM then IMA) */
|
||||||
return 0;
|
return 0;
|
||||||
case coding_XBOX_IMA:
|
case coding_XBOX_IMA:
|
||||||
|
//todo should be 0x48 when stereo, but blocked/interleave layout don't understand stereo codecs
|
||||||
|
return 0x24; //vgmstream->channels==1 ? 0x24 : 0x48;
|
||||||
case coding_XBOX_IMA_int:
|
case coding_XBOX_IMA_int:
|
||||||
case coding_FSB_IMA:
|
case coding_FSB_IMA:
|
||||||
|
case coding_WWISE_IMA:
|
||||||
return 0x24;
|
return 0x24;
|
||||||
case coding_APPLE_IMA4:
|
case coding_APPLE_IMA4:
|
||||||
return 0x22;
|
return 0x22;
|
||||||
@ -1299,6 +1304,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
return 0x90;
|
return 0x90;
|
||||||
case coding_MC3:
|
case coding_MC3:
|
||||||
return 0x04;
|
return 0x04;
|
||||||
|
case coding_FADPCM:
|
||||||
|
return 0x8c;
|
||||||
case coding_EA_MT:
|
case coding_EA_MT:
|
||||||
return 0; /* variable (frames of bit counts or PCM frames) */
|
return 0; /* variable (frames of bit counts or PCM frames) */
|
||||||
#ifdef VGM_USE_ATRAC9
|
#ifdef VGM_USE_ATRAC9
|
||||||
@ -1916,6 +1923,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
chan);
|
chan);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case coding_FADPCM:
|
||||||
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
decode_fadpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
|
vgmstream->channels,vgmstream->samples_into_block,
|
||||||
|
samples_to_do);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case coding_EA_MT:
|
case coding_EA_MT:
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
decode_ea_mt(vgmstream, buffer+samples_written*vgmstream->channels+chan,
|
decode_ea_mt(vgmstream, buffer+samples_written*vgmstream->channels+chan,
|
||||||
@ -2532,7 +2546,7 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
|
|||||||
* Inits vgmstreams' channels doing two things:
|
* Inits vgmstreams' channels doing two things:
|
||||||
* - sets the starting offset per channel (depending on the layout)
|
* - sets the starting offset per channel (depending on the layout)
|
||||||
* - opens its own streamfile from on a base one. One streamfile per channel may be open (to improve read/seeks).
|
* - opens its own streamfile from on a base one. One streamfile per channel may be open (to improve read/seeks).
|
||||||
* Should be called in metas before returning the VGMSTREAM..
|
* Should be called in metas before returning the VGMSTREAM.
|
||||||
*/
|
*/
|
||||||
int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset) {
|
int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t start_offset) {
|
||||||
STREAMFILE * file;
|
STREAMFILE * file;
|
||||||
|
@ -152,6 +152,7 @@ typedef enum {
|
|||||||
coding_MTAF, /* Konami MTAF ADPCM */
|
coding_MTAF, /* Konami MTAF ADPCM */
|
||||||
coding_MTA2, /* Konami MTA2 ADPCM */
|
coding_MTA2, /* Konami MTA2 ADPCM */
|
||||||
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
|
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
|
||||||
|
coding_FADPCM, /* FMOD FADPCM 4-bit ADCPM */
|
||||||
|
|
||||||
/* others */
|
/* others */
|
||||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
|
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
|
||||||
@ -238,15 +239,15 @@ typedef enum {
|
|||||||
layout_thp_blocked,
|
layout_thp_blocked,
|
||||||
layout_filp_blocked,
|
layout_filp_blocked,
|
||||||
layout_blocked_ea_swvr,
|
layout_blocked_ea_swvr,
|
||||||
layout_ps2_adm_blocked,
|
layout_blocked_adm,
|
||||||
layout_dsp_bdsp_blocked,
|
layout_dsp_bdsp_blocked,
|
||||||
layout_mxch_blocked,
|
layout_mxch_blocked,
|
||||||
layout_blocked_ivaud, /* GTA IV .ivaud blocks */
|
layout_blocked_ivaud, /* GTA IV .ivaud blocks */
|
||||||
layout_tra_blocked, /* DefJam Rapstar .tra blocks */
|
layout_tra_blocked, /* DefJam Rapstar .tra blocks */
|
||||||
layout_ps2_iab_blocked,
|
layout_ps2_iab_blocked,
|
||||||
layout_ps2_strlr_blocked,
|
layout_ps2_strlr_blocked,
|
||||||
layout_rws_blocked,
|
layout_blocked_rws,
|
||||||
layout_hwas_blocked,
|
layout_blocked_hwas,
|
||||||
layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
||||||
layout_blocked_awc, /* Rockstar AWC */
|
layout_blocked_awc, /* Rockstar AWC */
|
||||||
layout_blocked_vgs, /* Guitar Hero II (PS2) */
|
layout_blocked_vgs, /* Guitar Hero II (PS2) */
|
||||||
@ -456,7 +457,6 @@ typedef enum {
|
|||||||
meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */
|
meta_UBI_CKD, /* Ubisoft CKD RIFF header (Rayman Origins Wii) */
|
||||||
|
|
||||||
meta_XBOX_WAVM, /* XBOX WAVM File */
|
meta_XBOX_WAVM, /* XBOX WAVM File */
|
||||||
meta_XBOX_RIFF, /* XBOX RIFF/WAVE File */
|
|
||||||
meta_XBOX_WVS, /* XBOX WVS */
|
meta_XBOX_WVS, /* XBOX WVS */
|
||||||
meta_NGC_WVS, /* Metal Arms - Glitch in the System */
|
meta_NGC_WVS, /* Metal Arms - Glitch in the System */
|
||||||
meta_XBOX_MATX, /* XBOX MATX */
|
meta_XBOX_MATX, /* XBOX MATX */
|
||||||
@ -481,6 +481,7 @@ typedef enum {
|
|||||||
meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */
|
meta_RIFF_WAVE_POS, /* .wav + .pos for looping (Ys Complete PC) */
|
||||||
meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */
|
meta_RIFF_WAVE_labl, /* RIFF w/ loop Markers in LIST-adtl-labl */
|
||||||
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
|
meta_RIFF_WAVE_smpl, /* RIFF w/ loop data in smpl chunk */
|
||||||
|
meta_RIFF_WAVE_wsmp, /* RIFF w/ loop data in wsmp chunk */
|
||||||
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
|
meta_RIFF_WAVE_MWV, /* .mwv RIFF w/ loop data in ctrl chunk pflt */
|
||||||
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
meta_RIFF_WAVE_SNS, /* .sns RIFF */
|
||||||
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
meta_RIFX_WAVE, /* RIFX, for big-endian WAVs */
|
||||||
@ -550,7 +551,7 @@ typedef enum {
|
|||||||
meta_PS2_WAD, /* The golden Compass */
|
meta_PS2_WAD, /* The golden Compass */
|
||||||
meta_DSP_XIII, /* XIII, possibly more (Ubisoft header???) */
|
meta_DSP_XIII, /* XIII, possibly more (Ubisoft header???) */
|
||||||
meta_DSP_CABELAS, /* Cabelas games */
|
meta_DSP_CABELAS, /* Cabelas games */
|
||||||
meta_PS2_ADM, /* Dragon Quest 5 */
|
meta_PS2_ADM, /* Dragon Quest V (PS2) */
|
||||||
meta_PS2_LPCM, /* Ah! My Goddess */
|
meta_PS2_LPCM, /* Ah! My Goddess */
|
||||||
meta_DSP_BDSP, /* Ah! My Goddess */
|
meta_DSP_BDSP, /* Ah! My Goddess */
|
||||||
meta_PS2_VMS, /* Autobahn Raser - Police Madness */
|
meta_PS2_VMS, /* Autobahn Raser - Police Madness */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user