mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
commit
44a48fcad6
@ -59,6 +59,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("BAKA", baka);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BAR", bar);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BCSTM", bcstm);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BCWAV", bcwav);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BD3", bd3);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BDSP", bdsp);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BFSTM", bfstm);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("BFWAV", bfwav);
|
||||
@ -238,6 +239,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("RND", rnd);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RRDS", rrds);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RSD", rsd);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RSF", rsf);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RSM", rsm);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RSTM", rstm);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RVWS", rvws);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("RWAR", rwar);
|
||||
@ -263,6 +265,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("SC", sc);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SCD", scd);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SCK", sck);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SD9", sd9);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SDF", sdf);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SDT", sdt);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SEG", seg);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("SF0", sf0);
|
||||
|
@ -38,7 +38,7 @@ size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFi
|
||||
|
||||
/* ngc_dsp_decoder */
|
||||
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem);
|
||||
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave);
|
||||
size_t dsp_bytes_to_samples(size_t bytes, int channels);
|
||||
int32_t dsp_nibbles_to_samples(int32_t nibbles);
|
||||
void dsp_read_coefs_be(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t offset, off_t spacing);
|
||||
@ -276,4 +276,19 @@ void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * cha
|
||||
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
|
||||
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
|
||||
|
||||
|
||||
|
||||
/* An internal struct to pass around and simulate a bitstream. */
|
||||
typedef enum { BITSTREAM_MSF, BITSTREAM_VORBIS } vgm_bitstream_t;
|
||||
typedef struct {
|
||||
uint8_t * buf; /* buffer to read/write*/
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
off_t b_off; /* current offset in bits inside the buffer */
|
||||
off_t info_offset; /* for logging */
|
||||
vgm_bitstream_t mode; /* read/write modes */
|
||||
} vgm_bitstream;
|
||||
|
||||
int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value);
|
||||
int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value);
|
||||
|
||||
#endif /*_CODING_H*/
|
||||
|
@ -835,3 +835,149 @@ size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align) {
|
||||
* so (full_block_align / channels) DOESN'T give the size of a single channel (common in ATRAC3plus) */
|
||||
return (bytes / full_block_align) * 2048;
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************** */
|
||||
/* BITSTREAM */
|
||||
/* ******************************************** */
|
||||
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
|
||||
static int r_bits_vorbis(vgm_bitstream * ib, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = ib->b_off / 8; /* byte offset */
|
||||
pos = ib->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << i); /* bit to set in value */
|
||||
|
||||
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ib->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
|
||||
static int w_bits_vorbis(vgm_bitstream * ob, int num_bits, uint32_t value) {
|
||||
off_t off, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ob->b_off + num_bits > ob->bufsize*8) goto fail;
|
||||
|
||||
|
||||
off = ob->b_off / 8; /* byte offset */
|
||||
pos = ob->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_val = (1U << i); /* bit check for value */
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit to set in buf */
|
||||
|
||||
if (value & bit_val) /* is bit in val set? */
|
||||
ob->buf[off] |= bit_buf; /* set bit */
|
||||
else
|
||||
ob->buf[off] &= ~bit_buf; /* unset bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ob->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
|
||||
static int r_bits_msf(vgm_bitstream * ib, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = ib->b_off / 8; /* byte offset */
|
||||
pos = ib->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << (num_bits-1-i)); /* bit to set in value */
|
||||
|
||||
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++;
|
||||
if (pos%8 == 0) { /* new byte starts */
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ib->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
|
||||
static int w_bits_msf(vgm_bitstream * ob, int num_bits, uint32_t value) {
|
||||
off_t off, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ob->b_off + num_bits > ob->bufsize*8) goto fail;
|
||||
|
||||
|
||||
off = ob->b_off / 8; /* byte offset */
|
||||
pos = ob->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_val = (1U << (num_bits-1-i)); /* bit check for value */
|
||||
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit to set in buf */
|
||||
|
||||
if (value & bit_val) /* is bit in val set? */
|
||||
ob->buf[off] |= bit_buf; /* set bit */
|
||||
else
|
||||
ob->buf[off] &= ~bit_buf; /* unset bit */
|
||||
|
||||
pos++;
|
||||
if (pos%8 == 0) { /* new byte starts */
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ob->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value) {
|
||||
if (ib->mode == BITSTREAM_VORBIS)
|
||||
return r_bits_vorbis(ib,num_bits,value);
|
||||
else
|
||||
return r_bits_msf(ib,num_bits,value);
|
||||
}
|
||||
int w_bits(vgm_bitstream * ob, int num_bits, uint32_t value) {
|
||||
if (ob->mode == BITSTREAM_VORBIS)
|
||||
return w_bits_vorbis(ob,num_bits,value);
|
||||
else
|
||||
return w_bits_msf(ob,num_bits,value);
|
||||
}
|
||||
|
@ -18,8 +18,7 @@
|
||||
* Officially defined in "Microsoft Multimedia Standards Update" doc (RIFFNEW.pdf).
|
||||
*/
|
||||
|
||||
static const int32_t ADPCMTable[89] =
|
||||
{
|
||||
static const int ADPCMTable[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28, 31,
|
||||
34, 37, 41, 45, 50, 55, 60, 66,
|
||||
@ -34,8 +33,7 @@ static const int32_t ADPCMTable[89] =
|
||||
32767
|
||||
};
|
||||
|
||||
static const int IMA_IndexTable[16] =
|
||||
{
|
||||
static const int IMA_IndexTable[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
@ -45,17 +43,22 @@ static const int IMA_IndexTable[16] =
|
||||
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;
|
||||
|
||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
|
||||
sample_decoded = *hist1;
|
||||
step = ADPCMTable[*step_index];
|
||||
/* calculate diff = [signed] (step / 8) + (step / 4) + (step / 2) + (step) [when code = 4+2+1]
|
||||
* simplified through math, using bitwise ops to avoid rounding:
|
||||
* diff = (code + 1/2) * (step / 4)
|
||||
* > diff = (step * nibble / 4) + (step / 8)
|
||||
* > diff = (((step * nibble) + (step / 2)) / 4) */
|
||||
|
||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf; /* ADPCM code */
|
||||
sample_decoded = *hist1; /* predictor value */
|
||||
step = ADPCMTable[*step_index]; /* current step */
|
||||
|
||||
delta = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded += delta;
|
||||
|
||||
*hist1 = clamp16(sample_decoded);
|
||||
*step_index += IMA_IndexTable[sample_nibble];
|
||||
@ -63,21 +66,20 @@ static void std_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
||||
if (*step_index > 88) *step_index=88;
|
||||
}
|
||||
|
||||
/* Apple's IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend) */
|
||||
/* Apple's IMA variation. Exactly the same except it uses 16b history (probably more sensitive to overflow/sign extend?) */
|
||||
static void std_ima_expand_nibble_16(VGMSTREAMCHANNEL * stream, off_t byte_offset, int nibble_shift, int16_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 = step >> 3;
|
||||
if (sample_nibble & 1) delta += step >> 2;
|
||||
if (sample_nibble & 2) delta += step >> 1;
|
||||
if (sample_nibble & 4) delta += step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded += delta;
|
||||
|
||||
*hist1 = clamp16(sample_decoded); //no need for this actually
|
||||
*step_index += IMA_IndexTable[sample_nibble];
|
||||
@ -91,14 +93,12 @@ static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
||||
|
||||
sample_nibble = (read_8bit(byte_offset,stream->streamfile) >> nibble_shift)&0xf;
|
||||
sample_decoded = *hist1;
|
||||
step = ADPCMTable[*step_index];
|
||||
|
||||
sample_decoded = sample_decoded << 3;
|
||||
step = ADPCMTable[*step_index];
|
||||
delta = step * (sample_nibble & 7) * 2 + step;
|
||||
if (sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
delta = step * (sample_nibble & 7) * 2 + step; /* custom */
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded += delta;
|
||||
sample_decoded = sample_decoded >> 3;
|
||||
|
||||
*hist1 = clamp16(sample_decoded);
|
||||
@ -107,41 +107,41 @@ static void n3ds_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
||||
if (*step_index > 88) *step_index=88;
|
||||
}
|
||||
|
||||
/* update step_index before doing current sample */
|
||||
/* The Incredibles PC, updates step_index before doing current sample */
|
||||
static void snds_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_index += IMA_IndexTable[sample_nibble];
|
||||
if (*step_index < 0) *step_index=0;
|
||||
if (*step_index > 88) *step_index=88;
|
||||
|
||||
step = ADPCMTable[*step_index];
|
||||
delta = (sample_nibble & 7) * step / 4 + step / 8;
|
||||
if (sample_nibble & 8)
|
||||
delta = -delta;
|
||||
sample_decoded = *hist1 + delta;
|
||||
|
||||
delta = (sample_nibble & 7) * step / 4 + step / 8; /* standard IMA */
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded += delta;
|
||||
|
||||
*hist1 = clamp16(sample_decoded);
|
||||
}
|
||||
|
||||
/* algorithm by aluigi, unsure if it's a known IMA variation */
|
||||
/* Omikron: The Nomad Soul, algorithm by aluigi */
|
||||
static void otns_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 = 0;
|
||||
if(sample_nibble & 4) delta = step << 2;
|
||||
if(sample_nibble & 2) delta += step << 1;
|
||||
if(sample_nibble & 1) delta += step;
|
||||
delta >>= 2;
|
||||
if(sample_nibble & 8)
|
||||
sample_decoded -= delta;
|
||||
else
|
||||
sample_decoded += delta;
|
||||
if (sample_nibble & 8) delta = -delta;
|
||||
sample_decoded += delta;
|
||||
|
||||
*hist1 = clamp16(sample_decoded);
|
||||
*step_index += IMA_IndexTable[sample_nibble];
|
||||
@ -149,23 +149,22 @@ static void otns_ima_expand_nibble(VGMSTREAMCHANNEL * stream, off_t byte_offset,
|
||||
if (*step_index > 88) *step_index=88;
|
||||
}
|
||||
|
||||
/* algorithm by Zench (https://bitbucket.org/Zenchreal/decubisnd) */
|
||||
/* 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;
|
||||
|
||||
delta = (((sample_nibble & 7) * 2 + 1) * step) >> 3;
|
||||
if (sample_nibble & 8)
|
||||
delta = -delta;
|
||||
sample_decoded = *hist1 + delta;
|
||||
|
||||
*hist1 = clamp16(sample_decoded);
|
||||
}
|
||||
|
||||
/* ************************************ */
|
||||
|
@ -25,14 +25,6 @@
|
||||
#define EALAYER3_MAX_GRANULES 2
|
||||
#define EALAYER3_MAX_CHANNELS 2
|
||||
|
||||
/* helper to simulate a bitstream */
|
||||
typedef struct {
|
||||
uint8_t * buf; /* buffer to read/write*/
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
off_t b_off; /* current offset in bits inside the buffer */
|
||||
off_t info_offset; /* for logs */
|
||||
} ealayer3_bitstream;
|
||||
|
||||
/* parsed info from a single EALayer3 frame */
|
||||
typedef struct {
|
||||
/* EALayer3 v1 header */
|
||||
@ -81,18 +73,14 @@ typedef struct {
|
||||
} ealayer3_frame_info;
|
||||
|
||||
|
||||
static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b);
|
||||
static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os);
|
||||
static int ealayer3_parse_frame(mpeg_codec_data *data, vgm_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_parse_frame_v1(vgm_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b);
|
||||
static int ealayer3_parse_frame_v2(vgm_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_parse_frame_common(vgm_bitstream *is, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_rebuild_mpeg_frame(vgm_bitstream* is_0, ealayer3_frame_info* eaf_0, vgm_bitstream* is_1, ealayer3_frame_info* eaf_1, vgm_bitstream* os);
|
||||
static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, ealayer3_frame_info * eaf);
|
||||
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start);
|
||||
|
||||
static int r_bits(ealayer3_bitstream * iw, int num_bits, uint32_t * value);
|
||||
static int w_bits(ealayer3_bitstream * ow, int num_bits, uint32_t value);
|
||||
|
||||
|
||||
/* **************************************************************************** */
|
||||
/* EXTERNAL API */
|
||||
/* **************************************************************************** */
|
||||
@ -101,7 +89,7 @@ static int w_bits(ealayer3_bitstream * ow, int num_bits, uint32_t value);
|
||||
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
|
||||
int ok;
|
||||
ealayer3_frame_info eaf;
|
||||
ealayer3_bitstream is = {0};
|
||||
vgm_bitstream is = {0};
|
||||
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
|
||||
|
||||
//;VGM_LOG("init at %lx\n", start_offset);
|
||||
@ -135,7 +123,7 @@ int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *
|
||||
off_t info_offset = stream->offset;
|
||||
|
||||
ealayer3_frame_info eaf_0, eaf_1;
|
||||
ealayer3_bitstream is_0 = {0}, is_1 = {0}, os = {0};
|
||||
vgm_bitstream is_0 = {0}, is_1 = {0}, os = {0};
|
||||
uint8_t ibuf_0[EALAYER3_EA_FRAME_BUFFER_SIZE], ibuf_1[EALAYER3_EA_FRAME_BUFFER_SIZE];
|
||||
|
||||
/* read first frame/granule, or PCM-only frame (found alone at the end of SCHl streams) */
|
||||
@ -213,7 +201,7 @@ fail:
|
||||
/* INTERNAL HELPERS */
|
||||
/* **************************************************************************** */
|
||||
|
||||
static int ealayer3_parse_frame(mpeg_codec_data *data, ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
static int ealayer3_parse_frame(mpeg_codec_data *data, vgm_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
int ok;
|
||||
|
||||
/* make sure as there is re-parsing in loops */
|
||||
@ -235,7 +223,7 @@ fail:
|
||||
|
||||
|
||||
/* read V1"a" (in SCHl) and V1"b" (in SNS) EALayer3 frame */
|
||||
static int ealayer3_parse_frame_v1(ealayer3_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b) {
|
||||
static int ealayer3_parse_frame_v1(vgm_bitstream *is, ealayer3_frame_info * eaf, int channels_per_frame, int is_v1b) {
|
||||
int ok;
|
||||
|
||||
/* read EA-frame V1 header */
|
||||
@ -282,7 +270,7 @@ fail:
|
||||
|
||||
/* read V2"PCM" and V2"Spike" EALayer3 frame (exactly the same but V2P seems to have bigger
|
||||
* PCM blocks and maybe smaller frames) */
|
||||
static int ealayer3_parse_frame_v2(ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
static int ealayer3_parse_frame_v2(vgm_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
int ok;
|
||||
|
||||
/* read EA-frame V2 header */
|
||||
@ -328,7 +316,7 @@ fail:
|
||||
|
||||
|
||||
/* parses an EALayer3 frame (common part) */
|
||||
static int ealayer3_parse_frame_common(ealayer3_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
static int ealayer3_parse_frame_common(vgm_bitstream *is, ealayer3_frame_info * eaf) {
|
||||
/* index tables */
|
||||
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
|
||||
static const int sample_rates[4][4] = { /* [version_index][sample rate index] */
|
||||
@ -412,7 +400,7 @@ fail:
|
||||
|
||||
|
||||
/* converts an EALAYER3 frame to a standard MPEG frame from pre-parsed info */
|
||||
static int ealayer3_rebuild_mpeg_frame(ealayer3_bitstream* is_0, ealayer3_frame_info* eaf_0, ealayer3_bitstream* is_1, ealayer3_frame_info* eaf_1, ealayer3_bitstream* os) {
|
||||
static int ealayer3_rebuild_mpeg_frame(vgm_bitstream* is_0, ealayer3_frame_info* eaf_0, vgm_bitstream* is_1, ealayer3_frame_info* eaf_1, vgm_bitstream* os) {
|
||||
uint32_t c = 0;
|
||||
int i,j;
|
||||
int expected_bitrate_index, expected_frame_size;
|
||||
@ -663,7 +651,7 @@ fail:
|
||||
static int ealayer3_skip_data(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream, int at_start) {
|
||||
int ok, i;
|
||||
ealayer3_frame_info eaf;
|
||||
ealayer3_bitstream is = {0};
|
||||
vgm_bitstream is = {0};
|
||||
uint8_t ibuf[EALAYER3_EA_FRAME_BUFFER_SIZE];
|
||||
int skips = at_start ? num_stream : data->streams_size - 1 - num_stream;
|
||||
|
||||
@ -685,68 +673,4 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ********************************************* */
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Order is BE (MSF). */
|
||||
static int r_bits(ealayer3_bitstream * is, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || is->b_off + num_bits > is->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = is->b_off / 8; /* byte offset */
|
||||
pos = is->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << (num_bits-1-i)); /* bit to set in value */
|
||||
|
||||
if (is->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++;
|
||||
if (pos%8 == 0) { /* new byte starts */
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
is->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write bits (max 32) to buf and update the bit offset. Order is BE (MSF). */
|
||||
static int w_bits(ealayer3_bitstream * os, int num_bits, uint32_t value) {
|
||||
off_t off, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || os->b_off + num_bits > os->bufsize*8) goto fail;
|
||||
|
||||
|
||||
off = os->b_off / 8; /* byte offset */
|
||||
pos = os->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_val = (1U << (num_bits-1-i)); /* bit check for value */
|
||||
bit_buf = (1U << (8-1-pos)) & 0xFF; /* bit to set in buf */
|
||||
|
||||
if (value & bit_val) /* is bit in val set? */
|
||||
os->buf[off] |= bit_buf; /* set bit */
|
||||
else
|
||||
os->buf[off] &= ~bit_buf; /* unset bit */
|
||||
|
||||
pos++;
|
||||
if (pos%8 == 0) { /* new byte starts */
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
os->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define _MPEG_DECODER_H_
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* used by mpeg_decoder.c, but scattered in other .c files */
|
||||
#ifdef VGM_USE_MPEG
|
||||
|
@ -37,13 +37,11 @@ void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
||||
}
|
||||
|
||||
/* read from memory rather than a file */
|
||||
void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) {
|
||||
static void decode_ngc_dsp_subint_internal(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, uint8_t * mem) {
|
||||
int i=first_sample;
|
||||
int32_t sample_count;
|
||||
|
||||
int framesin = first_sample/14;
|
||||
|
||||
int8_t header = mem[framesin*8];
|
||||
int8_t header = mem[0];
|
||||
int32_t scale = 1 << (header & 0xf);
|
||||
int coef_index = (header >> 4) & 0xf;
|
||||
int32_t hist1 = stream->adpcm_history1_16;
|
||||
@ -54,7 +52,7 @@ void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
|
||||
first_sample = first_sample%14;
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
int sample_byte = mem[framesin*8+1+i/2];
|
||||
int sample_byte = mem[1 + i/2];
|
||||
|
||||
outbuf[sample_count] = clamp16((
|
||||
(((i&1?
|
||||
@ -72,6 +70,27 @@ void decode_ngc_dsp_mem(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
|
||||
stream->adpcm_history2_16 = hist2;
|
||||
}
|
||||
|
||||
/* decode DSP with byte-interleaved frames (ex. 0x08: 1122112211221122) */
|
||||
void decode_ngc_dsp_subint(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int interleave) {
|
||||
uint8_t sample_data[0x08];
|
||||
int i;
|
||||
|
||||
int framesin = first_sample/14;
|
||||
|
||||
for (i=0; i < 0x08; i++) {
|
||||
/* base + current frame + subint section + subint byte + channel adjust */
|
||||
sample_data[i] = read_8bit(
|
||||
stream->offset
|
||||
+ framesin*(0x08*channelspacing)
|
||||
+ i/interleave * interleave * channelspacing
|
||||
+ i%interleave
|
||||
+ interleave * channel, stream->streamfile);
|
||||
}
|
||||
|
||||
decode_ngc_dsp_subint_internal(stream, outbuf, channelspacing, first_sample, samples_to_do, sample_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The original DSP spec uses nibble counts for loop points, and some
|
||||
* variants don't have a proper sample count, so we (who are interested
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define _VORBIS_CUSTOM_DECODER_H_
|
||||
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* used by vorbis_custom_decoder.c, but scattered in other .c files */
|
||||
#ifdef VGM_USE_VORBIS
|
||||
|
@ -8,15 +8,6 @@
|
||||
/* DEFS */
|
||||
/* **************************************************************************** */
|
||||
|
||||
/* An internal struct to pass around and simulate a bitstream. */
|
||||
typedef struct {
|
||||
uint8_t * buf; /* buffer to read/write*/
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
off_t b_off; /* current offset in bits inside the buffer */
|
||||
} vgm_bitstream;
|
||||
|
||||
static int r_bits(vgm_bitstream * iw, int num_bits, uint32_t * value);
|
||||
|
||||
static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size);
|
||||
static int build_header_comment(uint8_t * buf, size_t bufsize);
|
||||
|
||||
@ -137,6 +128,7 @@ static int get_packet_header(STREAMFILE *streamFile, off_t *offset, size_t *size
|
||||
ib.buf = ibuf;
|
||||
ib.bufsize = ibufsize;
|
||||
ib.b_off = 0;
|
||||
ib.mode = BITSTREAM_VORBIS;
|
||||
|
||||
/* read using Vorbis weird LSF */
|
||||
r_bits(&ib, 4,&size_bits);
|
||||
@ -157,35 +149,4 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
|
||||
static int r_bits(vgm_bitstream * ib, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ib->b_off + num_bits > ib->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = ib->b_off / 8; /* byte offset */
|
||||
pos = ib->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << i); /* bit to set in value */
|
||||
|
||||
if (ib->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ib->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -13,25 +13,17 @@
|
||||
/* DEFS */
|
||||
/* **************************************************************************** */
|
||||
|
||||
/* An internal struct to pass around and simulate a bitstream.
|
||||
* Mainly to keep code cleaner and somewhat closer to ww2ogg */
|
||||
typedef struct {
|
||||
uint8_t * buf; /* buffer to read/write*/
|
||||
size_t bufsize; /* max size of the buffer */
|
||||
off_t b_off; /* current offset in bits inside the buffer */
|
||||
} ww_bitstream;
|
||||
|
||||
static int build_header_identification(uint8_t * buf, size_t bufsize, int channels, int sample_rate, int blocksize_short, int blocksize_long);
|
||||
static int build_header_comment(uint8_t * buf, size_t bufsize);
|
||||
static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_t header_type, int * granulepos, size_t * packet_size, int big_endian);
|
||||
static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
|
||||
static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels);
|
||||
|
||||
static int ww2ogg_generate_vorbis_packet(ww_bitstream * ow, ww_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
|
||||
static int ww2ogg_generate_vorbis_setup(ww_bitstream * ow, ww_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile);
|
||||
static int ww2ogg_codebook_library_copy(ww_bitstream * ow, ww_bitstream * iw);
|
||||
static int ww2ogg_codebook_library_rebuild(ww_bitstream * ow, ww_bitstream * iw, size_t cb_size, STREAMFILE *streamFile);
|
||||
static int ww2ogg_codebook_library_rebuild_by_id(ww_bitstream * ow, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile);
|
||||
static int ww2ogg_generate_vorbis_packet(vgm_bitstream * ow, vgm_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian);
|
||||
static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile);
|
||||
static int ww2ogg_codebook_library_copy(vgm_bitstream * ow, vgm_bitstream * iw);
|
||||
static int ww2ogg_codebook_library_rebuild(vgm_bitstream * ow, vgm_bitstream * iw, size_t cb_size, STREAMFILE *streamFile);
|
||||
static int ww2ogg_codebook_library_rebuild_by_id(vgm_bitstream * ow, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile);
|
||||
static int ww2ogg_tremor_ilog(unsigned int v);
|
||||
static unsigned int ww2ogg_tremor_book_maptype1_quantvals(unsigned int entries, unsigned int dimensions);
|
||||
|
||||
@ -39,9 +31,6 @@ static int load_wvc(uint8_t * ibuf, size_t ibufsize, uint32_t codebook_id, wwise
|
||||
static int load_wvc_file(uint8_t * buf, size_t bufsize, uint32_t codebook_id, STREAMFILE *streamFile);
|
||||
static int load_wvc_array(uint8_t * buf, size_t bufsize, uint32_t codebook_id, wwise_setup_t setup_type);
|
||||
|
||||
static int r_bits(ww_bitstream * iw, int num_bits, uint32_t * value);
|
||||
static int w_bits(ww_bitstream * ow, int num_bits, uint32_t value);
|
||||
|
||||
|
||||
/* **************************************************************************** */
|
||||
/* EXTERNAL API */
|
||||
@ -165,7 +154,7 @@ static int get_packet_header(STREAMFILE *streamFile, off_t offset, wwise_header_
|
||||
|
||||
/* Transforms a Wwise data packet into a real Vorbis one (depending on config) */
|
||||
static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) {
|
||||
ww_bitstream ow, iw;
|
||||
vgm_bitstream ow, iw;
|
||||
int rc, granulepos;
|
||||
size_t header_size, packet_size;
|
||||
|
||||
@ -183,11 +172,13 @@ static int rebuild_packet(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFil
|
||||
/* prepare helper structs */
|
||||
ow.buf = obuf;
|
||||
ow.bufsize = obufsize;
|
||||
ow.b_off = 0 ;
|
||||
ow.b_off = 0;
|
||||
ow.mode = BITSTREAM_VORBIS;
|
||||
|
||||
iw.buf = ibuf;
|
||||
iw.bufsize = ibufsize;
|
||||
iw.b_off = 0;
|
||||
iw.mode = BITSTREAM_VORBIS;
|
||||
|
||||
rc = ww2ogg_generate_vorbis_packet(&ow,&iw, streamFile,offset, data, big_endian);
|
||||
if (!rc) goto fail;
|
||||
@ -206,7 +197,7 @@ fail:
|
||||
|
||||
/* Transforms a Wwise setup packet into a real Vorbis one (depending on config). */
|
||||
static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian, int channels) {
|
||||
ww_bitstream ow, iw;
|
||||
vgm_bitstream ow, iw;
|
||||
int rc, granulepos;
|
||||
size_t header_size, packet_size;
|
||||
|
||||
@ -226,10 +217,12 @@ static int rebuild_setup(uint8_t * obuf, size_t obufsize, STREAMFILE *streamFile
|
||||
ow.buf = obuf;
|
||||
ow.bufsize = obufsize;
|
||||
ow.b_off = 0;
|
||||
ow.mode = BITSTREAM_VORBIS;
|
||||
|
||||
iw.buf = ibuf;
|
||||
iw.bufsize = ibufsize;
|
||||
iw.b_off = 0;
|
||||
iw.mode = BITSTREAM_VORBIS;
|
||||
|
||||
rc = ww2ogg_generate_vorbis_setup(&ow,&iw, data, channels, packet_size, streamFile);
|
||||
if (!rc) goto fail;
|
||||
@ -295,7 +288,7 @@ static int build_header_comment(uint8_t * buf, size_t bufsize) {
|
||||
|
||||
/* Copy packet as-is or rebuild first byte if mod_packets is used.
|
||||
* (ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-720004.3) */
|
||||
static int ww2ogg_generate_vorbis_packet(ww_bitstream * ow, ww_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) {
|
||||
static int ww2ogg_generate_vorbis_packet(vgm_bitstream * ow, vgm_bitstream * iw, STREAMFILE *streamFile, off_t offset, vorbis_custom_codec_data * data, int big_endian) {
|
||||
int i,granule;
|
||||
size_t header_size, packet_size, data_size;
|
||||
|
||||
@ -350,10 +343,13 @@ static int ww2ogg_generate_vorbis_packet(ww_bitstream * ow, ww_bitstream * iw, S
|
||||
/* get next first byte to read next_mode_number */
|
||||
uint32_t next_mode_number;
|
||||
uint8_t nbuf[1];
|
||||
ww_bitstream nw;
|
||||
vgm_bitstream nw;
|
||||
|
||||
nw.buf = nbuf;
|
||||
nw.bufsize = 1;
|
||||
nw.b_off = 0;
|
||||
nw.mode = BITSTREAM_VORBIS;
|
||||
|
||||
|
||||
if (read_streamfile(nw.buf, next_offset + next_header_size, nw.bufsize, streamFile) != nw.bufsize)
|
||||
goto fail;
|
||||
@ -409,7 +405,7 @@ fail:
|
||||
|
||||
/* Rebuild a Wwise setup (simplified with removed stuff), recreating all six setup parts.
|
||||
* (ref: https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-650004.2.4) */
|
||||
static int ww2ogg_generate_vorbis_setup(ww_bitstream * ow, ww_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile) {
|
||||
static int ww2ogg_generate_vorbis_setup(vgm_bitstream * ow, vgm_bitstream * iw, vorbis_custom_codec_data * data, int channels, size_t packet_size, STREAMFILE *streamFile) {
|
||||
int i,j,k;
|
||||
uint32_t codebook_count = 0, floor_count = 0, residue_count = 0;
|
||||
uint32_t codebook_count_less1 = 0;
|
||||
@ -798,7 +794,7 @@ fail:
|
||||
|
||||
|
||||
/* copies Vorbis codebooks (untouched, but size uncertain) */
|
||||
static int ww2ogg_codebook_library_copy(ww_bitstream * ow, ww_bitstream * iw) {
|
||||
static int ww2ogg_codebook_library_copy(vgm_bitstream * ow, vgm_bitstream * iw) {
|
||||
int i;
|
||||
uint32_t id = 0, dimensions = 0, entries = 0;
|
||||
uint32_t ordered = 0, lookup_type = 0;
|
||||
@ -914,7 +910,7 @@ fail:
|
||||
|
||||
|
||||
/* rebuilds a Wwise codebook into a Vorbis codebook */
|
||||
static int ww2ogg_codebook_library_rebuild(ww_bitstream * ow, ww_bitstream * iw, size_t cb_size, STREAMFILE *streamFile) {
|
||||
static int ww2ogg_codebook_library_rebuild(vgm_bitstream * ow, vgm_bitstream * iw, size_t cb_size, STREAMFILE *streamFile) {
|
||||
int i;
|
||||
uint32_t id = 0, dimensions = 0, entries = 0;
|
||||
uint32_t ordered = 0, lookup_type = 0;
|
||||
@ -1038,11 +1034,11 @@ fail:
|
||||
}
|
||||
|
||||
/* rebuilds an external Wwise codebook referenced by id to a Vorbis codebook */
|
||||
static int ww2ogg_codebook_library_rebuild_by_id(ww_bitstream * ow, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile) {
|
||||
static int ww2ogg_codebook_library_rebuild_by_id(vgm_bitstream * ow, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile) {
|
||||
size_t ibufsize = 0x8000; /* arbitrary max size of a codebook */
|
||||
uint8_t ibuf[0x8000]; /* Wwise codebook buffer */
|
||||
size_t cb_size;
|
||||
ww_bitstream iw;
|
||||
vgm_bitstream iw;
|
||||
|
||||
cb_size = load_wvc(ibuf,ibufsize, codebook_id, setup_type, streamFile);
|
||||
if (cb_size == 0) goto fail;
|
||||
@ -1050,6 +1046,7 @@ static int ww2ogg_codebook_library_rebuild_by_id(ww_bitstream * ow, uint32_t cod
|
||||
iw.buf = ibuf;
|
||||
iw.bufsize = ibufsize;
|
||||
iw.b_off = 0;
|
||||
iw.mode = BITSTREAM_VORBIS;
|
||||
|
||||
return ww2ogg_codebook_library_rebuild(ow, &iw, cb_size, streamFile);
|
||||
fail:
|
||||
@ -1228,70 +1225,4 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ********************************************* */
|
||||
|
||||
/* Read bits (max 32) from buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. from 2 bytes 00100111 00000001 we can could read 4b=0111 and 6b=010010, 6b=remainder (second value is split into the 2nd byte) */
|
||||
static int r_bits(ww_bitstream * iw, int num_bits, uint32_t * value) {
|
||||
off_t off, pos;
|
||||
int i, bit_buf, bit_val;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || iw->b_off + num_bits > iw->bufsize*8) goto fail;
|
||||
|
||||
*value = 0; /* set all bits to 0 */
|
||||
off = iw->b_off / 8; /* byte offset */
|
||||
pos = iw->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit check for buf */
|
||||
bit_val = (1U << i); /* bit to set in value */
|
||||
|
||||
if (iw->buf[off] & bit_buf) /* is bit in buf set? */
|
||||
*value |= bit_val; /* set bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
iw->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write bits (max 32) to buf and update the bit offset. Vorbis packs values in LSB order and byte by byte.
|
||||
* (ex. writing 1101011010 from b_off 2 we get 01101011 00001101 (value split, and 11 in the first byte skipped)*/
|
||||
static int w_bits(ww_bitstream * ow, int num_bits, uint32_t value) {
|
||||
off_t off, pos;
|
||||
int i, bit_val, bit_buf;
|
||||
if (num_bits == 0) return 1;
|
||||
if (num_bits > 32 || num_bits < 0 || ow->b_off + num_bits > ow->bufsize*8) goto fail;
|
||||
|
||||
|
||||
off = ow->b_off / 8; /* byte offset */
|
||||
pos = ow->b_off % 8; /* bit sub-offset */
|
||||
for (i = 0; i < num_bits; i++) {
|
||||
bit_val = (1U << i); /* bit check for value */
|
||||
bit_buf = (1U << pos) & 0xFF; /* bit to set in buf */
|
||||
|
||||
if (value & bit_val) /* is bit in val set? */
|
||||
ow->buf[off] |= bit_buf; /* set bit */
|
||||
else
|
||||
ow->buf[off] &= ~bit_buf; /* unset bit */
|
||||
|
||||
pos++; /* new byte starts */
|
||||
if (pos%8 == 0) {
|
||||
pos = 0;
|
||||
off++;
|
||||
}
|
||||
}
|
||||
|
||||
ow->b_off += num_bits;
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -52,6 +52,7 @@ static const char* extension_list[] = {
|
||||
"bar",
|
||||
"bcstm",
|
||||
"bcwav",
|
||||
"bd3", //txth/reserved [Elevator Action Deluxe (PS3)]
|
||||
"bdsp",
|
||||
"bfstm",
|
||||
"bfwav",
|
||||
@ -233,7 +234,8 @@ static const char* extension_list[] = {
|
||||
"rrds",
|
||||
"rsd",
|
||||
"rsf",
|
||||
"rstm",
|
||||
"rsm",
|
||||
"rstm", //rsm header id
|
||||
"rvws",
|
||||
"rwar",
|
||||
"rwav",
|
||||
@ -258,6 +260,7 @@ static const char* extension_list[] = {
|
||||
"scd",
|
||||
"sck",
|
||||
"sd9",
|
||||
"sdf",
|
||||
"sdt",
|
||||
"seg",
|
||||
"sf0",
|
||||
@ -382,6 +385,7 @@ static const char* extension_list[] = {
|
||||
//, NULL //end mark
|
||||
};
|
||||
|
||||
/* List supported formats and return elements in the list, for plugins that need to know. */
|
||||
const char ** vgmstream_get_formats(size_t * size) {
|
||||
*size = sizeof(extension_list) / sizeof(char*);
|
||||
return extension_list;
|
||||
@ -427,6 +431,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_CRI_ADX_enc_9, "CRI ADX 4-bit ADPCM (type 9 encryption)"},
|
||||
|
||||
{coding_NGC_DSP, "Nintendo DSP 4-bit ADPCM"},
|
||||
{coding_NGC_DSP_subint, "Nintendo DSP 4-bit ADPCM (subinterleave)"},
|
||||
{coding_NGC_DTK, "Nintendo DTK 4-bit ADPCM"},
|
||||
{coding_NGC_AFC, "Nintendo AFC 4-bit ADPCM"},
|
||||
|
||||
@ -523,7 +528,6 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_none, "flat (no layout)"},
|
||||
{layout_interleave, "interleave"},
|
||||
{layout_interleave_shortblock, "interleave with short last block"},
|
||||
{layout_interleave_byte, "sub-frame interleave"},
|
||||
{layout_mxch_blocked, "MxCh blocked"},
|
||||
{layout_ast_blocked, "AST blocked"},
|
||||
{layout_halpst_blocked, "HALPST blocked"},
|
||||
@ -560,6 +564,7 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_blocked_ea_sns, "blocked (EA SNS)"},
|
||||
{layout_blocked_awc, "blocked (AWC)"},
|
||||
{layout_blocked_vgs, "blocked (VGS)"},
|
||||
{layout_blocked_vawx, "blocked (VAWX)"},
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{layout_ogg_vorbis, "Ogg"},
|
||||
#endif
|
||||
|
@ -161,6 +161,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
case layout_blocked_vgs:
|
||||
block_update_vgs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vawx:
|
||||
block_update_vawx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
25
src/layout/blocked_vawx.c
Normal file
25
src/layout/blocked_vawx.c
Normal file
@ -0,0 +1,25 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* pseudo-blocks that must skip last 0x20 every 0x8000 */
|
||||
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
int i;
|
||||
size_t block_size;
|
||||
|
||||
/* no header */
|
||||
block_size = vgmstream->channels * 0x10;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
vgmstream->current_block_size = block_size / vgmstream->channels;
|
||||
|
||||
if ((vgmstream->next_block_offset - 0x800) > 0
|
||||
&& ((vgmstream->next_block_offset - 0x800 + 0x20) % 0x8000) == 0) {
|
||||
vgmstream->next_block_offset += 0x20;
|
||||
}
|
||||
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = block_offset + 0x10*i;
|
||||
}
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* for formats where the interleave is smaller than a frame, so we need to
|
||||
* deinterleave in memory before passing it along to a specialized decoder which
|
||||
* reads from memory
|
||||
*/
|
||||
|
||||
/* just do one frame at a time */
|
||||
|
||||
void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
/* frame sizes are much smaller than this */
|
||||
uint8_t sample_data[0x400];
|
||||
int samples_written=0;
|
||||
|
||||
int frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
int samples_this_block;
|
||||
|
||||
samples_this_block = samples_per_frame;
|
||||
|
||||
while (samples_written<sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
|
||||
if (samples_written+samples_to_do > sample_count)
|
||||
samples_to_do=sample_count-samples_written;
|
||||
|
||||
{
|
||||
int i,j;
|
||||
for (j=0;j<vgmstream->channels;j++) {
|
||||
for (i=0;i<frame_size;i++) {
|
||||
sample_data[i] = read_8bit(vgmstream->ch[j].offset+
|
||||
i/vgmstream->interleave_block_size*
|
||||
vgmstream->interleave_block_size*
|
||||
vgmstream->channels+
|
||||
i%vgmstream->interleave_block_size,
|
||||
vgmstream->ch[j].streamfile);
|
||||
}
|
||||
decode_vgmstream_mem(vgmstream, samples_written,
|
||||
samples_to_do, buffer, sample_data, j);
|
||||
}
|
||||
}
|
||||
|
||||
samples_written += samples_to_do;
|
||||
vgmstream->current_sample += samples_to_do;
|
||||
vgmstream->samples_into_block+=samples_to_do;
|
||||
|
||||
if (vgmstream->samples_into_block==samples_this_block) {
|
||||
int chan;
|
||||
for (chan=0;chan<vgmstream->channels;chan++)
|
||||
vgmstream->ch[chan].offset+=frame_size*vgmstream->channels;
|
||||
vgmstream->samples_into_block=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -5,18 +5,17 @@
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* blocked layouts */
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void ast_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void mxch_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void halpst_block_update(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
@ -66,14 +65,13 @@ void hwas_block_update(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_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_vawx(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_interleave_byte(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
@ -12,8 +12,8 @@ void thp_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
nextFrameSize=read_32bitBE(vgmstream->current_block_offset,streamFile);
|
||||
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset
|
||||
+ vgmstream->thpNextFrameSize;
|
||||
vgmstream->thpNextFrameSize=nextFrameSize;
|
||||
+ vgmstream->full_block_size;
|
||||
vgmstream->full_block_size = nextFrameSize;
|
||||
|
||||
start_offset=vgmstream->current_block_offset
|
||||
+ read_32bitBE(vgmstream->current_block_offset+0x08,streamFile)+0x10;
|
||||
|
@ -203,6 +203,22 @@
|
||||
<File
|
||||
RelativePath=".\meta\hca_keys.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\aax_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\aix_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\bar_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\sqex_scd_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
@ -229,7 +245,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\afc_header.c"
|
||||
RelativePath=".\meta\afc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -413,7 +429,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\gh3_bar.c"
|
||||
RelativePath=".\meta\bar.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -661,6 +677,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\ogl.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\omu.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\otm.c"
|
||||
@ -1002,6 +1022,10 @@
|
||||
RelativePath=".\meta\ps2_xa2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ps2_xa2_rrp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ps2_xa30.c"
|
||||
>
|
||||
@ -1206,6 +1230,10 @@
|
||||
RelativePath=".\meta\vsf.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\vsf_tta.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\vxn.c"
|
||||
>
|
||||
@ -1622,6 +1650,10 @@
|
||||
RelativePath=".\layout\blocked_ea_1snh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vawx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vgs.c"
|
||||
>
|
||||
@ -1666,10 +1698,6 @@
|
||||
RelativePath=".\layout\interleave.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\interleave_byte.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_ivaud.c"
|
||||
>
|
||||
|
@ -118,6 +118,10 @@
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="vgmstream.h" />
|
||||
<ClInclude Include="meta\adx_keys.h" />
|
||||
<ClInclude Include="meta\aax_streamfile.h" />
|
||||
<ClInclude Include="meta\aix_streamfile.h" />
|
||||
<ClInclude Include="meta\bar_streamfile.h" />
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h" />
|
||||
<ClInclude Include="meta\meta.h" />
|
||||
<ClInclude Include="meta\hca_keys.h" />
|
||||
<ClInclude Include="coding\acm_decoder.h" />
|
||||
@ -197,7 +201,7 @@
|
||||
<ClCompile Include="meta\acm.c" />
|
||||
<ClCompile Include="meta\ads.c" />
|
||||
<ClCompile Include="meta\adx.c" />
|
||||
<ClCompile Include="meta\afc_header.c" />
|
||||
<ClCompile Include="meta\afc.c" />
|
||||
<ClCompile Include="meta\agsc.c" />
|
||||
<ClCompile Include="meta\ahx.c" />
|
||||
<ClCompile Include="meta\aifc.c" />
|
||||
@ -235,7 +239,7 @@
|
||||
<ClCompile Include="meta\gca.c" />
|
||||
<ClCompile Include="meta\gcsw.c" />
|
||||
<ClCompile Include="meta\genh.c" />
|
||||
<ClCompile Include="meta\gh3_bar.c" />
|
||||
<ClCompile Include="meta\bar.c" />
|
||||
<ClCompile Include="meta\gsp_gsb.c" />
|
||||
<ClCompile Include="meta\gtd.c" />
|
||||
<ClCompile Include="meta\halpst.c" />
|
||||
@ -293,6 +297,7 @@
|
||||
<ClCompile Include="meta\nwa.c" />
|
||||
<ClCompile Include="meta\ogg_vorbis_file.c" />
|
||||
<ClCompile Include="meta\ogl.c" />
|
||||
<ClCompile Include="meta\omu.c" />
|
||||
<ClCompile Include="meta\otm.c" />
|
||||
<ClCompile Include="meta\p3d.c" />
|
||||
<ClCompile Include="meta\pc_al2.c" />
|
||||
@ -366,6 +371,7 @@
|
||||
<ClCompile Include="meta\ps2_wad.c" />
|
||||
<ClCompile Include="meta\ps2_wb.c" />
|
||||
<ClCompile Include="meta\ps2_xa2.c" />
|
||||
<ClCompile Include="meta\ps2_xa2_rrp.c" />
|
||||
<ClCompile Include="meta\ps2_xa30.c" />
|
||||
<ClCompile Include="meta\ps3_cps.c" />
|
||||
<ClCompile Include="meta\ps3_msf.c" />
|
||||
@ -407,6 +413,7 @@
|
||||
<ClCompile Include="meta\ubi_sb.c" />
|
||||
<ClCompile Include="meta\vs.c" />
|
||||
<ClCompile Include="meta\vsf.c" />
|
||||
<ClCompile Include="meta\vsf_tta.c" />
|
||||
<ClCompile Include="meta\vxn.c" />
|
||||
<ClCompile Include="meta\waa_wac_wad_wam.c" />
|
||||
<ClCompile Include="meta\wii_04sw.c" />
|
||||
@ -480,6 +487,7 @@
|
||||
<ClCompile Include="layout\blocked_awc.c" />
|
||||
<ClCompile Include="layout\blocked_ea_1snh.c" />
|
||||
<ClCompile Include="layout\blocked_vgs.c" />
|
||||
<ClCompile Include="layout\blocked_vawx.c" />
|
||||
<ClCompile Include="layout\caf_blocked.c" />
|
||||
<ClCompile Include="layout\blocked_dec.c" />
|
||||
<ClCompile Include="layout\blocked_ea_schl.c" />
|
||||
@ -490,7 +498,6 @@
|
||||
<ClCompile Include="layout\halpst_blocked.c" />
|
||||
<ClCompile Include="layout\ims_block.c" />
|
||||
<ClCompile Include="layout\interleave.c" />
|
||||
<ClCompile Include="layout\interleave_byte.c" />
|
||||
<ClCompile Include="layout\blocked_ivaud.c" />
|
||||
<ClCompile Include="layout\mus_acm_layout.c" />
|
||||
<ClCompile Include="layout\mxch_blocked.c" />
|
||||
|
@ -62,6 +62,18 @@
|
||||
<ClInclude Include="meta\adx_keys.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\aax_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\aix_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\bar_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\sqex_scd_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\meta.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -133,7 +145,7 @@
|
||||
<ClCompile Include="meta\adx.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\afc_header.c">
|
||||
<ClCompile Include="meta\afc.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\agsc.c">
|
||||
@ -241,7 +253,7 @@
|
||||
<ClCompile Include="meta\genh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\gh3_bar.c">
|
||||
<ClCompile Include="meta\bar.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\gsp_gsb.c">
|
||||
@ -394,6 +406,9 @@
|
||||
<ClCompile Include="meta\ogl.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\omu.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\otm.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -613,6 +628,9 @@
|
||||
<ClCompile Include="meta\ps2_xa2.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_xa2_rrp.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\ps2_xa30.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -736,6 +754,9 @@
|
||||
<ClCompile Include="meta\vsf.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\vsf_tta.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\vxn.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -949,6 +970,9 @@
|
||||
<ClCompile Include="layout\blocked_vgs.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_vawx.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\caf_blocked.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -982,9 +1006,6 @@
|
||||
<ClCompile Include="layout\interleave.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\interleave_byte.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_ivaud.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
109
src/meta/aax.c
109
src/meta/aax.c
@ -1,16 +1,5 @@
|
||||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct _AAXSTREAMFILE
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
size_t file_size;
|
||||
} AAXSTREAMFILE;
|
||||
|
||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size);
|
||||
#include "aax_streamfile.h"
|
||||
|
||||
struct utf_query
|
||||
{
|
||||
@ -107,10 +96,9 @@ struct utf_table_info
|
||||
};
|
||||
|
||||
|
||||
/* Actual AAX init fcn */
|
||||
/* AAX - segmented ADX [Padora's Tower (Wii)] */
|
||||
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamFileAAX = NULL;
|
||||
STREAMFILE * streamFileADX = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
@ -131,7 +119,7 @@ VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
|
||||
int channel_count = 0, segment_count;
|
||||
int sample_rate = 0;
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
|
||||
long aax_data_offset;
|
||||
@ -297,91 +285,6 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* virtual file, a piece of the overall file */
|
||||
|
||||
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
||||
{
|
||||
/* truncate at end of logical file */
|
||||
if (offset+length > streamfile->file_size)
|
||||
{
|
||||
long signed_length = length;
|
||||
signed_length = streamfile->file_size - offset;
|
||||
if (signed_length < 0) signed_length = 0;
|
||||
length = signed_length;
|
||||
}
|
||||
return read_streamfile(dest,
|
||||
streamfile->start_physical_offset+offset,
|
||||
length,streamfile->real_file);
|
||||
}
|
||||
|
||||
static void close_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aax(AAXSTREAMFILE *streamfile)
|
||||
{
|
||||
long offset = streamfile->real_file->get_offset(streamfile->real_file);
|
||||
offset -= streamfile->start_physical_offset;
|
||||
if (offset < 0) offset = 0;
|
||||
if (offset > streamfile->file_size) offset = streamfile->file_size;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length)
|
||||
{
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
||||
{
|
||||
AAXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size)
|
||||
{
|
||||
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aax;
|
||||
streamfile->sf.get_size = (void*)get_size_aax;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aax;
|
||||
streamfile->sf.get_name = (void*)get_name_aax;
|
||||
streamfile->sf.get_realname = (void*)get_name_aax;
|
||||
streamfile->sf.open = (void*)open_aax_impl;
|
||||
streamfile->sf.close = (void*)close_aax;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->file_size = file_size;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
/* @UTF table reading, abridged */
|
||||
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
|
||||
{
|
||||
@ -744,8 +647,7 @@ static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long off
|
||||
|
||||
/* CRI's UTF wrapper around DSP */
|
||||
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int table_error = 0;
|
||||
|
||||
@ -843,4 +745,3 @@ fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
87
src/meta/aax_streamfile.h
Normal file
87
src/meta/aax_streamfile.h
Normal file
@ -0,0 +1,87 @@
|
||||
#ifndef _AAX_STREAMFILE_H_
|
||||
#define _AAX_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile representing a subfile inside another */
|
||||
|
||||
typedef struct _AAXSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
size_t file_size;
|
||||
} AAXSTREAMFILE;
|
||||
|
||||
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
|
||||
/* truncate at end of logical file */
|
||||
if (offset+length > streamfile->file_size) {
|
||||
long signed_length = length;
|
||||
signed_length = streamfile->file_size - offset;
|
||||
if (signed_length < 0) signed_length = 0;
|
||||
length = signed_length;
|
||||
}
|
||||
return read_streamfile(dest, streamfile->start_physical_offset+offset, length,streamfile->real_file);
|
||||
}
|
||||
|
||||
static void close_aax(AAXSTREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aax(AAXSTREAMFILE *streamfile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aax(AAXSTREAMFILE *streamfile) {
|
||||
long offset = streamfile->real_file->get_offset(streamfile->real_file);
|
||||
offset -= streamfile->start_physical_offset;
|
||||
if (offset < 0) offset = 0;
|
||||
if (offset > streamfile->file_size) offset = streamfile->file_size;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length) {
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||
AAXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size) {
|
||||
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aax;
|
||||
streamfile->sf.get_size = (void*)get_size_aax;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aax;
|
||||
streamfile->sf.get_name = (void*)get_name_aax;
|
||||
streamfile->sf.get_realname = (void*)get_name_aax;
|
||||
streamfile->sf.open = (void*)open_aax_impl;
|
||||
streamfile->sf.close = (void*)close_aax;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->file_size = file_size;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
#endif /* _AAX_STREAMFILE_H_ */
|
@ -47,17 +47,17 @@ static const adxkey_info adxkey8_list[] = {
|
||||
/* unknown source */
|
||||
{0x586d,0x5d65,0x63eb, NULL,0}, // from guessadx (unique?)
|
||||
|
||||
/* Navel (Shuffle! On the Stage) */
|
||||
{0x4969,0x5deb,0x467f, NULL,0}, // 2nd key from guessadx
|
||||
/* Navel (Shuffle! On the Stage (PS2)) */
|
||||
{0x4969,0x5deb,0x467f, "SHUF",0},
|
||||
|
||||
/* Success (Aoishiro) */
|
||||
{0x4d65,0x5eb7,0x5dfd, NULL,0}, // 1st key from guessadx
|
||||
/* Success (Aoishiro (PS2)) */
|
||||
{0x4d65,0x5eb7,0x5dfd, "wakasugi",0},
|
||||
|
||||
/* Sonic Team 2 (Sonic and the Black Knight) */
|
||||
{0x55b7,0x6191,0x5a77, "morio",0},
|
||||
|
||||
/* Enterbrain (Amagami) */
|
||||
{0x5a17,0x509f,0x5bfd, "mituba",0},
|
||||
{0x5a17,0x509f,0x5bfd, "mituba",0}, /* also AHX key */
|
||||
|
||||
/* Yamasa (Yamasa Digi Portable: Matsuri no Tatsujin) */
|
||||
{0x4c01,0x549d,0x676f, NULL,0}, // confirmed unique with guessadx
|
||||
@ -171,7 +171,7 @@ static const adxkey_info adxkey8_list[] = {
|
||||
/* Suzumiya Haruhi-chan no Mahjong (2011-07-07)(-)(Kadokawa Shoten)[PSP] */
|
||||
{0x5c33,0x4133,0x4ce7, NULL,0}, // ?
|
||||
|
||||
/* Storm Lover Natsu Koi!! (2011-08-04)(Vridge)(D3 Publisher) */
|
||||
/* Storm Lover Natsu Koi!! (2011-08-04)(Vridge)(D3 Publisher)[PSP] */
|
||||
{0x4133,0x5a01,0x5723, NULL,0}, // ?
|
||||
|
||||
};
|
||||
|
204
src/meta/aix.c
204
src/meta/aix.c
@ -1,20 +1,7 @@
|
||||
#include "../vgmstream.h"
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
typedef struct _AIXSTREAMFILE
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
off_t current_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t current_block_size;
|
||||
int stream_id;
|
||||
} AIXSTREAMFILE;
|
||||
|
||||
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id);
|
||||
#include "aix_streamfile.h"
|
||||
|
||||
/* AIX - interleaved AAX, N segments per channels [SoulCalibur IV (PS3)] */
|
||||
VGMSTREAM * init_vgmstream_aix(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
@ -228,190 +215,3 @@ fail:
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
||||
while (length > 0)
|
||||
{
|
||||
int read_something = 0;
|
||||
|
||||
/* read the beginning of the requested block, if we can */
|
||||
if (offset >= streamfile->current_logical_offset)
|
||||
{
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
|
||||
length_available =
|
||||
(streamfile->current_logical_offset+
|
||||
streamfile->current_block_size) -
|
||||
offset;
|
||||
|
||||
if (length < length_available)
|
||||
{
|
||||
to_read = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
streamfile->current_physical_offset+0x10+
|
||||
(offset-streamfile->current_logical_offset),
|
||||
to_read,streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
{
|
||||
/* an error which we will not attempt to handle here */
|
||||
return sz;
|
||||
}
|
||||
|
||||
read_something = 1;
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_something)
|
||||
{
|
||||
/* couldn't read anything, must seek */
|
||||
int found_block = 0;
|
||||
|
||||
/* as we have no memory we must start seeking from the beginning */
|
||||
if (offset < streamfile->current_logical_offset)
|
||||
{
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->current_physical_offset =
|
||||
streamfile->start_physical_offset;
|
||||
}
|
||||
|
||||
/* seek ye forwards */
|
||||
while (!found_block) {
|
||||
/*printf("seek looks at %x\n",streamfile->current_physical_offset);*/
|
||||
switch (read_32bitBE(streamfile->current_physical_offset,
|
||||
streamfile->real_file))
|
||||
{
|
||||
case 0x41495850: /* AIXP */
|
||||
if (read_8bit(
|
||||
streamfile->current_physical_offset+8,
|
||||
streamfile->real_file) ==
|
||||
streamfile->stream_id)
|
||||
{
|
||||
streamfile->current_block_size =
|
||||
(uint16_t)read_16bitBE(
|
||||
streamfile->current_physical_offset+0x0a,
|
||||
streamfile->real_file);
|
||||
|
||||
if (offset >= streamfile->current_logical_offset+
|
||||
streamfile->current_block_size)
|
||||
{
|
||||
streamfile->current_logical_offset +=
|
||||
streamfile->current_block_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_block = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_block)
|
||||
{
|
||||
streamfile->current_physical_offset +=
|
||||
read_32bitBE(
|
||||
streamfile->current_physical_offset+0x04,
|
||||
streamfile->real_file
|
||||
) + 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x41495846: /* AIXF */
|
||||
/* shouldn't ever see this */
|
||||
case 0x41495845: /* AIXE */
|
||||
/* shouldn't have reached the end o' the line... */
|
||||
default:
|
||||
return sz;
|
||||
break;
|
||||
} /* end block/chunk type select */
|
||||
} /* end while !found_block */
|
||||
} /* end if !read_something */
|
||||
} /* end while length > 0 */
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void close_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aix(AIXSTREAMFILE *streamfile)
|
||||
{
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length)
|
||||
{
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
||||
{
|
||||
AIXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file,off_t start_offset,int stream_id)
|
||||
{
|
||||
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aix;
|
||||
streamfile->sf.get_size = (void*)get_size_aix;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aix;
|
||||
streamfile->sf.get_name = (void*)get_name_aix;
|
||||
streamfile->sf.get_realname = (void*)get_name_aix;
|
||||
streamfile->sf.open = (void*)open_aix_impl;
|
||||
streamfile->sf.close = (void*)close_aix;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->current_physical_offset =
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->stream_id = stream_id;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
|
169
src/meta/aix_streamfile.h
Normal file
169
src/meta/aix_streamfile.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef _AIX_STREAMFILE_H_
|
||||
#define _AIX_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile representing a subfile inside another, in blocked AIX format */
|
||||
|
||||
typedef struct _AIXSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
off_t start_physical_offset;
|
||||
off_t current_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t current_block_size;
|
||||
int stream_id;
|
||||
} AIXSTREAMFILE;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id);
|
||||
|
||||
|
||||
static size_t read_aix(AIXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
|
||||
size_t sz = 0;
|
||||
|
||||
/*printf("trying to read %x bytes from %x (str%d)\n",length,offset,streamfile->stream_id);*/
|
||||
while (length > 0) {
|
||||
int read_something = 0;
|
||||
|
||||
/* read the beginning of the requested block, if we can */
|
||||
if (offset >= streamfile->current_logical_offset) {
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
|
||||
length_available = (streamfile->current_logical_offset + streamfile->current_block_size) - offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
streamfile->current_physical_offset+0x10 + (offset-streamfile->current_logical_offset),
|
||||
to_read,streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
if (bytes_read != to_read) {
|
||||
return sz; /* an error which we will not attempt to handle here */
|
||||
}
|
||||
|
||||
read_something = 1;
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_something) {
|
||||
/* couldn't read anything, must seek */
|
||||
int found_block = 0;
|
||||
|
||||
/* as we have no memory we must start seeking from the beginning */
|
||||
if (offset < streamfile->current_logical_offset) {
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->current_physical_offset = streamfile->start_physical_offset;
|
||||
}
|
||||
|
||||
/* seek ye forwards */
|
||||
while (!found_block) {
|
||||
/*printf("seek looks at %x\n",streamfile->current_physical_offset);*/
|
||||
switch (read_32bitBE(streamfile->current_physical_offset, streamfile->real_file)) {
|
||||
case 0x41495850: /* AIXP */
|
||||
if (read_8bit(streamfile->current_physical_offset+8, streamfile->real_file) == streamfile->stream_id) {
|
||||
streamfile->current_block_size = (uint16_t)read_16bitBE(streamfile->current_physical_offset+0x0a, streamfile->real_file);
|
||||
|
||||
if (offset >= streamfile->current_logical_offset+ streamfile->current_block_size) {
|
||||
streamfile->current_logical_offset += streamfile->current_block_size;
|
||||
}
|
||||
else {
|
||||
found_block = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_block) {
|
||||
streamfile->current_physical_offset += read_32bitBE(streamfile->current_physical_offset+0x04, streamfile->real_file) + 8;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x41495846: /* AIXF */
|
||||
/* shouldn't ever see this */
|
||||
case 0x41495845: /* AIXE */
|
||||
/* shouldn't have reached the end o' the line... */
|
||||
default:
|
||||
return sz;
|
||||
break;
|
||||
} /* end block/chunk type select */
|
||||
} /* end while !found_block */
|
||||
} /* end if !read_something */
|
||||
} /* end while length > 0 */
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void close_aix(AIXSTREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_aix(AIXSTREAMFILE *streamfile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t get_offset_aix(AIXSTREAMFILE *streamfile) {
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_aix(AIXSTREAMFILE *streamfile,char *buffer,size_t length) {
|
||||
strncpy(buffer,"ARBITRARY.ADX",length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static STREAMFILE *open_aix_impl(AIXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||
AIXSTREAMFILE *newfile;
|
||||
if (strcmp(filename,"ARBITRARY.ADX"))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
memcpy(newfile,streamfile,sizeof(AIXSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
/*static*/ STREAMFILE *open_aix_with_STREAMFILE(STREAMFILE *file, off_t start_offset, int stream_id) {
|
||||
AIXSTREAMFILE *streamfile = malloc(sizeof(AIXSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
/* success, set our pointers */
|
||||
|
||||
streamfile->sf.read = (void*)read_aix;
|
||||
streamfile->sf.get_size = (void*)get_size_aix;
|
||||
streamfile->sf.get_offset = (void*)get_offset_aix;
|
||||
streamfile->sf.get_name = (void*)get_name_aix;
|
||||
streamfile->sf.get_realname = (void*)get_name_aix;
|
||||
streamfile->sf.open = (void*)open_aix_impl;
|
||||
streamfile->sf.close = (void*)close_aix;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = NULL;
|
||||
streamfile->sf.get_error_count = NULL;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
streamfile->current_physical_offset = start_offset;
|
||||
streamfile->start_physical_offset = start_offset;
|
||||
streamfile->current_logical_offset = 0;
|
||||
streamfile->current_block_size = 0;
|
||||
streamfile->stream_id = stream_id;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
#endif /* _AIX_STREAMFILE_H_ */
|
77
src/meta/bar.c
Normal file
77
src/meta/bar.c
Normal file
@ -0,0 +1,77 @@
|
||||
#include "meta.h"
|
||||
#include "bar_streamfile.h"
|
||||
|
||||
/* Guitar Hero III Mobile .bar */
|
||||
VGMSTREAM * init_vgmstream_bar(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE* streamFileBAR = NULL; // don't close, this is just the source streamFile wrapped
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
off_t ch2_start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
long file_size;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bar",filename_extension(filename))) goto fail;
|
||||
|
||||
/* decryption wrapper for header reading */
|
||||
streamFileBAR = wrap_bar_STREAMFILE(streamFile);
|
||||
if (!streamFileBAR) goto fail;
|
||||
|
||||
file_size = get_streamfile_size(streamFileBAR);
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFileBAR) != 0x11000100 ||
|
||||
read_32bitBE(0x04,streamFileBAR) != 0x01000200) goto fail;
|
||||
if (read_32bitLE(0x50,streamFileBAR) != file_size) goto fail;
|
||||
|
||||
start_offset = read_32bitLE(0x18,streamFileBAR);
|
||||
if (0x54 != start_offset) goto fail;
|
||||
ch2_start_offset = read_32bitLE(0x48,streamFileBAR);
|
||||
if (ch2_start_offset >= file_size) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 11025;
|
||||
vgmstream->coding_type = coding_IMA;
|
||||
vgmstream->num_samples = (file_size-ch2_start_offset)*2;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_GH3_BAR;
|
||||
|
||||
{
|
||||
STREAMFILE *file1, *file2;
|
||||
file1 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file1) goto fail;
|
||||
file2 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file2)
|
||||
{
|
||||
close_streamfile(file1);
|
||||
goto fail;
|
||||
}
|
||||
vgmstream->ch[0].streamfile = file1;
|
||||
vgmstream->ch[1].streamfile = file2;
|
||||
vgmstream->ch[0].channel_start_offset=
|
||||
vgmstream->ch[0].offset=start_offset;
|
||||
vgmstream->ch[1].channel_start_offset=
|
||||
vgmstream->ch[1].offset=ch2_start_offset;
|
||||
}
|
||||
|
||||
// discard our decrypt wrapper, without closing the original streamfile
|
||||
free(streamFileBAR);
|
||||
|
||||
return vgmstream;
|
||||
fail:
|
||||
if (streamFileBAR)
|
||||
free(streamFileBAR);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
100
src/meta/bar_streamfile.h
Normal file
100
src/meta/bar_streamfile.h
Normal file
@ -0,0 +1,100 @@
|
||||
#ifndef _BAR_STREAMFILE_H_
|
||||
#define _BAR_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* a streamfile wrapping another for decryption */
|
||||
|
||||
enum {BAR_KEY_LENGTH = 16};
|
||||
|
||||
// don't know if this is unique, but seems accurate
|
||||
static const uint8_t bar_key[BAR_KEY_LENGTH] = {
|
||||
0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
||||
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80
|
||||
};
|
||||
|
||||
typedef struct _BARSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
} BARSTREAMFILE;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
||||
|
||||
|
||||
static size_t read_bar(BARSTREAMFILE *streamFile, uint8_t *dest, off_t offset, size_t length) {
|
||||
off_t i;
|
||||
size_t read_length = streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
||||
|
||||
for (i = 0; i < read_length; i++) {
|
||||
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
||||
}
|
||||
|
||||
return read_length;
|
||||
}
|
||||
|
||||
static size_t get_size_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_size(streamFile->real_file);
|
||||
}
|
||||
|
||||
static size_t get_offset_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_offset(streamFile->real_file);
|
||||
}
|
||||
|
||||
static void get_name_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||
return streamFile->real_file->get_name(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
static void get_realname_bar(BARSTREAMFILE *streamFile, char *name, size_t length) {
|
||||
return streamFile->real_file->get_realname(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
STREAMFILE *open_bar(BARSTREAMFILE *streamFile, const char * const filename, size_t buffersize) {
|
||||
STREAMFILE *newfile = streamFile->real_file->open(streamFile->real_file,filename,buffersize);
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
return wrap_bar_STREAMFILE(newfile);
|
||||
}
|
||||
|
||||
static void close_bar(BARSTREAMFILE *streamFile) {
|
||||
streamFile->real_file->close(streamFile->real_file);
|
||||
free(streamFile);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
size_t get_bytes_read_bar(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_bytes_read(streamFile->real_file);
|
||||
}
|
||||
|
||||
int (*get_error_count)(BARSTREAMFILE *streamFile) {
|
||||
return streamFile->real_file->get_error_count(streamFile->real_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*static*/ STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file) {
|
||||
BARSTREAMFILE *streamfile = malloc(sizeof(BARSTREAMFILE));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
memset(streamfile, 0, sizeof(BARSTREAMFILE));
|
||||
|
||||
streamfile->sf.read = (void*)read_bar;
|
||||
streamfile->sf.get_size = (void*)get_size_bar;
|
||||
streamfile->sf.get_offset = (void*)get_offset_bar;
|
||||
streamfile->sf.get_name = (void*)get_name_bar;
|
||||
streamfile->sf.get_realname = (void*)get_realname_bar;
|
||||
streamfile->sf.open = (void*)open_bar;
|
||||
streamfile->sf.close = (void*)close_bar;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = get_bytes_read_bar;
|
||||
streamfile->sf.get_error_count = get_error_count_bar;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
||||
|
||||
#endif /* _BAR_STREAMFILE_H_ */
|
@ -17,8 +17,8 @@ VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
|
||||
|
||||
/* SNR headers normally need an external SNS file, but some have data */
|
||||
if (get_streamfile_size(streamFile) > 0x10) {
|
||||
/* for Burnout Paradise has this, not sure if extension */
|
||||
off_t start_offset = (read_32bitBE(0x0c, streamFile) == 0) ? 0x0c : 0x08;
|
||||
/* SNR with data (flag 0x40 not set), seen in Burnout Paradise, NFL2013 iOS */
|
||||
off_t start_offset = (read_32bitBE(0x08, streamFile) == 0) ? 0x0c : 0x08;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x00, start_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream) goto fail;
|
||||
|
@ -353,8 +353,8 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
||||
}
|
||||
else if (fsbh.mode & FSOUND_GCADPCM) {
|
||||
/* FSB3: ?; FSB4: de Blob (Wii), Night at the Museum, M. Night Shyamalan Avatar: The Last Airbender */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
dsp_read_coefs_be(vgmstream, streamFile, custom_data_offset, 0x2e);
|
||||
}
|
||||
@ -380,6 +380,8 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
||||
|
||||
/* full channel interleave, used in short streams (ex. de Blob Wii SFXs) */
|
||||
if (fsbh.numchannels > 1 && (fsbh.flags & FMOD_FSB_SOURCE_NOTINTERLEAVED)) {
|
||||
if (vgmstream->coding_type == coding_NGC_DSP_subint)
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = fsbh.lengthcompressedbytes / fsbh.numchannels;
|
||||
}
|
||||
|
@ -193,27 +193,22 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
case 0x01: /* FMOD_SOUND_FORMAT_PCM8 [Anima - Gate of Memories (PC)] */
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
vgmstream->layout_type = ChannelCount == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
vgmstream->coding_type = coding_PCM8_U;
|
||||
break;
|
||||
|
||||
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 */
|
||||
if (ChannelCount == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = ChannelCount == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case 0x03: /* FMOD_SOUND_FORMAT_PCM24 */
|
||||
goto fail;
|
||||
goto fail; /* not used */
|
||||
|
||||
case 0x04: /* FMOD_SOUND_FORMAT_PCM32 */
|
||||
goto fail;
|
||||
goto fail; /* not used */
|
||||
|
||||
case 0x05: /* FMOD_SOUND_FORMAT_PCMFLOAT [Anima - Gate of Memories (PC)] */
|
||||
vgmstream->coding_type = coding_PCMFLOAT;
|
||||
@ -222,31 +217,25 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM [Sonic Boom - Fire and Ice (3DS)] */
|
||||
if (ChannelCount == 1) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else {
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
}
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
dsp_read_coefs_be(vgmstream,streamFile,DSPInfoStart,0x2E);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
break;
|
||||
|
||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */
|
||||
vgmstream->coding_type = (vgmstream->channels > 2) ? coding_FSB_IMA : coding_XBOX;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_XBOX;
|
||||
if (vgmstream->channels > 2) /* multichannel FSB IMA (interleaved header) */
|
||||
vgmstream->coding_type = coding_FSB_IMA;
|
||||
break;
|
||||
|
||||
case 0x08: /* FMOD_SOUND_FORMAT_VAG */
|
||||
goto fail;
|
||||
goto fail; /* not used */
|
||||
|
||||
case 0x09: /* FMOD_SOUND_FORMAT_HEVAG */
|
||||
vgmstream->coding_type = coding_HEVAG;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->coding_type = coding_HEVAG;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -270,9 +259,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x0B: {/* FMOD_SOUND_FORMAT_MPEG */
|
||||
mpeg_custom_config cfg;
|
||||
mpeg_custom_config cfg = {0};
|
||||
|
||||
memset(&cfg, 0, sizeof(mpeg_custom_config));
|
||||
cfg.fsb_padding = (vgmstream->channels > 2 ? 16 : 4); /* observed default */
|
||||
|
||||
vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, StartOffset, &vgmstream->coding_type, vgmstream->channels, MPEG_FSB, &cfg);
|
||||
@ -295,9 +283,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x0F: {/* FMOD_SOUND_FORMAT_VORBIS */
|
||||
vorbis_custom_config cfg;
|
||||
vorbis_custom_config cfg = {0};
|
||||
|
||||
memset(&cfg, 0, sizeof(vorbis_custom_config));
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.sample_rate = vgmstream->sample_rate;
|
||||
cfg.setup_id = VorbisSetupId;
|
||||
|
@ -88,11 +88,10 @@ static VGMSTREAM * init_vgmstream_kt_wiibgm_offset(STREAMFILE *streamFile, off_t
|
||||
vgmstream->loop_start_sample = read_32bitBE(offset+0x14, streamFile);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->meta_type = meta_KT_WIIBGM;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x1;
|
||||
vgmstream->meta_type = meta_KT_WIIBGM;
|
||||
|
||||
dsp_read_coefs_be(vgmstream,streamFile, offset+0x5C, 0x60);
|
||||
start_offset = offset+0x800;
|
||||
@ -101,7 +100,7 @@ static VGMSTREAM * init_vgmstream_kt_wiibgm_offset(STREAMFILE *streamFile, off_t
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -208,8 +208,9 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
} else if (genh.coef_interleave_type == 1) {
|
||||
if (!genh.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
coding = coding_NGC_DSP_subint;
|
||||
vgmstream->interleave_block_size = genh.interleave;
|
||||
vgmstream->layout_type = layout_none;
|
||||
} else if (genh.coef_interleave_type == 2) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
}// else {
|
||||
|
@ -1,182 +0,0 @@
|
||||
#include "meta.h"
|
||||
|
||||
// Guitar Hero III Mobile .bar
|
||||
|
||||
enum {BAR_KEY_LENGTH = 16};
|
||||
|
||||
// don't know if this is unique, but seems accurate
|
||||
static const uint8_t bar_key[BAR_KEY_LENGTH] =
|
||||
{0xbd,0x14,0x0e,0x0a,0x91,0xeb,0xaa,0xf6,
|
||||
0x11,0x44,0x17,0xc2,0x1c,0xe4,0x66,0x80};
|
||||
|
||||
typedef struct _BARSTREAM
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
} BARSTREAM;
|
||||
|
||||
STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file);
|
||||
|
||||
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
// don't close, this is just the source streamFile wrapped
|
||||
STREAMFILE* streamFileBAR = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
off_t ch2_start_offset;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
long file_size;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("bar",filename_extension(filename))) goto fail;
|
||||
|
||||
/* decryption wrapper for header reading */
|
||||
streamFileBAR = wrap_bar_STREAMFILE(streamFile);
|
||||
if (!streamFileBAR) goto fail;
|
||||
|
||||
file_size = get_streamfile_size(streamFileBAR);
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFileBAR) != 0x11000100 ||
|
||||
read_32bitBE(0x04,streamFileBAR) != 0x01000200) goto fail;
|
||||
if (read_32bitLE(0x50,streamFileBAR) != file_size) goto fail;
|
||||
|
||||
start_offset = read_32bitLE(0x18,streamFileBAR);
|
||||
if (0x54 != start_offset) goto fail;
|
||||
ch2_start_offset = read_32bitLE(0x48,streamFileBAR);
|
||||
if (ch2_start_offset >= file_size) goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
channel_count = 2;
|
||||
loop_flag = 0;
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 11025;
|
||||
vgmstream->coding_type = coding_IMA;
|
||||
vgmstream->num_samples = (file_size-ch2_start_offset)*2;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->meta_type = meta_GH3_BAR;
|
||||
|
||||
{
|
||||
STREAMFILE *file1, *file2;
|
||||
file1 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file1) goto fail;
|
||||
file2 = streamFileBAR->open(streamFileBAR,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file2)
|
||||
{
|
||||
close_streamfile(file1);
|
||||
goto fail;
|
||||
}
|
||||
vgmstream->ch[0].streamfile = file1;
|
||||
vgmstream->ch[1].streamfile = file2;
|
||||
vgmstream->ch[0].channel_start_offset=
|
||||
vgmstream->ch[0].offset=start_offset;
|
||||
vgmstream->ch[1].channel_start_offset=
|
||||
vgmstream->ch[1].offset=ch2_start_offset;
|
||||
}
|
||||
|
||||
// discard our decrypt wrapper, without closing the original streamfile
|
||||
free(streamFileBAR);
|
||||
|
||||
return vgmstream;
|
||||
fail:
|
||||
if (streamFileBAR)
|
||||
free(streamFileBAR);
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t read_bar(BARSTREAM *streamFile, uint8_t *dest, off_t offset, size_t length)
|
||||
{
|
||||
off_t i;
|
||||
size_t read_length =
|
||||
streamFile->real_file->read(streamFile->real_file, dest, offset, length);
|
||||
|
||||
for (i = 0; i < read_length; i++)
|
||||
{
|
||||
dest[i] = dest[i] ^ bar_key[(i+offset)%BAR_KEY_LENGTH];
|
||||
}
|
||||
|
||||
return read_length;
|
||||
}
|
||||
|
||||
static size_t get_size_bar(BARSTREAM *streamFile)
|
||||
{
|
||||
return streamFile->real_file->get_size(streamFile->real_file);
|
||||
}
|
||||
|
||||
static size_t get_offset_bar(BARSTREAM *streamFile)
|
||||
{
|
||||
return streamFile->real_file->get_offset(streamFile->real_file);
|
||||
}
|
||||
|
||||
static void get_name_bar(BARSTREAM *streamFile, char *name, size_t length)
|
||||
{
|
||||
return streamFile->real_file->get_name(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
static void get_realname_bar(BARSTREAM *streamFile, char *name, size_t length)
|
||||
{
|
||||
return streamFile->real_file->get_realname(streamFile->real_file, name, length);
|
||||
}
|
||||
|
||||
STREAMFILE *open_bar(BARSTREAM *streamFile, const char * const filename, size_t buffersize)
|
||||
{
|
||||
STREAMFILE *newfile = streamFile->real_file->open(
|
||||
streamFile->real_file,filename,buffersize);
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
return wrap_bar_STREAMFILE(newfile);
|
||||
}
|
||||
|
||||
static void close_bar(BARSTREAM *streamFile)
|
||||
{
|
||||
streamFile->real_file->close(streamFile->real_file);
|
||||
free(streamFile);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
size_t get_bytes_read_bar(BARSTREAM *streamFile)
|
||||
{
|
||||
return streamFile->real_file->get_bytes_read(streamFile->real_file);
|
||||
}
|
||||
|
||||
int (*get_error_count)(BARSTREAM *streamFile)
|
||||
{
|
||||
return streamFile->real_file->get_error_count(streamFile->real_file);
|
||||
}
|
||||
#endif
|
||||
|
||||
STREAMFILE *wrap_bar_STREAMFILE(STREAMFILE *file)
|
||||
{
|
||||
BARSTREAM *streamfile = malloc(sizeof(BARSTREAM));
|
||||
|
||||
if (!streamfile)
|
||||
return NULL;
|
||||
|
||||
memset(streamfile, 0, sizeof(BARSTREAM));
|
||||
|
||||
streamfile->sf.read = (void*)read_bar;
|
||||
streamfile->sf.get_size = (void*)get_size_bar;
|
||||
streamfile->sf.get_offset = (void*)get_offset_bar;
|
||||
streamfile->sf.get_name = (void*)get_name_bar;
|
||||
streamfile->sf.get_realname = (void*)get_realname_bar;
|
||||
streamfile->sf.open = (void*)open_bar;
|
||||
streamfile->sf.close = (void*)close_bar;
|
||||
#ifdef PROFILE_STREAMFILE
|
||||
streamfile->sf.get_bytes_read = get_bytes_read_bar;
|
||||
streamfile->sf.get_error_count = get_error_count_bar;
|
||||
#endif
|
||||
|
||||
streamfile->real_file = file;
|
||||
|
||||
return &streamfile->sf;
|
||||
}
|
@ -80,8 +80,6 @@ VGMSTREAM * init_vgmstream_xbox_xwav(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_vpk(STREAMFILE *streamFile);
|
||||
@ -173,7 +171,6 @@ VGMSTREAM * init_vgmstream_aus(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_rws(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_fsb(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_fsb4_wav(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE * streamFile);
|
||||
@ -243,11 +240,9 @@ VGMSTREAM * init_vgmstream_ngc_swd(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_capdsp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xbox_wvs(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_wvs(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_str(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_dc_str_v2(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xbox_matx(STREAMFILE *streamFile);
|
||||
@ -276,12 +271,8 @@ VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_xa2(STREAMFILE * streamFile);
|
||||
|
||||
//VGMSTREAM * init_vgmstream_idsp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_idsp2(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_idsp3(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_idsp4(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_ymf(STREAMFILE * streamFile);
|
||||
@ -321,7 +312,6 @@ VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_naomi_spsd(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_bgw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_spw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_ass(STREAMFILE * streamFile);
|
||||
@ -359,7 +349,6 @@ VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_wii_smp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile);
|
||||
@ -387,6 +376,7 @@ VGMSTREAM * init_vgmstream_ps2_vsf(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_nds_rrds(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_tk5(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_vsf_tta(STREAMFILE *streamFile);
|
||||
|
||||
@ -447,7 +437,6 @@ VGMSTREAM * init_vgmstream_wii_bns(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_wii_was(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pona_3do(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pona_psx(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xbox_hlwav(STREAMFILE* streamFile);
|
||||
@ -492,8 +481,6 @@ VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_p3d(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_adsc(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_mpds(STREAMFILE* streamFile);
|
||||
@ -503,9 +490,7 @@ VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_psx_mgav(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str1(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str2(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_sth_str3(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps2_b1s(STREAMFILE* streamFile);
|
||||
@ -526,7 +511,7 @@ VGMSTREAM * init_vgmstream_ps2_vms(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_xau(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_gh3_bar(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_bar(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ffw(STREAMFILE* streamFile);
|
||||
|
||||
@ -583,7 +568,6 @@ VGMSTREAM * init_vgmstream_pc_adp_bos(STREAMFILE* streamFile);
|
||||
VGMSTREAM * init_vgmstream_pc_adp_otns(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_eb_sfx(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_eb_sf0(STREAMFILE* streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ps3_klbs(STREAMFILE* streamFile);
|
||||
@ -669,6 +653,7 @@ VGMSTREAM * init_vgmstream_wii_04sw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_txth(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile);
|
||||
@ -677,8 +662,6 @@ VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_stm(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE * streamFile);
|
||||
@ -695,8 +678,8 @@ VGMSTREAM * init_vgmstream_ezw(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_vxn(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE * streamFile);
|
||||
|
@ -2070,8 +2070,8 @@ VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
|
||||
ch0_header.loop_end_offset)+1;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x4;
|
||||
vgmstream->meta_type = meta_WII_NDP;
|
||||
|
||||
@ -2089,22 +2089,12 @@ VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) {
|
||||
vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
|
||||
|
||||
/* open the file for reading */
|
||||
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[0].streamfile)
|
||||
goto fail;
|
||||
vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start;
|
||||
|
||||
vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!vgmstream->ch[1].streamfile)
|
||||
goto fail;
|
||||
vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,ch1_start))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
45
src/meta/omu.c
Normal file
45
src/meta/omu.c
Normal file
@ -0,0 +1,45 @@
|
||||
#include "meta.h"
|
||||
|
||||
/* IMU - found in Alter Echo (PS2) */
|
||||
VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* check extension */
|
||||
if ( !check_extensions(streamFile,"omu") )
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4F4D5520 && /* "OMU " */
|
||||
read_32bitBE(0x08,streamFile) != 0x46524D54) /* "FRMT" */
|
||||
goto fail;
|
||||
|
||||
loop_flag = 1;
|
||||
channel_count = (int)read_8bit(0x14,streamFile);
|
||||
start_offset = 0x40;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->num_samples = (int32_t)(read_32bitLE(0x3C,streamFile)/(vgmstream->channels*2));
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
vgmstream->meta_type = meta_PS2_OMU;
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -27,6 +27,10 @@ VGMSTREAM * init_vgmstream_ps2_int(STREAMFILE *streamFile) {
|
||||
else
|
||||
channel_count = 4;
|
||||
|
||||
/* ignore A2M .int */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x41324D00) /* "A2M\0" */
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
@ -59,57 +63,3 @@ fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// OMU is a PS2 .INT file with header ...
|
||||
// found in Alter Echo
|
||||
VGMSTREAM * init_vgmstream_ps2_omu(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int i,channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("omu",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if((read_32bitBE(0,streamFile)!=0x4F4D5520) && (read_32bitBE(0x08,streamFile)!=0x46524D54))
|
||||
goto fail;
|
||||
|
||||
channel_count = (int)read_8bit(0x14,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,1);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels=channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->num_samples = (int32_t)(read_32bitLE(0x3C,streamFile)/(vgmstream->channels*2));
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_OMU;
|
||||
|
||||
vgmstream->loop_start_sample=0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
{
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);
|
||||
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=0x40+(i*vgmstream->interleave_block_size);
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* RSTM (from Midnight Club 3, Bully - Canis Canim Edit) */
|
||||
/* RSTM - from Rockstar games [Midnight Club 3, Bully - Canis Canim Edit (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("rstm",filename_extension(filename))) goto fail;
|
||||
/* check extension (.rsm: in filelist, .rstm: renamed to header id) */
|
||||
if ( !check_extensions(streamFile,"rsm,rstm") )
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x5253544D) /* "RSTM" */
|
||||
@ -19,46 +17,28 @@ VGMSTREAM * init_vgmstream_ps2_rstm(STREAMFILE *streamFile) {
|
||||
|
||||
loop_flag = (read_32bitLE(0x24,streamFile)!=0xFFFFFFFF);
|
||||
channel_count = read_32bitLE(0x0C,streamFile);
|
||||
start_offset = 0x800;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x20,streamFile)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x24,streamFile)*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = read_32bitLE(0x20,streamFile)*28/16/channel_count;
|
||||
}
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_32bitLE(0x20,streamFile),channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_32bitLE(0x24,streamFile),channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
vgmstream->meta_type = meta_PS2_RSTM;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
||||
int channel_count = 0;
|
||||
int is_swag = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile,"vag,swag,str") )
|
||||
/* check extension (.swag: Frantix PSP, .str: Ben10 Galactic Racing, .vig: MX vs. ATV Untamed PS2) */
|
||||
if ( !check_extensions(streamFile,"vag,swag,str,vig") )
|
||||
goto fail;
|
||||
|
||||
/* check VAG Header */
|
||||
@ -63,7 +63,11 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
||||
break;
|
||||
case 'p': /* "VAGp" (extended) [most common, ex Ratchet & Clank] */
|
||||
|
||||
if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
|
||||
if (check_extensions(streamFile,"vig")) { /* MX vs. ATV Untamed PS2 */
|
||||
channel_count = 2; /* normal interleave */
|
||||
loop_flag = 0;
|
||||
}
|
||||
else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
|
||||
channel_count = 2; /* The Simpsons Wrestling PSX interleave */
|
||||
loop_flag = 0;
|
||||
}
|
||||
@ -136,7 +140,14 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
||||
case 'p': // VAGp
|
||||
interleave=0x10;
|
||||
|
||||
if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
|
||||
if (check_extensions(streamFile,"vig")) { /* MX vs. ATV Untamed PS2 */
|
||||
vgmstream->layout_type=layout_interleave;
|
||||
vgmstream->meta_type=meta_PS2_VAGp;
|
||||
|
||||
vgmstream->num_samples = (datasize - 0x10*channel_count) / 16 * 28;
|
||||
start_offset = 0x800;
|
||||
}
|
||||
else if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* interleaved "VAGp" */
|
||||
interleave = 0x6000; /* The Simpsons Wrestling PSX interleave, includes header */
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->meta_type = meta_PS2_VAGs;
|
||||
|
@ -58,61 +58,3 @@ fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* XA2 (RC Revenge Pro) */
|
||||
VGMSTREAM * init_vgmstream_ps2_xa2_rrp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("xa2",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0xC,streamFile) != 0x00000000)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitLE(0x0,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1000;
|
||||
vgmstream->meta_type = meta_PS2_XA2_RRP;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
59
src/meta/ps2_xa2_rrp.c
Normal file
59
src/meta/ps2_xa2_rrp.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "meta.h"
|
||||
|
||||
|
||||
/* XA2 (RC Revenge Pro) */
|
||||
VGMSTREAM * init_vgmstream_ps2_xa2_rrp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("xa2",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0xC,streamFile) != 0x00000000)
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitLE(0x0,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1000;
|
||||
vgmstream->meta_type = meta_PS2_XA2_RRP;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
/* clean up anything we may have opened */
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -11,8 +11,8 @@ VGMSTREAM * init_vgmstream_ps3_msf(STREAMFILE *streamFile) {
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile,"msf,at3")) goto fail; /* .at3: Silent Hill HD Collection */
|
||||
/* check extension, case insensitive (.at3: Silent Hill HD Collection, .mp3: Darkstalkers Resurrection) */
|
||||
if (!check_extensions(streamFile,"msf,at3,mp3")) goto fail;
|
||||
|
||||
/* "WMSF" variation with a mini header over the MSFC header, same extension */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x574D5346) {
|
||||
|
@ -888,15 +888,12 @@ fail:
|
||||
/* RSD6WADP */
|
||||
VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("rsd",filename_extension(filename))) goto fail;
|
||||
if (!check_extensions(streamFile,"rsd"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x52534436) /* RSD6 */
|
||||
@ -906,54 +903,25 @@ VGMSTREAM * init_vgmstream_rsd6wadp(STREAMFILE *streamFile) {
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = read_32bitLE(0x8,streamFile);
|
||||
start_offset = 0x800;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_flag;
|
||||
vgmstream->loop_end_sample = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave_byte; //layout_interleave;
|
||||
vgmstream->interleave_block_size = 2; //read_32bitLE(0xC,streamFile);
|
||||
vgmstream->coding_type = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = 0x02; //read_32bitLE(0xC,streamFile);
|
||||
vgmstream->meta_type = meta_RSD6WADP;
|
||||
|
||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||
int i;
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x1A4+i*2,streamFile);
|
||||
}
|
||||
if (vgmstream->channels) {
|
||||
for (i=0;i<16;i++) {
|
||||
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(0x1CC+i*2,streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
dsp_read_coefs_be(vgmstream,streamFile,0x1a4,0x28);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -1,31 +1,14 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "sqex_scd_streamfile.h"
|
||||
|
||||
/* Square-Enix SCD (FF XIII, XIV) */
|
||||
|
||||
/* special streamfile type to handle deinterleaving of complete files,
|
||||
(based heavily on AIXSTREAMFILE */
|
||||
typedef struct _SCDINTSTREAMFILE
|
||||
{
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
const char * filename;
|
||||
off_t start_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t interleave_block_size;
|
||||
off_t stride_size;
|
||||
size_t total_size;
|
||||
} SCDINTSTREAMFILE;
|
||||
|
||||
static STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size);
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
||||
static void scd_ogg_decrypt_v3_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* SCD - Square-Enix console games (FF XIII, XIV) */
|
||||
VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
@ -34,39 +17,39 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
int32_t loop_start, loop_end;
|
||||
|
||||
int target_stream = streamFile->stream_index;
|
||||
int loop_flag = 0, channel_count, codec_id;
|
||||
int loop_flag = 0, channel_count, codec_id, sample_rate;
|
||||
int aux_chunk_count;
|
||||
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if ( !check_extensions(streamFile, "scd") ) goto fail;
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
|
||||
/* SEDB */
|
||||
if (read_32bitBE(0,streamFile) != 0x53454442) goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53454442) goto fail;
|
||||
/* SSCF */
|
||||
if (read_32bitBE(4,streamFile) != 0x53534346) goto fail;
|
||||
if (read_32bitBE(0x04,streamFile) != 0x53534346) goto fail;
|
||||
|
||||
/** main header section **/
|
||||
if (read_32bitBE(8,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
||||
read_32bitBE(8,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
||||
if (read_32bitBE(0x08,streamFile) == 2 || /* version 2 BE, as seen in FFXIII demo for PS3 */
|
||||
read_32bitBE(0x08,streamFile) == 3) { /* version 3 BE, as seen in FFXIII for PS3 */
|
||||
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
//size_offset = 0x14;
|
||||
} else if (read_32bitLE(8,streamFile) == 3 || /* version 2/3 LE, as seen in FFXIV for PC (and others?) */
|
||||
read_32bitLE(8,streamFile) == 2) {
|
||||
} else if (read_32bitLE(0x08,streamFile) == 3 || /* version 2/3 LE, as seen in FFXIV for PC (and others?) */
|
||||
read_32bitLE(0x08,streamFile) == 2) {
|
||||
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
//size_offset = 0x10;
|
||||
} else goto fail;
|
||||
|
||||
/* 0xc: probably 00=LE, 01=BE */
|
||||
/* 0xd: unk (always 0x04) */
|
||||
/* 0x0c: probably 0=LE, 1=BE */
|
||||
/* 0x0d: unk (always 0x04) */
|
||||
tables_offset = read_16bit(0xe,streamFile);
|
||||
|
||||
#if 0
|
||||
@ -97,14 +80,14 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
meta_offset = read_32bit(headers_offset + (target_stream-1)*4,streamFile);
|
||||
|
||||
/** stream header **/
|
||||
stream_size = read_32bit(meta_offset + 0x0, streamFile);
|
||||
channel_count = read_32bit(meta_offset+4,streamFile);
|
||||
/* 0x8 sample rate */
|
||||
codec_id = read_32bit(meta_offset+0xc,streamFile);
|
||||
stream_size = read_32bit(meta_offset+0x00, streamFile);
|
||||
channel_count = read_32bit(meta_offset+0x04,streamFile);
|
||||
sample_rate = read_32bit(meta_offset+0x08,streamFile);
|
||||
codec_id = read_32bit(meta_offset+0x0c,streamFile);
|
||||
|
||||
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
||||
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
||||
loop_flag = (loop_end > 0);
|
||||
loop_start = read_32bit(meta_offset+0x10,streamFile);
|
||||
loop_end = read_32bit(meta_offset+0x14,streamFile);
|
||||
loop_flag = (loop_end > 0);
|
||||
|
||||
post_meta_offset = meta_offset + 0x20;
|
||||
start_offset = post_meta_offset + read_32bit(meta_offset+0x18,streamFile);
|
||||
@ -123,18 +106,14 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
/* special case using init_vgmstream_ogg_vorbis with callbacks */
|
||||
if (codec_id == 0x6)
|
||||
{
|
||||
if (codec_id == 0x06) {
|
||||
VGMSTREAM * result = NULL;
|
||||
uint32_t seek_table_size, vorb_header_size;
|
||||
uint8_t xor_version, xor_byte;
|
||||
vgm_vorbis_info_t inf;
|
||||
vgm_vorbis_info_t inf = {0};
|
||||
|
||||
|
||||
memset(&inf, 0, sizeof(inf));
|
||||
inf.loop_start = loop_start;
|
||||
inf.loop_end = loop_end;
|
||||
inf.loop_flag = loop_flag;
|
||||
@ -205,13 +184,12 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bit(meta_offset+8,streamFile);
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_streams = headers_entries;
|
||||
vgmstream->meta_type = meta_SQEX_SCD;
|
||||
|
||||
switch (codec_id) {
|
||||
case 0x1:
|
||||
/* PCM */
|
||||
case 0x01: /* PCM */
|
||||
vgmstream->coding_type = coding_PCM16_int;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = stream_size / 2 / channel_count;
|
||||
@ -221,124 +199,111 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_end_sample = loop_end / 2 / channel_count;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: /* OGG [Final Fantasy XIII-2 (PS3), Final Fantasy XIV (PC)] */
|
||||
goto fail; /* handled above */
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x7:
|
||||
/* MPEG */
|
||||
{
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
coding_t ct;
|
||||
case 0x07: { /* MPEG [Final Fantasy XIII (PS3)] */
|
||||
mpeg_codec_data *mpeg_data = NULL;
|
||||
|
||||
/* Drakengard 3, some Kingdom Hearts */
|
||||
if (vgmstream->sample_rate == 47999)
|
||||
vgmstream->sample_rate = 48000;
|
||||
if (vgmstream->sample_rate == 44099)
|
||||
vgmstream->sample_rate = 44100;
|
||||
/* Drakengard 3, some Kingdom Hearts */
|
||||
if (vgmstream->sample_rate == 47999)
|
||||
vgmstream->sample_rate = 48000;
|
||||
if (vgmstream->sample_rate == 44099)
|
||||
vgmstream->sample_rate = 44100;
|
||||
|
||||
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &ct, vgmstream->channels);
|
||||
if (!mpeg_data) goto fail;
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels);
|
||||
if (!mpeg_data) goto fail;
|
||||
vgmstream->codec_data = mpeg_data;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->coding_type = ct;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
|
||||
vgmstream->num_samples -= vgmstream->num_samples%576;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
|
||||
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
|
||||
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
|
||||
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
|
||||
}
|
||||
vgmstream->interleave_block_size = 0;
|
||||
vgmstream->num_samples = mpeg_bytes_to_samples(stream_size, mpeg_data);
|
||||
vgmstream->num_samples -= vgmstream->num_samples%576;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = mpeg_bytes_to_samples(loop_start, mpeg_data);
|
||||
vgmstream->loop_start_sample -= vgmstream->loop_start_sample%576;
|
||||
vgmstream->loop_end_sample = mpeg_bytes_to_samples(loop_end, mpeg_data);
|
||||
vgmstream->loop_end_sample -= vgmstream->loop_end_sample%576;
|
||||
}
|
||||
vgmstream->interleave_block_size = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case 0xC:
|
||||
/* MS ADPCM */
|
||||
case 0x0C: /* MS ADPCM [Final Fantasy XIV (PC) sfx] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0xc,streamFile);
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
||||
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x0c,streamFile);
|
||||
|
||||
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = msadpcm_bytes_to_samples(loop_start, vgmstream->interleave_block_size, vgmstream->channels);
|
||||
vgmstream->loop_end_sample = msadpcm_bytes_to_samples(loop_end, vgmstream->interleave_block_size, vgmstream->channels);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA: /* Dragon Quest X (Wii) */
|
||||
case 0x15: /* Dragon Quest X (Wii U) (no apparent differences except higher sample rate) */
|
||||
/* GC/Wii DSP ADPCM */
|
||||
{
|
||||
STREAMFILE * file;
|
||||
int i;
|
||||
const off_t interleave_size = 0x800;
|
||||
const off_t stride_size = interleave_size * channel_count;
|
||||
case 0x0A: /* DSP ADPCM [Dragon Quest X (Wii)] */
|
||||
case 0x15: { /* DSP ADPCM [Dragon Quest X (Wii U)] (no apparent differences except higher sample rate) */
|
||||
STREAMFILE * file;
|
||||
int i;
|
||||
const off_t interleave_size = 0x800;
|
||||
const off_t stride_size = interleave_size * channel_count;
|
||||
size_t total_size;
|
||||
scd_int_codec_data * data = NULL;
|
||||
|
||||
size_t total_size;
|
||||
|
||||
scd_int_codec_data * data = NULL;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_scd_int;
|
||||
|
||||
/* a normal DSP header... */
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0,streamFile);
|
||||
total_size = (read_32bitBE(start_offset+4,streamFile)+1)/2;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end+1;
|
||||
}
|
||||
|
||||
/* verify other channel headers */
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
|
||||
(read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* the primary streamfile we'll be using */
|
||||
file = streamFile->open(streamFile,filename,stride_size);
|
||||
if (!file)
|
||||
goto fail;
|
||||
|
||||
vgmstream->ch[0].streamfile = file;
|
||||
|
||||
data = malloc(sizeof(scd_int_codec_data));
|
||||
data->substream_count = channel_count;
|
||||
data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
|
||||
data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
STREAMFILE * intfile =
|
||||
open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||
if (!intfile)
|
||||
goto fail;
|
||||
|
||||
data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
|
||||
data->intfiles[i] = intfile;
|
||||
if (!data->substreams[i])
|
||||
goto fail;
|
||||
|
||||
/* TODO: only handles mono substreams, though that's all we have with DSP */
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
/* copy the channels */
|
||||
memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
|
||||
/* copy the whole VGMSTREAM */
|
||||
memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
|
||||
|
||||
}
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_scd_int;
|
||||
|
||||
/* a normal DSP header... */
|
||||
total_size = (read_32bitBE(start_offset+0x04,streamFile)+1)/2;
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end+1;
|
||||
}
|
||||
|
||||
/* verify other channel headers */
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
if (read_32bitBE(start_offset+interleave_size*i+0,streamFile) != vgmstream->num_samples ||
|
||||
(read_32bitBE(start_offset+4,streamFile)+1)/2 != total_size) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* the primary streamfile we'll be using */
|
||||
file = streamFile->open(streamFile,filename,stride_size);
|
||||
if (!file) goto fail;
|
||||
|
||||
vgmstream->ch[0].streamfile = file;
|
||||
|
||||
data = malloc(sizeof(scd_int_codec_data));
|
||||
data->substream_count = channel_count;
|
||||
data->substreams = calloc(channel_count, sizeof(VGMSTREAM *));
|
||||
data->intfiles = calloc(channel_count, sizeof(STREAMFILE *));
|
||||
|
||||
vgmstream->codec_data = data;
|
||||
|
||||
for (i=0;i<channel_count;i++) {
|
||||
STREAMFILE * intfile =
|
||||
open_scdint_with_STREAMFILE(file, "ARBITRARY.DSP", start_offset+interleave_size*i, interleave_size, stride_size, total_size);
|
||||
if (!intfile) goto fail;
|
||||
|
||||
data->substreams[i] = init_vgmstream_ngc_dsp_std(intfile);
|
||||
data->intfiles[i] = intfile;
|
||||
if (!data->substreams[i]) goto fail;
|
||||
|
||||
/* TODO: only handles mono substreams, though that's all we have with DSP */
|
||||
/* save start things so we can restart for seeking/looping */
|
||||
memcpy(data->substreams[i]->start_ch,data->substreams[i]->ch,sizeof(VGMSTREAMCHANNEL)*1);
|
||||
memcpy(data->substreams[i]->start_vgmstream,data->substreams[i],sizeof(VGMSTREAM));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0xB:
|
||||
/* XMA2 */ /* Lightning Returns SFX, FFXIII (X360) */
|
||||
{
|
||||
case 0x0B: { /* XMA2 [Final Fantasy (X360), Lightning Returns (X360) sfx] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[200];
|
||||
int32_t bytes;
|
||||
@ -356,44 +321,42 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xE:
|
||||
/* ATRAC3plus */ /* Lord of Arcana (PSP) */
|
||||
{
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
case 0x0E: { /* ATRAC3plus [Lord of Arcana (PSP)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
|
||||
/* full RIFF header at start_offset/post_meta_offset (same) */
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
/* full RIFF header at start_offset/post_meta_offset (same) */
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
/* manually read skip_samples if FFmpeg didn't do it */
|
||||
if (ffmpeg_data->skipSamples <= 0) {
|
||||
off_t chunk_offset;
|
||||
size_t chunk_size, fact_skip_samples = 0;
|
||||
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
|
||||
goto fail;
|
||||
if (chunk_size == 0x8) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
|
||||
} else if (chunk_size == 0xc) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
|
||||
}
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
|
||||
/* manually read skip_samples if FFmpeg didn't do it */
|
||||
if (ffmpeg_data->skipSamples <= 0) {
|
||||
off_t chunk_offset;
|
||||
size_t chunk_size, fact_skip_samples = 0;
|
||||
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
|
||||
goto fail;
|
||||
if (chunk_size == 0x8) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
|
||||
} else if (chunk_size == 0xc) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
|
||||
}
|
||||
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
||||
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
|
||||
}
|
||||
break;
|
||||
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
VGM_LOG("SCD: unknown codec_id 0x%x\n", codec_id);
|
||||
goto fail;
|
||||
@ -410,131 +373,6 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE *open_scdint_impl(SCDINTSTREAMFILE *streamfile,const char * const filename,size_t buffersize)
|
||||
{
|
||||
SCDINTSTREAMFILE *newfile;
|
||||
|
||||
if (strcmp(filename, streamfile->filename))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
memcpy(newfile,streamfile,sizeof(SCDINTSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static void close_scdint(SCDINTSTREAMFILE *streamfile)
|
||||
{
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_scdint(SCDINTSTREAMFILE *streamfile)
|
||||
{
|
||||
return streamfile->total_size;
|
||||
}
|
||||
|
||||
static size_t get_offset_scdint(SCDINTSTREAMFILE *streamfile)
|
||||
{
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_scdint(SCDINTSTREAMFILE *streamfile, char *buffer, size_t length)
|
||||
{
|
||||
strncpy(buffer,streamfile->filename,length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length)
|
||||
{
|
||||
size_t sz = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
|
||||
block_num = offset / streamfile->interleave_block_size;
|
||||
intrablock_offset = offset % streamfile->interleave_block_size;
|
||||
streamfile->current_logical_offset = offset;
|
||||
physical_offset = streamfile->start_physical_offset + block_num * streamfile->stride_size + intrablock_offset;
|
||||
|
||||
length_available =
|
||||
streamfile->interleave_block_size - intrablock_offset;
|
||||
|
||||
if (length < length_available)
|
||||
{
|
||||
to_read = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0)
|
||||
{
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
physical_offset,
|
||||
to_read, streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
|
||||
streamfile->current_logical_offset = offset + bytes_read;
|
||||
|
||||
if (bytes_read != to_read)
|
||||
{
|
||||
/* an error which we will not attempt to handle here */
|
||||
return sz;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* start_offset is for *this* interleaved stream */
|
||||
static STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size)
|
||||
{
|
||||
SCDINTSTREAMFILE * scd = NULL;
|
||||
|
||||
/* _scdint funcs can't handle this case */
|
||||
if (start_offset + total_size > file->get_size(file))
|
||||
return NULL;
|
||||
|
||||
scd = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!scd)
|
||||
return NULL;
|
||||
|
||||
scd->sf.read = (void*)read_scdint;
|
||||
scd->sf.get_size = (void*)get_size_scdint;
|
||||
scd->sf.get_offset = (void*)get_offset_scdint;
|
||||
scd->sf.get_name = (void*)get_name_scdint;
|
||||
scd->sf.get_realname = (void*)get_name_scdint;
|
||||
scd->sf.open = (void*)open_scdint_impl;
|
||||
scd->sf.close = (void*)close_scdint;
|
||||
|
||||
scd->real_file = file;
|
||||
scd->filename = filename;
|
||||
scd->start_physical_offset = start_offset;
|
||||
scd->current_logical_offset = 0;
|
||||
scd->interleave_block_size = interleave_block_size;
|
||||
scd->stride_size = stride_size;
|
||||
scd->total_size = total_size;
|
||||
|
||||
return &scd->sf;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
static void scd_ogg_decrypt_v2_callback(void *ptr, size_t size, size_t nmemb, void *datasource, int bytes_read) {
|
||||
|
134
src/meta/sqex_scd_streamfile.h
Normal file
134
src/meta/sqex_scd_streamfile.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef _SQEX_SCD_STREAMFILE_H_
|
||||
#define _SQEX_SCD_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
/* special streamfile type to handle deinterleaving of complete files (based heavily on AIXSTREAMFILE */
|
||||
|
||||
typedef struct _SCDINTSTREAMFILE {
|
||||
STREAMFILE sf;
|
||||
STREAMFILE *real_file;
|
||||
const char * filename;
|
||||
off_t start_physical_offset;
|
||||
off_t current_logical_offset;
|
||||
off_t interleave_block_size;
|
||||
off_t stride_size;
|
||||
size_t total_size;
|
||||
} SCDINTSTREAMFILE;
|
||||
|
||||
|
||||
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size);
|
||||
|
||||
|
||||
static STREAMFILE *open_scdint_impl(SCDINTSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
|
||||
SCDINTSTREAMFILE *newfile;
|
||||
|
||||
if (strcmp(filename, streamfile->filename))
|
||||
return NULL;
|
||||
|
||||
newfile = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!newfile)
|
||||
return NULL;
|
||||
|
||||
memcpy(newfile,streamfile,sizeof(SCDINTSTREAMFILE));
|
||||
return &newfile->sf;
|
||||
}
|
||||
|
||||
static void close_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
free(streamfile);
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t get_size_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
return streamfile->total_size;
|
||||
}
|
||||
|
||||
static size_t get_offset_scdint(SCDINTSTREAMFILE *streamfile) {
|
||||
return streamfile->current_logical_offset;
|
||||
}
|
||||
|
||||
static void get_name_scdint(SCDINTSTREAMFILE *streamfile, char *buffer, size_t length) {
|
||||
strncpy(buffer,streamfile->filename,length);
|
||||
buffer[length-1]='\0';
|
||||
}
|
||||
|
||||
static size_t read_scdint(SCDINTSTREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length) {
|
||||
size_t sz = 0;
|
||||
|
||||
while (length > 0) {
|
||||
off_t to_read;
|
||||
off_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
|
||||
block_num = offset / streamfile->interleave_block_size;
|
||||
intrablock_offset = offset % streamfile->interleave_block_size;
|
||||
streamfile->current_logical_offset = offset;
|
||||
physical_offset = streamfile->start_physical_offset + block_num * streamfile->stride_size + intrablock_offset;
|
||||
|
||||
length_available = streamfile->interleave_block_size - intrablock_offset;
|
||||
|
||||
if (length < length_available) {
|
||||
to_read = length;
|
||||
}
|
||||
else {
|
||||
to_read = length_available;
|
||||
}
|
||||
|
||||
if (to_read > 0) {
|
||||
size_t bytes_read;
|
||||
|
||||
bytes_read = read_streamfile(dest,
|
||||
physical_offset,
|
||||
to_read, streamfile->real_file);
|
||||
|
||||
sz += bytes_read;
|
||||
|
||||
streamfile->current_logical_offset = offset + bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return sz; /* an error which we will not attempt to handle here */
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return sz;
|
||||
}
|
||||
|
||||
/* start_offset is for *this* interleaved stream */
|
||||
/*static*/ STREAMFILE *open_scdint_with_STREAMFILE(STREAMFILE *file, const char * filename, off_t start_offset, off_t interleave_block_size, off_t stride_size, size_t total_size) {
|
||||
SCDINTSTREAMFILE * scd = NULL;
|
||||
|
||||
/* _scdint funcs can't handle this case */
|
||||
if (start_offset + total_size > file->get_size(file))
|
||||
return NULL;
|
||||
|
||||
scd = malloc(sizeof(SCDINTSTREAMFILE));
|
||||
if (!scd)
|
||||
return NULL;
|
||||
|
||||
scd->sf.read = (void*)read_scdint;
|
||||
scd->sf.get_size = (void*)get_size_scdint;
|
||||
scd->sf.get_offset = (void*)get_offset_scdint;
|
||||
scd->sf.get_name = (void*)get_name_scdint;
|
||||
scd->sf.get_realname = (void*)get_name_scdint;
|
||||
scd->sf.open = (void*)open_scdint_impl;
|
||||
scd->sf.close = (void*)close_scdint;
|
||||
|
||||
scd->real_file = file;
|
||||
scd->filename = filename;
|
||||
scd->start_physical_offset = start_offset;
|
||||
scd->current_logical_offset = 0;
|
||||
scd->interleave_block_size = interleave_block_size;
|
||||
scd->stride_size = stride_size;
|
||||
scd->total_size = total_size;
|
||||
|
||||
return &scd->sf;
|
||||
}
|
||||
|
||||
#endif /* _SCD_STREAMFILE_H_ */
|
@ -87,7 +87,7 @@ VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->thpNextFrameSize=read_32bitBE(0x18,streamFile);
|
||||
vgmstream->full_block_size = read_32bitBE(0x18,streamFile); /* block size of current block, changes every time */
|
||||
thp_block_update(start_offset,vgmstream);
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
|
@ -219,7 +219,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
} else if (txth.channels > 1 && txth.codec_mode == 1) {
|
||||
if (!txth.interleave) goto fail;
|
||||
vgmstream->layout_type = layout_interleave_byte;
|
||||
coding = coding_NGC_DSP_subint;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = txth.interleave;
|
||||
} else if (txth.channels == 1 || txth.codec_mode == 2) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -471,7 +472,13 @@ static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_h
|
||||
if (!parse_num(streamFile,val, &txth->codec_mode)) goto fail;
|
||||
}
|
||||
else if (0==strcmp(key,"interleave")) {
|
||||
if (!parse_num(streamFile,val, &txth->interleave)) goto fail;
|
||||
if (0==strcmp(val,"half_size")) {
|
||||
txth->interleave = txth->data_size / txth->channels;
|
||||
VGM_LOG("int=%x, ds=%x\n", txth->interleave, txth->data_size);
|
||||
}
|
||||
else {
|
||||
if (!parse_num(streamFile,val, &txth->interleave)) goto fail;
|
||||
}
|
||||
}
|
||||
else if (0==strcmp(key,"id_value")) {
|
||||
if (!parse_num(streamFile,val, &txth->id_value)) goto fail;
|
||||
|
@ -70,10 +70,11 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) {
|
||||
switch(((uint64_t)platform << 32) | type) {
|
||||
|
||||
case 0x57696E2070636D20: /* "Win pcm " */
|
||||
case 0x4F72626970636D20: /* "Orbipcm " (Orbis = PS4)*/
|
||||
/* chunks: "data" */
|
||||
vgmstream->coding_type = little_endian ? coding_PCM16LE : coding_PCM16BE;
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = block_align;
|
||||
vgmstream->interleave_block_size = block_align; /* usually 0x04 */
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bits_per_sample);
|
||||
break;
|
||||
@ -88,7 +89,7 @@ VGMSTREAM * init_vgmstream_ubi_raki(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
case 0x5769692061647063: /* "Wii adpc" */
|
||||
case 0x4361666561647063: /* "Cafeadpc" (WiiU) */
|
||||
case 0x4361666561647063: /* "Cafeadpc" (Cafe = WiiU) */
|
||||
/* chunks: "datS" (stereo), "datL" (mono or full interleave), "datR" (full interleave), "data" equivalents */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
|
||||
|
@ -184,13 +184,18 @@ VGMSTREAM * init_vgmstream_ubi_sb(STREAMFILE *streamFile) {
|
||||
vgmstream->interleave_block_size = sb.stream_size / sb.channels;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(sb.stream_size, sb.channels);
|
||||
|
||||
if (sb.channels > 1) { VGM_LOG("UBI SB: >1 channel\n"); goto fail; } //todo
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case FMT_AT3: {
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
/* skip weird value (3, 4) in Brothers in Arms: D-Day (PSP) */
|
||||
if (read_32bitBE(start_offset+0x04,streamData) == 0x52494646) {
|
||||
start_offset += 0x04;
|
||||
sb.stream_size -= 0x04;
|
||||
}
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, sb.stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -480,6 +485,7 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
int is_sb5 = check_extensions(streamFile, "sb5"); /* PSP, 3DS? */
|
||||
//int is_sb6 = check_extensions(streamFile, "sb6"); /* PS3? */
|
||||
int is_sb7 = check_extensions(streamFile, "sb7"); /* Wii */
|
||||
int is_biadd_psp = 0;
|
||||
|
||||
|
||||
/* The format varies with almost every game + platform (some kind of class serialization?),
|
||||
@ -554,6 +560,21 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Tom Clancy's Rainbow Six 3 (2003)(PS2) */
|
||||
if (sb->version == 0x000A0007 && is_sb1) {
|
||||
sb->section1_entry_size = 0x48;
|
||||
sb->section2_entry_size = 0x6c;
|
||||
|
||||
sb->external_flag_offset = 0; /* no apparent flag */
|
||||
sb->channels_offset = 0x20;
|
||||
sb->sample_rate_offset = 0x24;
|
||||
sb->num_samples_offset = 0x30;
|
||||
sb->stream_name_offset = 0x40;
|
||||
sb->stream_type_offset = 0x68;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: Sands of Time (2003)(GC) */
|
||||
if ((sb->version == 0x000A0002 && is_sb3) || /* Prince of Persia 1 port */
|
||||
(sb->version == 0x000A0004 && is_sb3)) { /* main game */
|
||||
@ -649,8 +670,17 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: Revelations (2005)(PSP) */
|
||||
/* two games with same id; use project file as identifier */
|
||||
if (sb->version == 0x0012000C && is_sb4) {
|
||||
STREAMFILE * streamTest = open_stream_name(streamFile, "BIAAUDIO.SP4");
|
||||
if (streamTest) {
|
||||
is_biadd_psp = 1;
|
||||
close_streamfile(streamTest);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prince of Persia: Revelations (2005)(PSP) */
|
||||
if (sb->version == 0x0012000C && is_sb4 && !is_biadd_psp) {
|
||||
sb->section1_entry_size = 0x68;
|
||||
sb->section2_entry_size = 0x84;
|
||||
|
||||
@ -665,6 +695,23 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Brothers in Arms - D-Day (2006)(PSP) */
|
||||
if (sb->version == 0x0012000C && is_sb4 && is_biadd_psp) {
|
||||
sb->section1_entry_size = 0x80;
|
||||
sb->section2_entry_size = 0x94;
|
||||
|
||||
sb->stream_id_offset = 0x0; //todo 0x1C or 0x20? table seems problematic
|
||||
sb->external_flag_offset = 0x24;
|
||||
sb->num_samples_offset = 0; /* variable? */
|
||||
sb->sample_rate_offset = 0x44;
|
||||
sb->channels_offset = 0x4c;
|
||||
sb->stream_type_offset = 0x50;
|
||||
sb->stream_name_offset = 0x54;
|
||||
|
||||
sb->has_internal_names = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: The Two Thrones (2005)(PC) */
|
||||
if (sb->version == 0x00150000 && is_sb0) {
|
||||
sb->section1_entry_size = 0x68;
|
||||
@ -731,21 +778,6 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Red Steel (2006)(Wii) */
|
||||
if (sb->version == 0x00180006 && is_sb7) { /* same as 0x00150000 */
|
||||
sb->section1_entry_size = 0x68;
|
||||
sb->section2_entry_size = 0x6c;
|
||||
|
||||
sb->external_flag_offset = 0x28; /* maybe 0x2c */
|
||||
sb->num_samples_offset = 0x3c;
|
||||
sb->sample_rate_offset = 0x50;
|
||||
sb->channels_offset = 0x58;
|
||||
sb->stream_type_offset = 0x5c;
|
||||
sb->extra_name_offset = 0x60;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: Rival Swords (2007)(PSP) */
|
||||
if (sb->version == 0x00180005 && is_sb5) {
|
||||
sb->section1_entry_size = 0x48;
|
||||
@ -762,6 +794,51 @@ static int config_sb_header_version(ubi_sb_header * sb, STREAMFILE *streamFile)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Rainbow Six Vegas (2007)(PSP) */
|
||||
if (sb->version == 0x00180006 && is_sb5) {
|
||||
sb->section1_entry_size = 0x48;
|
||||
sb->section2_entry_size = 0x54;
|
||||
|
||||
sb->external_flag_offset = 0;
|
||||
sb->channels_offset = 0x28;
|
||||
sb->sample_rate_offset = 0x2c;
|
||||
//sb->num_samples_offset = 0x34 or 0x3c /* varies */
|
||||
sb->extra_name_offset = 0x44;
|
||||
sb->stream_type_offset = 0x48;
|
||||
|
||||
sb->has_extra_name_flag = 1;
|
||||
sb->has_rotating_ids = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* todo Rainbow Six Vegas changes:
|
||||
* some streams use type 0x06 instead of 0x01, known values:
|
||||
* 0x0c: header offset in extra table?
|
||||
* 0x2c: stream size
|
||||
* 0x30: stream offset
|
||||
* most other fields are fixed, comparing different files
|
||||
* header is in the extra table, after the stream name (repeated?)
|
||||
* (0x04: sample rate, 0x0c: channels, etc)
|
||||
* stream data may be newer Ubi ADPCM (see DecUbiSnd)
|
||||
*/
|
||||
#endif
|
||||
|
||||
/* Red Steel (2006)(Wii) */
|
||||
if (sb->version == 0x00180006 && is_sb7) { /* same as 0x00150000 */
|
||||
sb->section1_entry_size = 0x68;
|
||||
sb->section2_entry_size = 0x6c;
|
||||
|
||||
sb->external_flag_offset = 0x28; /* maybe 0x2c */
|
||||
sb->num_samples_offset = 0x3c;
|
||||
sb->sample_rate_offset = 0x50;
|
||||
sb->channels_offset = 0x58;
|
||||
sb->stream_type_offset = 0x5c;
|
||||
sb->extra_name_offset = 0x60;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: Rival Swords (2007)(Wii) */
|
||||
if (sb->version == 0x00190003 && is_sb7) {
|
||||
sb->section1_entry_size = 0x68;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
@ -37,12 +38,11 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
|
||||
switch(type) {
|
||||
case 2: /* VAG */
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->layout_type = channel_count == 6 ? layout_blocked_vawx : layout_interleave ;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x44,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x48,streamFile);
|
||||
/* todo 6ch has 0x8000 blocks and must skip last 0x20 each block (or, skip 0x20 every 0x1550*6 */
|
||||
|
||||
break;
|
||||
|
||||
@ -110,6 +110,9 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
|
||||
if (vgmstream->layout_type == layout_blocked_vawx)
|
||||
block_update_vawx(start_offset,vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -66,67 +66,3 @@ fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* VSF with SMSS header (from Tiny Toon Adventures: Defenders of the Universe */
|
||||
VGMSTREAM * init_vgmstream_ps2_vsf_tta(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("vsf",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x534D5353) /* "SMSS" */
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = read_32bitLE(0x18,streamFile);
|
||||
channel_count = read_32bitLE(0x0c,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile)*2)*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x1c,streamFile)*2)*28/16/channel_count;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x8,streamFile);
|
||||
vgmstream->meta_type = meta_PS2_VSF_TTA;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
66
src/meta/vsf_tta.c
Normal file
66
src/meta/vsf_tta.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "meta.h"
|
||||
|
||||
|
||||
/* VSF with SMSS header (from Tiny Toon Adventures: Defenders of the Universe) */
|
||||
VGMSTREAM * init_vgmstream_ps2_vsf_tta(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
off_t start_offset;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("vsf",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x534D5353) /* "SMSS" */
|
||||
goto fail;
|
||||
|
||||
|
||||
loop_flag = read_32bitLE(0x18,streamFile);
|
||||
channel_count = read_32bitLE(0x0c,streamFile);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x800;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)*28/16/channel_count;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (read_32bitLE(0x18,streamFile)*2)*28/16/channel_count;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x1c,streamFile)*2)*28/16/channel_count;
|
||||
}
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x8,streamFile);
|
||||
vgmstream->meta_type = meta_PS2_VSF_TTA;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -55,6 +55,13 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE *streamFile) {
|
||||
vgmstream->meta_type = meta_VXN;
|
||||
|
||||
switch (codec) {
|
||||
case 0x0001: /* PCM */
|
||||
if (bits != 16) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->interleave_block_size = block_align;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
break;
|
||||
|
||||
case 0x0002: /* MSADPCM (ex. Asphalt 7) */
|
||||
if (bits != 4) goto fail;
|
||||
|
15
src/util.h
15
src/util.h
@ -61,17 +61,16 @@ static inline int get_low_nibble_signed(uint8_t n) {
|
||||
return nibble_to_int[n&0xf];
|
||||
}
|
||||
|
||||
/* return a file's extension (a pointer to the first character of the
|
||||
* extension in the original filename or the ending null byte if no extension
|
||||
*/
|
||||
const char * filename_extension(const char * filename);
|
||||
|
||||
static inline int clamp16(int32_t val) {
|
||||
if (val>32767) return 32767;
|
||||
if (val<-32768) return -32768;
|
||||
return val;
|
||||
if (val>32767) return 32767;
|
||||
if (val<-32768) return -32768;
|
||||
return val;
|
||||
}
|
||||
|
||||
/* return a file's extension (a pointer to the first character of the
|
||||
* extension in the original filename or the ending null byte if no extension */
|
||||
const char * filename_extension(const char * filename);
|
||||
|
||||
void swap_samples_le(sample *buf, int count);
|
||||
|
||||
void concatn(int length, char * dst, const char * src);
|
||||
|
339
src/vgmstream.c
339
src/vgmstream.c
@ -147,7 +147,6 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_kraw,
|
||||
init_vgmstream_ps2_omu,
|
||||
init_vgmstream_ps2_xa2,
|
||||
//init_vgmstream_idsp,
|
||||
init_vgmstream_idsp2,
|
||||
init_vgmstream_idsp3,
|
||||
init_vgmstream_idsp4,
|
||||
@ -279,7 +278,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_dsp_bdsp,
|
||||
init_vgmstream_ps2_vms,
|
||||
init_vgmstream_xau,
|
||||
init_vgmstream_gh3_bar,
|
||||
init_vgmstream_bar,
|
||||
init_vgmstream_ffw,
|
||||
init_vgmstream_dsp_dspw,
|
||||
init_vgmstream_ps2_jstm,
|
||||
@ -440,21 +439,6 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
#ifdef VGM_DEBUG_OUTPUT
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* debug fun */
|
||||
if (vgmstream->coding_type != coding_FFmpeg){
|
||||
int i = 0;
|
||||
|
||||
/* probable segfault but some layouts/codecs can ignore these */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
VGM_ASSERT(vgmstream->ch[i].streamfile == NULL, "VGMSTREAM: null streamfile in ch%i\n",i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif/*VGM_DEBUG_OUTPUT*/
|
||||
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* check FFmpeg streams here, for lack of a better place */
|
||||
if (vgmstream->coding_type == coding_FFmpeg) {
|
||||
@ -577,28 +561,6 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_aix) {
|
||||
aix_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
data->current_segment = 0;
|
||||
for (i=0;i<data->segment_count*data->stream_count;i++)
|
||||
{
|
||||
reset_vgmstream(data->adxs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_aax) {
|
||||
aax_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
data->current_segment = 0;
|
||||
for (i=0;i<data->segment_count;i++)
|
||||
{
|
||||
reset_vgmstream(data->adxs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
vgmstream->coding_type == coding_NWA0 ||
|
||||
vgmstream->coding_type == coding_NWA1 ||
|
||||
@ -611,19 +573,38 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
|
||||
reset_nwa(data->nwa);
|
||||
}
|
||||
|
||||
|
||||
if (vgmstream->layout_type==layout_aix) {
|
||||
aix_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
data->current_segment = 0;
|
||||
for (i=0;i<data->segment_count*data->stream_count;i++) {
|
||||
reset_vgmstream(data->adxs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_aax) {
|
||||
aax_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
data->current_segment = 0;
|
||||
for (i=0;i<data->segment_count;i++) {
|
||||
reset_vgmstream(data->adxs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_scd_int) {
|
||||
scd_int_codec_data *data = vgmstream->codec_data;
|
||||
int i;
|
||||
|
||||
for (i=0;i<data->substream_count;i++)
|
||||
{
|
||||
for (i=0;i<data->substream_count;i++) {
|
||||
reset_vgmstream(data->substreams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* simply allocate memory for the VGMSTREAM and its channels */
|
||||
/* Allocate memory and setup a VGMSTREAM */
|
||||
VGMSTREAM * allocate_vgmstream(int channel_count, int looped) {
|
||||
VGMSTREAM * vgmstream;
|
||||
VGMSTREAM * start_vgmstream;
|
||||
@ -705,7 +686,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
free_hca(vgmstream->codec_data);
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (vgmstream->coding_type==coding_EA_MT) {
|
||||
free_ea_mt(vgmstream->codec_data);
|
||||
vgmstream->codec_data = NULL;
|
||||
@ -780,53 +761,6 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_aix) {
|
||||
aix_codec_data *data = (aix_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
if (data->adxs) {
|
||||
int i;
|
||||
for (i=0;i<data->segment_count*data->stream_count;i++) {
|
||||
|
||||
/* note that the AIX close_streamfile won't do anything but
|
||||
* deallocate itself, there is only one open file and that
|
||||
* is in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->adxs[i]);
|
||||
}
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts) {
|
||||
free(data->sample_counts);
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
if (vgmstream->layout_type==layout_aax) {
|
||||
aax_codec_data *data = (aax_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
if (data->adxs) {
|
||||
int i;
|
||||
for (i=0;i<data->segment_count;i++) {
|
||||
|
||||
/* note that the AAX close_streamfile won't do anything but
|
||||
* deallocate itself, there is only one open file and that
|
||||
* is in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->adxs[i]);
|
||||
}
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts) {
|
||||
free(data->sample_counts);
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
if (
|
||||
vgmstream->coding_type == coding_NWA0 ||
|
||||
vgmstream->coding_type == coding_NWA1 ||
|
||||
@ -842,6 +776,51 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (vgmstream->layout_type==layout_aix) {
|
||||
aix_codec_data *data = (aix_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
if (data->adxs) {
|
||||
int i;
|
||||
for (i=0;i<data->segment_count*data->stream_count;i++) {
|
||||
/* note that the close_streamfile won't do anything but deallocate itself,
|
||||
* there is only one open file in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->adxs[i]);
|
||||
}
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts) {
|
||||
free(data->sample_counts);
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_aax) {
|
||||
aax_codec_data *data = (aax_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
if (data->adxs) {
|
||||
int i;
|
||||
for (i=0;i<data->segment_count;i++) {
|
||||
/* note that the close_streamfile won't do anything but deallocate itself,
|
||||
* there is only one open file in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->adxs[i]);
|
||||
}
|
||||
free(data->adxs);
|
||||
}
|
||||
if (data->sample_counts) {
|
||||
free(data->sample_counts);
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
if (vgmstream->layout_type==layout_scd_int) {
|
||||
scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data;
|
||||
|
||||
@ -849,10 +828,8 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
if (data->substreams) {
|
||||
int i;
|
||||
for (i=0;i<data->substream_count;i++) {
|
||||
|
||||
/* note that the scd_int close_streamfile won't do anything
|
||||
* but deallocate itself, there is only one open file and
|
||||
* that is in vgmstream->ch[0].streamfile */
|
||||
/* note that the close_streamfile won't do anything but deallocate itself,
|
||||
* there is only one open file in vgmstream->ch[0].streamfile */
|
||||
close_vgmstream(data->substreams[i]);
|
||||
if(data->intfiles[i]) close_streamfile(data->intfiles[i]);
|
||||
}
|
||||
@ -865,6 +842,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* now that the special cases have had their chance, clean up the standard items */
|
||||
{
|
||||
int i,j;
|
||||
@ -919,7 +897,22 @@ int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double
|
||||
}
|
||||
}
|
||||
|
||||
/* decode data into sample buffer */
|
||||
void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sample, int loop_end_sample) {
|
||||
if (!vgmstream) return;
|
||||
|
||||
/* this requires a bit more messing with the VGMSTREAM than I'm comfortable with... */
|
||||
if (loop_flag && !vgmstream->loop_flag && !vgmstream->loop_ch) {
|
||||
vgmstream->loop_ch = calloc(vgmstream->channels,sizeof(VGMSTREAMCHANNEL));
|
||||
/* loop_ch will be populated when decoded samples reach loop start */
|
||||
}
|
||||
vgmstream->loop_flag = loop_flag;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode data into sample buffer */
|
||||
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_interleave:
|
||||
@ -966,11 +959,9 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
case layout_blocked_ea_sns:
|
||||
case layout_blocked_awc:
|
||||
case layout_blocked_vgs:
|
||||
case layout_blocked_vawx:
|
||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||
break;
|
||||
case layout_interleave_byte:
|
||||
render_vgmstream_interleave_byte(buffer,sample_count,vgmstream);
|
||||
break;
|
||||
case layout_acm:
|
||||
case layout_mus_acm:
|
||||
render_vgmstream_mus_acm(buffer,sample_count,vgmstream);
|
||||
@ -989,7 +980,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
}
|
||||
}
|
||||
|
||||
/* get the size in samples of a single frame (1 or N channels), for interleaved/blocked layouts */
|
||||
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
|
||||
int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_CRI_ADX:
|
||||
@ -1001,6 +992,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_L5_555:
|
||||
return 32;
|
||||
case coding_NGC_DSP:
|
||||
case coding_NGC_DSP_subint:
|
||||
return 14;
|
||||
case coding_PCM16LE:
|
||||
case coding_PCM16LE_XOR_int:
|
||||
@ -1141,16 +1133,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_smallblock_size-4)*2;
|
||||
default:
|
||||
return get_vgmstream_samples_per_frame(vgmstream);
|
||||
}
|
||||
}
|
||||
|
||||
/* get the data size of a single frame (1 or N channels), for interleaved/blocked layouts */
|
||||
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
|
||||
int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_CRI_ADX:
|
||||
@ -1162,7 +1145,9 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
case coding_L5_555:
|
||||
return 18;
|
||||
case coding_NGC_DSP:
|
||||
return 8;
|
||||
return 0x08;
|
||||
case coding_NGC_DSP_subint:
|
||||
return 0x08 * vgmstream->channels;
|
||||
case coding_PCM16LE:
|
||||
case coding_PCM16LE_XOR_int:
|
||||
case coding_PCM16BE:
|
||||
@ -1275,6 +1260,15 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
/* In NDS IMA the frame size is the block size, so the last one is short */
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
return (vgmstream->interleave_smallblock_size-4)*2;
|
||||
default:
|
||||
return get_vgmstream_samples_per_frame(vgmstream);
|
||||
}
|
||||
}
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NDS_IMA:
|
||||
@ -1284,20 +1278,8 @@ int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel) {
|
||||
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NGC_DSP:
|
||||
decode_ngc_dsp_mem(&vgmstream->ch[channel],
|
||||
buffer+samples_written*vgmstream->channels+channel,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do, data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode samples into the buffer. Assume that we have written samples_written into the
|
||||
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
|
||||
void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer) {
|
||||
int chan;
|
||||
|
||||
@ -1346,6 +1328,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_NGC_DSP_subint:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_ngc_dsp_subint(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do,
|
||||
chan, vgmstream->interleave_block_size);
|
||||
}
|
||||
break;
|
||||
case coding_PCM16LE:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_pcm16LE(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
@ -1873,6 +1863,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
|
||||
int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream) {
|
||||
int samples_to_do;
|
||||
int samples_left_this_block;
|
||||
@ -1904,7 +1895,7 @@ int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMST
|
||||
return samples_to_do;
|
||||
}
|
||||
|
||||
/* loop if end sample is reached, and return 1 if we did loop */
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns 1 if loop was done. */
|
||||
int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
||||
/*if (!vgmstream->loop_flag) return 0;*/
|
||||
|
||||
@ -2026,7 +2017,8 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
||||
return 0; /* not looped */
|
||||
}
|
||||
|
||||
/* build a descriptive string */
|
||||
/* Write a description of the stream into array pointed by desc, which must be length bytes long.
|
||||
* Will always be null-terminated if length > 0 */
|
||||
void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
#define TEMPSIZE 256
|
||||
char temp[TEMPSIZE];
|
||||
@ -2111,8 +2103,7 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
|
||||
concatn(length,desc,temp);
|
||||
|
||||
if (vgmstream->layout_type == layout_interleave
|
||||
|| vgmstream->layout_type == layout_interleave_shortblock
|
||||
|| vgmstream->layout_type == layout_interleave_byte) {
|
||||
|| vgmstream->layout_type == layout_interleave_shortblock) {
|
||||
snprintf(temp,TEMPSIZE,
|
||||
"interleave: %#x bytes\n",
|
||||
(int32_t)vgmstream->interleave_block_size);
|
||||
@ -2337,67 +2328,45 @@ fail:
|
||||
return;
|
||||
}
|
||||
|
||||
static int get_vgmstream_channel_count(VGMSTREAM * vgmstream)
|
||||
/* average bitrate helper */
|
||||
static int get_vgmstream_average_bitrate_channel_count(VGMSTREAM * vgmstream)
|
||||
{
|
||||
//AAX, AIX, ACM?
|
||||
|
||||
if (vgmstream->layout_type==layout_scd_int) {
|
||||
scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data;
|
||||
if (data) {
|
||||
return data->substream_count;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return (data) ? data->substream_count : 0;
|
||||
}
|
||||
#ifdef VGM_USE_VORBIS
|
||||
if (vgmstream->coding_type==coding_ogg_vorbis) {
|
||||
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return (data) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
if (vgmstream->coding_type==coding_CRI_HCA) {
|
||||
hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return (data) ? 1 : 0;
|
||||
}
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
if (vgmstream->coding_type==coding_FFmpeg) {
|
||||
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
|
||||
|
||||
if (data) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return (data) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
if (vgmstream->coding_type==coding_MP4_AAC) {
|
||||
mp4_aac_codec_data *data = (mp4_aac_codec_data *) vgmstream->codec_data;
|
||||
if (data) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
return (data) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
return vgmstream->channels;
|
||||
}
|
||||
|
||||
static STREAMFILE * get_vgmstream_streamfile(VGMSTREAM * vgmstream, int channel)
|
||||
/* average bitrate helper */
|
||||
static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * vgmstream, int channel)
|
||||
{
|
||||
//AAX, AIX, ACM?
|
||||
|
||||
if (vgmstream->layout_type==layout_scd_int) {
|
||||
scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data;
|
||||
return data->intfiles[channel];
|
||||
@ -2405,19 +2374,16 @@ static STREAMFILE * get_vgmstream_streamfile(VGMSTREAM * vgmstream, int channel)
|
||||
#ifdef VGM_USE_VORBIS
|
||||
if (vgmstream->coding_type==coding_ogg_vorbis) {
|
||||
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data;
|
||||
|
||||
return data->ov_streamfile.streamfile;
|
||||
}
|
||||
#endif
|
||||
if (vgmstream->coding_type==coding_CRI_HCA) {
|
||||
hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data;
|
||||
|
||||
return data->streamfile;
|
||||
}
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
if (vgmstream->coding_type==coding_FFmpeg) {
|
||||
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
|
||||
|
||||
return data->streamfile;
|
||||
}
|
||||
#endif
|
||||
@ -2430,42 +2396,41 @@ static STREAMFILE * get_vgmstream_streamfile(VGMSTREAM * vgmstream, int channel)
|
||||
return vgmstream->ch[channel].streamfile;
|
||||
}
|
||||
|
||||
static int get_vgmstream_channel_average_bitrate(STREAMFILE * streamfile, int sample_rate, int length_samples)
|
||||
{
|
||||
static int get_vgmstream_average_bitrate_from_streamfile(STREAMFILE * streamfile, int sample_rate, int length_samples) {
|
||||
// todo: not correct in subsongs or formats which only use part of the data
|
||||
return (int)((int64_t)get_streamfile_size(streamfile) * 8 * sample_rate / length_samples);
|
||||
}
|
||||
|
||||
int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream)
|
||||
{
|
||||
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
||||
int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
|
||||
char path_current[PATH_LIMIT];
|
||||
char path_compare[PATH_LIMIT];
|
||||
|
||||
|
||||
unsigned int i, j;
|
||||
int bitrate = 0;
|
||||
int sample_rate = vgmstream->sample_rate;
|
||||
int length_samples = vgmstream->num_samples;
|
||||
int channels = get_vgmstream_channel_count(vgmstream);
|
||||
int channels = get_vgmstream_average_bitrate_channel_count(vgmstream);
|
||||
STREAMFILE * streamFile;
|
||||
|
||||
if (!sample_rate || !channels || !length_samples)
|
||||
return 0;
|
||||
|
||||
|
||||
if (channels >= 1) {
|
||||
streamFile = get_vgmstream_streamfile(vgmstream, 0);
|
||||
streamFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, 0);
|
||||
if (streamFile) {
|
||||
bitrate += get_vgmstream_channel_average_bitrate(streamFile, sample_rate, length_samples);
|
||||
bitrate += get_vgmstream_average_bitrate_from_streamfile(streamFile, sample_rate, length_samples);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < channels; ++i)
|
||||
{
|
||||
streamFile = get_vgmstream_streamfile(vgmstream, i);
|
||||
/* Compares files by absolute paths, so bitrate doesn't multiply when the same STREAMFILE is reopened per channel */
|
||||
for (i = 1; i < channels; ++i) {
|
||||
streamFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, i);
|
||||
if (!streamFile)
|
||||
continue;
|
||||
streamFile->get_name(streamFile, path_current, sizeof(path_current));
|
||||
for (j = 0; j < i; ++j)
|
||||
{
|
||||
STREAMFILE * compareFile = get_vgmstream_streamfile(vgmstream, j);
|
||||
for (j = 0; j < i; ++j) {
|
||||
STREAMFILE * compareFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, j);
|
||||
if (!compareFile)
|
||||
continue;
|
||||
streamFile->get_name(compareFile, path_compare, sizeof(path_compare));
|
||||
@ -2473,9 +2438,9 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream)
|
||||
break;
|
||||
}
|
||||
if (j == i)
|
||||
bitrate += get_vgmstream_channel_average_bitrate(streamFile, sample_rate, length_samples);
|
||||
bitrate += get_vgmstream_average_bitrate_from_streamfile(streamFile, sample_rate, length_samples);
|
||||
}
|
||||
|
||||
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
@ -2494,8 +2459,10 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
|
||||
int use_same_offset_per_channel = 0;
|
||||
|
||||
|
||||
/* stream/offsets not needed, scd manages itself */
|
||||
if (vgmstream->layout_type == layout_scd_int)
|
||||
/* stream/offsets not needed, manages themselves */
|
||||
if (vgmstream->layout_type == layout_aix ||
|
||||
vgmstream->layout_type == layout_aax ||
|
||||
vgmstream->layout_type == layout_scd_int)
|
||||
return 1;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
@ -98,6 +98,7 @@ typedef enum {
|
||||
coding_CRI_ADX_enc_9, /* CRI ADX, type 9 encryption (PSO2) */
|
||||
|
||||
coding_NGC_DSP, /* Nintendo DSP ADPCM */
|
||||
coding_NGC_DSP_subint, /* Nintendo DSP ADPCM with frame subinterframe */
|
||||
coding_NGC_DTK, /* Nintendo DTK ADPCM (hardware disc), also called TRK or ADP */
|
||||
coding_NGC_AFC, /* Nintendo AFC ADPCM */
|
||||
|
||||
@ -208,7 +209,6 @@ typedef enum {
|
||||
/* interleave */
|
||||
layout_interleave, /* equal interleave throughout the stream */
|
||||
layout_interleave_shortblock, /* interleave with a short last block */
|
||||
layout_interleave_byte, /* full byte interleave */
|
||||
|
||||
/* headered blocks */
|
||||
layout_ast_blocked,
|
||||
@ -242,6 +242,7 @@ typedef enum {
|
||||
layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
||||
layout_blocked_awc, /* Rockstar AWC */
|
||||
layout_blocked_vgs, /* Guitar Hero II (PS2) */
|
||||
layout_blocked_vawx, /* No More Heroes 6ch (PS3) */
|
||||
|
||||
/* otherwise odd */
|
||||
layout_acm, /* libacm layout */
|
||||
@ -730,9 +731,8 @@ typedef struct {
|
||||
int32_t loop_end_sample; /* last sample of the loop (not included in the loop) */
|
||||
|
||||
/* layouts/block */
|
||||
size_t interleave_block_size; /* interleave for this file */
|
||||
size_t interleave_block_size; /* interleave, or block/frame size (depending on the codec) */
|
||||
size_t interleave_smallblock_size; /* smaller interleave for last block */
|
||||
size_t full_block_size; /* fixed data size, from header (may include padding and other unusable data) */
|
||||
|
||||
/* channel state */
|
||||
VGMSTREAMCHANNEL * ch; /* pointer to array of channels */
|
||||
@ -740,6 +740,7 @@ typedef struct {
|
||||
VGMSTREAMCHANNEL * loop_ch; /* copies of channel status as they were at the loop point */
|
||||
|
||||
/* layout/block state */
|
||||
size_t full_block_size; /* actual data size of an entire block (ie. may be fixed, include padding/headers, etc) */
|
||||
int32_t current_sample; /* number of samples we've passed */
|
||||
int32_t samples_into_block; /* number of samples into the current block */
|
||||
off_t current_block_offset; /* start of this block (offset of block header) */
|
||||
@ -771,8 +772,6 @@ typedef struct {
|
||||
|
||||
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
||||
|
||||
int32_t thpNextFrameSize; /* THP */
|
||||
|
||||
void * start_vgmstream; /* a copy of the VGMSTREAM as it was at the beginning of the stream (for AAX/AIX/SCD) */
|
||||
|
||||
/* Data the codec needs for the whole stream. This is for codecs too
|
||||
@ -1155,6 +1154,45 @@ typedef struct {
|
||||
} ea_mt_codec_data;
|
||||
|
||||
|
||||
#if 0
|
||||
//possible future public/opaque API
|
||||
|
||||
/* define standard C param call and name mangling (to avoid __stdcall / .defs) */
|
||||
#define VGMSTREAM_CALL __cdecl //needed?
|
||||
|
||||
/* define external function types (during compilation) */
|
||||
#if defined(VGMSTREAM_EXPORT)
|
||||
#define VGMSTREAM_API __declspec(dllexport) /* when exporting/creating vgmstream DLL */
|
||||
#elif defined(VGMSTREAM_IMPORT)
|
||||
#define VGMSTREAM_API __declspec(dllimport) /* when importing/linking vgmstream DLL */
|
||||
#else
|
||||
#define VGMSTREAM_API /* nothing, internal/default */
|
||||
#endif
|
||||
|
||||
//VGMSTREAM_API void VGMSTREAM_CALL vgmstream_function(void);
|
||||
|
||||
//info for opaque VGMSTREAM
|
||||
typedef struct {
|
||||
int channels;
|
||||
int sample_rate;
|
||||
int num_samples;
|
||||
int loop_start_sample;
|
||||
int loop_end_sample;
|
||||
int loop_flag;
|
||||
int num_streams;
|
||||
int current_sample;
|
||||
int average_bitrate;
|
||||
} VGMSTREAM_INFO;
|
||||
void vgmstream_get_info(VGMSTREAM* vgmstream, VGMSTREAM_INFO *vgmstream_info);
|
||||
|
||||
//or maybe
|
||||
enum vgmstream_value_t { VGMSTREAM_CHANNELS, VGMSTREAM_CURRENT_SAMPLE, ... };
|
||||
int vgmstream_get_info(VGMSTREAM* vgmstream, vgmstream_value_t type);
|
||||
// or
|
||||
int vgmstream_get_current_sample(VGMSTREAM* vgmstream);
|
||||
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
/* vgmstream "public" API */
|
||||
/* -------------------------------------------------------------------------*/
|
||||
@ -1174,48 +1212,46 @@ void close_vgmstream(VGMSTREAM * vgmstream);
|
||||
/* calculate the number of samples to be played based on looping parameters */
|
||||
int32_t get_vgmstream_play_samples(double looptimes, double fadeseconds, double fadedelayseconds, VGMSTREAM * vgmstream);
|
||||
|
||||
/* render! */
|
||||
/* Decode data into sample buffer */
|
||||
void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
/* Write a description of the stream into array pointed by desc,
|
||||
* which must be length bytes long. Will always be null-terminated if length > 0 */
|
||||
/* Write a description of the stream into array pointed by desc, which must be length bytes long.
|
||||
* Will always be null-terminated if length > 0 */
|
||||
void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length);
|
||||
|
||||
/* Return the average bitrate in bps of all unique files contained within this
|
||||
* stream. Compares files by absolute paths. */
|
||||
/* Return the average bitrate in bps of all unique files contained within this stream. */
|
||||
int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream);
|
||||
|
||||
/* List of supported formats and elements in the list, for plugins that need to know. */
|
||||
/* List supported formats and return elements in the list, for plugins that need to know. */
|
||||
const char ** vgmstream_get_formats(size_t * size);
|
||||
|
||||
/* Force enable/disable internal looping. Should be done before playing anything,
|
||||
* and not all codecs support arbitrary loop values ATM. */
|
||||
void vgmstream_force_loop(VGMSTREAM* vgmstream, int loop_flag, int loop_start_sample, int loop_end_sample);
|
||||
|
||||
/* -------------------------------------------------------------------------*/
|
||||
/* vgmstream "private" API */
|
||||
/* -------------------------------------------------------------------------*/
|
||||
|
||||
/* allocate a VGMSTREAM and channel stuff */
|
||||
/* Allocate memory and setup a VGMSTREAM */
|
||||
VGMSTREAM * allocate_vgmstream(int channel_count, int looped);
|
||||
|
||||
/* smallest self-contained group of samples is a frame */
|
||||
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
|
||||
int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream);
|
||||
/* number of bytes per frame */
|
||||
/* Get the number of bytes of a single frame (smallest self-contained byte group, 1/N channels) */
|
||||
int get_vgmstream_frame_size(VGMSTREAM * vgmstream);
|
||||
/* in NDS IMA the frame size is the block size, so the last one is short */
|
||||
/* In NDS IMA the frame size is the block size, so the last one is short */
|
||||
int get_vgmstream_samples_per_shortframe(VGMSTREAM * vgmstream);
|
||||
int get_vgmstream_shortframe_size(VGMSTREAM * vgmstream);
|
||||
|
||||
/* Assume that we have written samples_written into the buffer already, and we have samples_to_do consecutive
|
||||
* samples ahead of us. Decode those samples into the buffer. */
|
||||
/* Decode samples into the buffer. Assume that we have written samples_written into the
|
||||
* buffer already, and we have samples_to_do consecutive samples ahead of us. */
|
||||
void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer);
|
||||
|
||||
/* Assume additionally that we have samples_to_do consecutive samples in "data",
|
||||
* and this this is for channel number "channel" */
|
||||
void decode_vgmstream_mem(VGMSTREAM * vgmstream, int samples_written, int samples_to_do, sample * buffer, uint8_t * data, int channel);
|
||||
|
||||
/* calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
|
||||
/* Calculate number of consecutive samples to do (taking into account stopping for loop start and end) */
|
||||
int vgmstream_samples_to_do(int samples_this_block, int samples_per_frame, VGMSTREAM * vgmstream);
|
||||
|
||||
/* Detect start and save values, also detect end and restore values. Only works on exact sample values.
|
||||
* Returns 1 if loop was done. */
|
||||
/* Detect loop start and save values, or detect loop end and restore (loop back). Returns 1 if loop was done. */
|
||||
int vgmstream_do_loop(VGMSTREAM * vgmstream);
|
||||
|
||||
/* Open the stream for reading at offset (standarized taking into account layouts, channels and so on).
|
||||
|
37
test/test.c
37
test/test.c
@ -208,26 +208,16 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
/* force only if there aren't already loop points */
|
||||
if (force_loop && !vgmstream->loop_flag) {
|
||||
/* this requires a bit more messing with the VGMSTREAM than I'm comfortable with... */
|
||||
vgmstream->loop_flag=1;
|
||||
vgmstream->loop_start_sample=0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
vgmstream->loop_ch=calloc(vgmstream->channels,sizeof(VGMSTREAMCHANNEL));
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
|
||||
/* force even if there are loop points */
|
||||
if (really_force_loop) {
|
||||
if (!vgmstream->loop_flag)
|
||||
vgmstream->loop_ch=calloc(vgmstream->channels,sizeof(VGMSTREAMCHANNEL));
|
||||
vgmstream->loop_flag=1;
|
||||
vgmstream->loop_start_sample=0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
|
||||
if (ignore_loop) {
|
||||
vgmstream->loop_flag=0;
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
if (play_sdtout) {
|
||||
@ -379,7 +369,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
if (write_lwav && vgmstream->loop_flag) { // Writing smpl chuck
|
||||
/* Writing "smpl" chunck at the end */
|
||||
if (write_lwav && vgmstream->loop_flag) {
|
||||
make_smpl_chunk((uint8_t*)buf, vgmstream->loop_start_sample, vgmstream->loop_end_sample);
|
||||
fwrite(buf,1,0x44,outfile);
|
||||
}
|
||||
@ -426,26 +417,16 @@ int main(int argc, char ** argv) {
|
||||
|
||||
/* these manipulations are undone by reset */
|
||||
|
||||
/* force only if there aren't already loop points */
|
||||
if (force_loop && !vgmstream->loop_flag) {
|
||||
/* this requires a bit more messing with the VGMSTREAM than I'm comfortable with... */
|
||||
vgmstream->loop_flag=1;
|
||||
vgmstream->loop_start_sample=0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
vgmstream->loop_ch=calloc(vgmstream->channels,sizeof(VGMSTREAMCHANNEL));
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
|
||||
/* force even if there are loop points */
|
||||
if (really_force_loop) {
|
||||
if (!vgmstream->loop_flag)
|
||||
vgmstream->loop_ch=calloc(vgmstream->channels,sizeof(VGMSTREAMCHANNEL));
|
||||
vgmstream->loop_flag=1;
|
||||
vgmstream->loop_start_sample=0;
|
||||
vgmstream->loop_end_sample=vgmstream->num_samples;
|
||||
vgmstream_force_loop(vgmstream, 1, 0,vgmstream->num_samples);
|
||||
}
|
||||
|
||||
if (ignore_loop) {
|
||||
vgmstream->loop_flag=0;
|
||||
vgmstream_force_loop(vgmstream, 0, 0,0);
|
||||
}
|
||||
|
||||
/* decode */
|
||||
@ -521,7 +502,7 @@ static void make_wav_header(uint8_t * buf, int32_t sample_count, int32_t sample_
|
||||
}
|
||||
|
||||
static void make_smpl_chunk(uint8_t * buf, int32_t loop_start, int32_t loop_end) {
|
||||
int i;
|
||||
int i;
|
||||
|
||||
memcpy(buf+0, "smpl", 4);/* header */
|
||||
put_32bitLE(buf+4, 0x3c);/* size */
|
||||
|
Loading…
x
Reference in New Issue
Block a user