mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Clean streamfile code
This commit is contained in:
parent
86b252c7d5
commit
1ac69f90d4
@ -281,7 +281,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\fsb5_interleave_streamfile.h"
|
||||
RelativePath=".\meta\fsb5_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -365,7 +365,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ubi_lyn_ogg_streamfile.h"
|
||||
RelativePath=".\meta\ubi_lyn_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -112,7 +112,7 @@
|
||||
<ClInclude Include="meta\ea_eaac_opus_streamfile.h" />
|
||||
<ClInclude Include="meta\ea_schl_streamfile.h" />
|
||||
<ClInclude Include="meta\fsb_interleave_streamfile.h" />
|
||||
<ClInclude Include="meta\fsb5_interleave_streamfile.h" />
|
||||
<ClInclude Include="meta\fsb5_streamfile.h" />
|
||||
<ClInclude Include="meta\jstm_streamfile.h" />
|
||||
<ClInclude Include="meta\kma9_streamfile.h" />
|
||||
<ClInclude Include="meta\lrmd_streamfile.h" />
|
||||
@ -133,7 +133,7 @@
|
||||
<ClInclude Include="meta\txth_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_bao_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_sb_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h" />
|
||||
<ClInclude Include="meta\ubi_lyn_streamfile.h" />
|
||||
<ClInclude Include="meta\meta.h" />
|
||||
<ClInclude Include="meta\hca_keys.h" />
|
||||
<ClInclude Include="meta\hca_keys_awb.h" />
|
||||
|
@ -107,7 +107,7 @@
|
||||
<ClInclude Include="meta\fsb_interleave_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\fsb5_interleave_streamfile.h">
|
||||
<ClInclude Include="meta\fsb5_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\jstm_streamfile.h">
|
||||
@ -170,7 +170,7 @@
|
||||
<ClInclude Include="meta\ubi_sb_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\ubi_lyn_ogg_streamfile.h">
|
||||
<ClInclude Include="meta\ubi_lyn_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\meta.h">
|
||||
|
@ -1,245 +1,114 @@
|
||||
#ifndef _AWC_XMA_STREAMFILE_H_
|
||||
#define _AWC_XMA_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
int channel;
|
||||
int channel_count;
|
||||
size_t block_size;
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
|
||||
size_t skip_size; /* size to skip from a block start to reach data start */
|
||||
size_t data_size; /* logical size of the block */
|
||||
|
||||
size_t logical_size;
|
||||
} awc_xma_io_data;
|
||||
|
||||
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data);
|
||||
static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t next_offset, size_t repeat_samples);
|
||||
static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel);
|
||||
|
||||
/* Reads plain XMA data of a single stream. Each block has a header and channels have different num_samples/frames.
|
||||
* Channel data is separate within the block (first all frames of ch0, then ch1, etc), padded, and sometimes
|
||||
* the last few frames of a channel are repeated in the new block (marked with the "discard samples" field). */
|
||||
static size_t awc_xma_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, awc_xma_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
size_t frame_size = 0x800;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->logical_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->logical_offset = 0x00;
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->data_size = 0;
|
||||
}
|
||||
|
||||
/* read blocks, one at a time */
|
||||
while (length > 0) {
|
||||
|
||||
/* ignore EOF */
|
||||
if (data->logical_offset >= data->logical_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
size_t header_size = get_block_header_size(streamfile, data->physical_offset, data);
|
||||
/* header table entries = frames... I hope */
|
||||
size_t others_size = get_block_skip_count(streamfile, data->physical_offset, data->channel) * frame_size;
|
||||
//size_t skip_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
|
||||
size_t data_size = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
|
||||
size_t repeat_samples = read_32bitBE(data->physical_offset + 0x10*data->channel + 0x08, streamfile);
|
||||
size_t repeat_size = 0;
|
||||
|
||||
|
||||
/* if there are repeat samples current block repeats some frames from last block, find out size */
|
||||
if (repeat_samples) {
|
||||
off_t data_offset = data->physical_offset + header_size + others_size;
|
||||
repeat_size = get_repeated_data_size(streamfile, data_offset, repeat_samples);
|
||||
}
|
||||
|
||||
data->skip_size = header_size + others_size + repeat_size;
|
||||
data->data_size = data_size - repeat_size;
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->block_size;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
offset += bytes_done;
|
||||
total_read += bytes_done;
|
||||
length -= bytes_done;
|
||||
dest += bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t awc_xma_io_size(STREAMFILE *streamfile, awc_xma_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
size_t frame_size = 0x800;
|
||||
size_t logical_size = 0;
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
physical_offset = data->stream_offset;
|
||||
max_physical_offset = data->stream_offset + data->stream_size;
|
||||
|
||||
/* get size of the logical stream */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t header_size = get_block_header_size(streamfile, physical_offset, data);
|
||||
/* header table entries = frames... I hope */
|
||||
size_t skip_size = get_block_skip_count(streamfile, physical_offset, data->channel) * frame_size;
|
||||
//size_t skip_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x00, streamfile) * frame_size;
|
||||
size_t data_size = read_32bitBE(physical_offset + 0x10*data->channel + 0x04, streamfile) * frame_size;
|
||||
size_t repeat_samples = read_32bitBE(physical_offset + 0x10*data->channel + 0x08, streamfile);
|
||||
size_t repeat_size = 0;
|
||||
|
||||
/* if there are repeat samples current block repeats some frames from last block, find out size */
|
||||
if (repeat_samples) {
|
||||
off_t data_offset = physical_offset + header_size + skip_size;
|
||||
repeat_size = get_repeated_data_size(streamfile, data_offset, repeat_samples);
|
||||
}
|
||||
|
||||
logical_size += data_size - repeat_size;
|
||||
physical_offset += data->block_size;
|
||||
}
|
||||
|
||||
data->logical_size = logical_size;
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for AWC XMA, which is interleaved XMA in AWC blocks */
|
||||
static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t stream_size, size_t block_size, int channel_count, int channel) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
awc_xma_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(awc_xma_io_data);
|
||||
|
||||
io_data.channel = channel;
|
||||
io_data.channel_count = channel_count;
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = stream_size;
|
||||
io_data.block_size = block_size;
|
||||
io_data.physical_offset = stream_offset;
|
||||
io_data.logical_size = awc_xma_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
if (io_data.logical_size > io_data.stream_size) {
|
||||
VGM_LOG("AWC XMA: wrong logical size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, awc_xma_io_read,awc_xma_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* block header size, aligned/padded to 0x800 */
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, awc_xma_io_data *data) {
|
||||
size_t header_size = 0;
|
||||
int i;
|
||||
int entries = data->channel_count;
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
header_size += 0x10;
|
||||
header_size += read_32bitBE(offset + 0x10*i + 0x04, streamFile) * 0x04; /* entries in the table */
|
||||
}
|
||||
|
||||
if (header_size % 0x800) /* padded */
|
||||
header_size += 0x800 - (header_size % 0x800);
|
||||
|
||||
return header_size;
|
||||
}
|
||||
|
||||
|
||||
/* find data that repeats in the beginning of a new block at the end of last block */
|
||||
static size_t get_repeated_data_size(STREAMFILE *streamFile, off_t next_offset, size_t repeat_samples) {
|
||||
const size_t frame_size = 0x800;
|
||||
const size_t samples_per_subframe = 512;
|
||||
size_t samples_this_frame;
|
||||
uint8_t subframes;
|
||||
|
||||
//todo: fix this
|
||||
/* Repeat samples are the number of decoded samples to discard, but in this streamfile we can't do that.
|
||||
* Also XMA is VBR, and may encode silent frames with up to 63 subframes yet we may have few repeat samples.
|
||||
* We could find out how many subframes of 512 samples to skip, then adjust the XMA frame header, though
|
||||
* output will be slightly off since subframes are related.
|
||||
*
|
||||
* For now just skip a full frame depending on the number of subframes vs repeat samples.
|
||||
* Most files work ok-ish but channels may desync slightly. */
|
||||
|
||||
subframes = ((uint8_t)read_8bit(next_offset,streamFile) >> 2) & 0x3F; /* peek into frame header */
|
||||
samples_this_frame = subframes*samples_per_subframe;
|
||||
if (repeat_samples >= (int)(samples_this_frame*0.13)) { /* skip mosts */
|
||||
return frame_size;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* header has a skip value, but somehow it's sometimes bigger than expected (WHY!?!?) so just sum all */
|
||||
static size_t get_block_skip_count(STREAMFILE *streamFile, off_t offset, int channel) {
|
||||
size_t skip_count = 0;
|
||||
int i;
|
||||
|
||||
//skip_size = read_32bitBE(offset + 0x10*channel + 0x00, streamFile); /* wrong! */
|
||||
for (i = 0; i < channel; i++) {
|
||||
skip_count += read_32bitBE(offset + 0x10*i + 0x04, streamFile); /* number of frames of this channel */
|
||||
}
|
||||
|
||||
return skip_count;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _AWC_XMA_STREAMFILE_H_ */
|
||||
#ifndef _AWC_XMA_STREAMFILE_H_
|
||||
#define _AWC_XMA_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
|
||||
static size_t get_block_header_size(STREAMFILE* sf, off_t offset, int channels);
|
||||
static size_t get_repeated_data_size(STREAMFILE* sf, off_t next_offset, size_t repeat_samples);
|
||||
static size_t get_block_skip_count(STREAMFILE* sf, off_t offset, int channel);
|
||||
|
||||
static void block_callback(STREAMFILE *sf, deblock_io_data* data) {
|
||||
const size_t frame_size = 0x800;
|
||||
int channel = data->cfg.track_number;
|
||||
int channels = data->cfg.track_count;
|
||||
|
||||
/* Blocks have a header then data per channel, each with a different num_samples/frames,
|
||||
* separate (first all frames of ch0, then ch1, etc), padded, and sometimes the last few
|
||||
* frames of a channel are repeated in the new block (marked with "repeat samples"). */
|
||||
size_t header_size = get_block_header_size(sf, data->physical_offset, channels);
|
||||
/* header table entries = frames... I hope */
|
||||
size_t others_size = get_block_skip_count(sf, data->physical_offset, channel) * frame_size;
|
||||
//size_t skip_size = read_u32be(data->physical_offset + 0x10*channel + 0x00, sf) * frame_size;
|
||||
size_t data_size = read_u32be(data->physical_offset + 0x10*channel + 0x04, sf) * frame_size;
|
||||
size_t repeat_samples = read_u32be(data->physical_offset + 0x10*channel + 0x08, sf);
|
||||
size_t repeat_size = 0;
|
||||
|
||||
data->block_size = data->cfg.chunk_size;
|
||||
|
||||
/* if there are repeat samples current block repeats some frames from last block, find out size */
|
||||
if (repeat_samples) {
|
||||
off_t data_offset = data->physical_offset + header_size + others_size;
|
||||
repeat_size = get_repeated_data_size(sf, data_offset, repeat_samples);
|
||||
}
|
||||
|
||||
data->skip_size = header_size + others_size + repeat_size;
|
||||
data->data_size = data_size - repeat_size;
|
||||
}
|
||||
|
||||
/* block header size, aligned/padded to 0x800 */
|
||||
static size_t get_block_header_size(STREAMFILE* sf, off_t offset, int channels) {
|
||||
size_t header_size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
header_size += 0x10;
|
||||
header_size += read_u32be(offset + 0x10*i + 0x04, sf) * 0x04; /* entries in the table */
|
||||
}
|
||||
|
||||
if (header_size % 0x800) /* padded */
|
||||
header_size += 0x800 - (header_size % 0x800);
|
||||
|
||||
return header_size;
|
||||
}
|
||||
|
||||
/* find data that repeats in the beginning of a new block at the end of last block */
|
||||
static size_t get_repeated_data_size(STREAMFILE* sf, off_t next_offset, size_t repeat_samples) {
|
||||
const size_t frame_size = 0x800;
|
||||
const size_t samples_per_subframe = 512;
|
||||
size_t samples_this_frame;
|
||||
uint8_t subframes;
|
||||
|
||||
//todo: fix this
|
||||
/* Repeat samples are the number of decoded samples to discard, but in this streamfile we can't do that.
|
||||
* Also XMA is VBR, and may encode silent frames with up to 63 subframes yet we may have few repeat samples.
|
||||
* We could find out how many subframes of 512 samples to skip, then adjust the XMA frame header, though
|
||||
* output will be slightly off since subframes are related.
|
||||
*
|
||||
* For now just skip a full frame depending on the number of subframes vs repeat samples.
|
||||
* Most files work ok-ish but channels may desync slightly. */
|
||||
|
||||
subframes = ((uint8_t)read_8bit(next_offset,sf) >> 2) & 0x3F; /* peek into frame header */
|
||||
samples_this_frame = subframes*samples_per_subframe;
|
||||
if (repeat_samples >= (int)(samples_this_frame*0.13)) { /* skip mosts */
|
||||
return frame_size;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* header has a skip value, but somehow it's sometimes bigger than expected (WHY!?!?) so just sum all */
|
||||
static size_t get_block_skip_count(STREAMFILE* sf, off_t offset, int channel) {
|
||||
size_t skip_count = 0;
|
||||
int i;
|
||||
|
||||
//skip_size = read_u32be(offset + 0x10*channel + 0x00, sf); /* wrong! */
|
||||
for (i = 0; i < channel; i++) {
|
||||
skip_count += read_u32be(offset + 0x10*i + 0x04, sf); /* number of frames of this channel */
|
||||
}
|
||||
|
||||
return skip_count;
|
||||
}
|
||||
|
||||
|
||||
/* Deblocks interleaved XMA in AWC blocks */
|
||||
static STREAMFILE* setup_awc_xma_streamfile(STREAMFILE *sf, off_t stream_offset, size_t stream_size, size_t block_size, int channel_count, int channel) {
|
||||
STREAMFILE *new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.track_number = channel;
|
||||
cfg.track_count = channel_count;
|
||||
cfg.stream_start = stream_offset;
|
||||
cfg.stream_size = stream_size;
|
||||
cfg.chunk_size = block_size;
|
||||
//cfg.physical_offset = stream_offset;
|
||||
//cfg.logical_size = awc_xma_io_size(sf, &cfg); /* force init */
|
||||
cfg.block_callback = block_callback;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
//new_sf = open_buffer_streamfile_f(new_sf, 0);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _AWC_XMA_STREAMFILE_H_ */
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "fsb5_interleave_streamfile.h"
|
||||
#include "fsb5_streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
@ -533,7 +533,7 @@ static layered_layout_data* build_layered_fsb5_celt(STREAMFILE *streamFile, fsb5
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
temp_streamFile = setup_fsb5_interleave_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, FSB5_INT_CELT, interleave);
|
||||
temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
|
||||
@ -609,7 +609,7 @@ static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE *streamFile, fs
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
temp_streamFile = setup_fsb5_interleave_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, FSB5_INT_ATRAC9, interleave);
|
||||
temp_streamFile = setup_fsb5_streamfile(streamFile, fsb5->stream_offset, fsb5->stream_size, layers, i, interleave);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
if (!vgmstream_open_stream(data->layers[i], temp_streamFile, 0x00))
|
||||
|
@ -1,201 +0,0 @@
|
||||
#ifndef _FSB5_INTERLEAVE_STREAMFILE_H_
|
||||
#define _FSB5_INTERLEAVE_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef enum { FSB5_INT_CELT, FSB5_INT_ATRAC9 } fsb_interleave_codec_t;
|
||||
typedef struct {
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
int skip_frames; /* frames to skip from other streams at points */
|
||||
|
||||
/* config */
|
||||
fsb_interleave_codec_t codec;
|
||||
size_t interleave;
|
||||
int stream_count;
|
||||
int stream_number;
|
||||
size_t stream_size;
|
||||
off_t start_offset; /* pointing to the stream's beginning */
|
||||
size_t total_size; /* size of the resulting substream */
|
||||
} fsb_interleave_io_data;
|
||||
|
||||
|
||||
|
||||
/* Reads skipping other streams */
|
||||
static size_t fsb_interleave_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, fsb_interleave_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->total_size) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets
|
||||
* (kinda slow as it trashes buffers, but shouldn't happen often) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->physical_offset = data->start_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->skip_frames = data->stream_number;
|
||||
}
|
||||
|
||||
/* read doing one frame at a time */
|
||||
while (length > 0) {
|
||||
size_t to_read, bytes_read;
|
||||
off_t intrablock_offset, intradata_offset;
|
||||
uint32_t data_size;
|
||||
|
||||
if (offset >= data->total_size)
|
||||
break;
|
||||
|
||||
/* get current data */
|
||||
switch (data->codec) {
|
||||
case FSB5_INT_CELT:
|
||||
case FSB5_INT_ATRAC9:
|
||||
data_size = data->interleave;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (data->skip_frames) {
|
||||
data->physical_offset += data_size;
|
||||
data->skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* requested offset is outside current block, try next */
|
||||
if (offset >= data->logical_offset + data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* reads could fall in the middle of the block */
|
||||
intradata_offset = offset - data->logical_offset;
|
||||
intrablock_offset = intradata_offset;
|
||||
|
||||
/* clamp reads up to this block's end */
|
||||
to_read = (data_size - intradata_offset);
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
if (to_read == 0)
|
||||
break; /* should never happen... */
|
||||
|
||||
/* finally read and move buffer/offsets */
|
||||
bytes_read = read_streamfile(dest, data->physical_offset + intrablock_offset, to_read, streamfile);
|
||||
total_read += bytes_read;
|
||||
if (bytes_read != to_read)
|
||||
break; /* couldn't read fully */
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
|
||||
/* block fully read, go next */
|
||||
if (intradata_offset + bytes_read == data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->stream_count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t fsb_interleave_io_size(STREAMFILE *streamfile, fsb_interleave_io_data* data) {
|
||||
off_t physical_offset, max_physical_offset;
|
||||
size_t total_size = 0;
|
||||
int skip_frames = 0;
|
||||
|
||||
if (data->total_size)
|
||||
return data->total_size;
|
||||
|
||||
physical_offset = data->start_offset;
|
||||
max_physical_offset = physical_offset + data->stream_size;
|
||||
skip_frames = data->stream_number;
|
||||
|
||||
/* get size of the underlying stream, skipping other streams
|
||||
* (all streams should have the same frame count) */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
size_t data_size;
|
||||
|
||||
data_size = data->interleave;
|
||||
switch(data->codec) {
|
||||
case FSB5_INT_CELT:
|
||||
case FSB5_INT_ATRAC9:
|
||||
data_size = data->interleave;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* there may be padding at the end, so this doubles as EOF marker */
|
||||
if (data_size == 0)
|
||||
break;
|
||||
if (physical_offset+data_size > max_physical_offset)
|
||||
break;
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (skip_frames) {
|
||||
physical_offset += data_size;
|
||||
skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
physical_offset += data_size;
|
||||
total_size += data_size;
|
||||
skip_frames = data->stream_count - 1;
|
||||
}
|
||||
|
||||
data->total_size = total_size;
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for multistreams, interleaves 1 packet per stream */
|
||||
static STREAMFILE* setup_fsb5_interleave_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t stream_size, int stream_count, int stream_number, fsb_interleave_codec_t codec, size_t interleave) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
fsb_interleave_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(fsb_interleave_io_data);
|
||||
|
||||
io_data.start_offset = start_offset;
|
||||
io_data.physical_offset = start_offset;
|
||||
io_data.skip_frames = stream_number; /* adjust since start_offset points to the first */
|
||||
io_data.codec = codec;
|
||||
io_data.interleave = interleave;
|
||||
io_data.stream_count = stream_count;
|
||||
io_data.stream_number = stream_number;
|
||||
io_data.stream_size = stream_size; /* full size for all streams */
|
||||
|
||||
io_data.total_size = fsb_interleave_io_size(streamFile, &io_data); /* force init, size of a single stream */
|
||||
|
||||
if (io_data.total_size == 0 || io_data.total_size > io_data.stream_size) {
|
||||
VGM_LOG("FSB5 INTERLEAVE: wrong total_size %x vs %x\n", io_data.total_size,io_data.stream_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, fsb_interleave_io_read,fsb_interleave_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _FSB_INTERLEAVE_STREAMFILE_H_ */
|
21
src/meta/fsb5_streamfile.h
Normal file
21
src/meta/fsb5_streamfile.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef _FSB5_STREAMFILE_H_
|
||||
#define _FSB5_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_fsb5_streamfile(STREAMFILE* sf, off_t stream_start, size_t stream_size, int stream_count, int stream_number, size_t interleave) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = stream_start;
|
||||
cfg.stream_size = stream_size;
|
||||
cfg.chunk_size = interleave;
|
||||
cfg.step_start = stream_number;
|
||||
cfg.step_count = stream_count;
|
||||
|
||||
/* setup sf */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _FSB5_STREAMFILE_H_ */
|
@ -172,7 +172,7 @@ VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) {
|
||||
/* 0x30+: extra chunks (0x00: 0x7f, 0x04: num_sample), alt loop starts/regions? */
|
||||
|
||||
if (channel_count == 6) {
|
||||
/* 2ch multistream hacky-hacks, don't try this at home. We'll end up with:
|
||||
/* 2ch multistream hacky-hacks in RE:RE, don't try this at home. We'll end up with:
|
||||
* main vgmstream > N vgmstream layers > substream IO deinterleaver > opus meta > Opus IO transmogrifier (phew) */
|
||||
layered_layout_data* data = NULL;
|
||||
int layers = channel_count / 2;
|
||||
@ -193,11 +193,11 @@ VGMSTREAM * init_vgmstream_opus_capcom(STREAMFILE *streamFile) {
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < layers; i++) {
|
||||
STREAMFILE* temp_streamFile = setup_opus_interleave_streamfile(streamFile, offset+0x28*i, layers);
|
||||
if (!temp_streamFile) goto fail;
|
||||
STREAMFILE* temp_sf = setup_opus_interleave_streamfile(streamFile, offset, i, layers);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
data->layers[i] = init_vgmstream_opus(temp_streamFile, meta_OPUS, 0x00, num_samples,loop_start,loop_end);
|
||||
close_streamfile(temp_streamFile);
|
||||
data->layers[i] = init_vgmstream_opus(temp_sf, meta_OPUS, 0x00, num_samples,loop_start,loop_end);
|
||||
close_streamfile(temp_sf);
|
||||
if (!data->layers[i]) goto fail;
|
||||
}
|
||||
|
||||
|
@ -1,136 +1,47 @@
|
||||
#ifndef _OPUS_INTERLEAVE_STREAMFILE_H_
|
||||
#define _OPUS_INTERLEAVE_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
int streams;
|
||||
off_t stream_offset;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* offset that corresponds to physical_offset */
|
||||
off_t physical_offset; /* actual file offset */
|
||||
int skip_frames; /* frames to skip from other streams at points */
|
||||
|
||||
size_t logical_size;
|
||||
} opus_interleave_io_data;
|
||||
|
||||
|
||||
/* Reads skipping other streams */
|
||||
static size_t opus_interleave_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, opus_interleave_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
/* ignore bad reads */
|
||||
if (offset < 0 || offset > data->logical_size) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
/* previous offset: re-start as we can't map logical<>physical offsets (may be VBR) */
|
||||
if (offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->skip_frames = 0;
|
||||
}
|
||||
|
||||
/* read doing one frame at a time */
|
||||
while (length > 0) {
|
||||
size_t data_size;
|
||||
|
||||
/* ignore EOF */
|
||||
if (data->logical_offset >= data->logical_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process block (must be read every time since skip frame sizes may vary) */
|
||||
{
|
||||
data_size = read_32bitBE(data->physical_offset,streamfile);
|
||||
if ((uint32_t)data_size == 0x01000080) //todo not ok if offset between 0 and header_size
|
||||
data_size = read_32bitLE(data->physical_offset+0x10,streamfile) + 0x08;
|
||||
else
|
||||
data_size += 0x08;
|
||||
}
|
||||
|
||||
/* skip frames from other streams */
|
||||
if (data->skip_frames) {
|
||||
data->physical_offset += data_size;
|
||||
data->skip_frames--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (offset >= data->logical_offset + data_size) {
|
||||
data->physical_offset += data_size;
|
||||
data->logical_offset += data_size;
|
||||
data->skip_frames = data->streams - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
to_read = data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + bytes_consumed, to_read, streamfile);
|
||||
|
||||
offset += bytes_done;
|
||||
total_read += bytes_done;
|
||||
length -= bytes_done;
|
||||
dest += bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t opus_interleave_io_size(STREAMFILE *streamfile, opus_interleave_io_data* data) {
|
||||
off_t info_offset;
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
info_offset = read_32bitLE(data->stream_offset+0x10,streamfile);
|
||||
data->logical_size = (0x08+info_offset) + read_32bitLE(data->stream_offset+info_offset+0x04,streamfile);
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
|
||||
/* Prepares custom IO for multistream, interleaves 1 packet per stream */
|
||||
static STREAMFILE* setup_opus_interleave_streamfile(STREAMFILE *streamFile, off_t start_offset, int streams) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
opus_interleave_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(opus_interleave_io_data);
|
||||
|
||||
io_data.stream_offset = start_offset;
|
||||
io_data.streams = streams;
|
||||
io_data.physical_offset = start_offset;
|
||||
io_data.logical_size = opus_interleave_io_size(streamFile, &io_data); /* force init */
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, opus_interleave_io_read,opus_interleave_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _OPUS_INTERLEAVE_STREAMFILE_H_ */
|
||||
#ifndef _OPUS_INTERLEAVE_STREAMFILE_H_
|
||||
#define _OPUS_INTERLEAVE_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
|
||||
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
|
||||
uint32_t chunk_size = read_u32be(data->physical_offset, sf);
|
||||
|
||||
//todo not ok if offset between 0 and header_size
|
||||
if (chunk_size == 0x01000080) /* header */
|
||||
chunk_size = read_u32le(data->physical_offset + 0x10, sf) + 0x08;
|
||||
else
|
||||
chunk_size += 0x08;
|
||||
data->block_size = chunk_size;
|
||||
data->data_size = data->block_size;
|
||||
}
|
||||
|
||||
/* Deblocks NXOPUS streams that interleave 1 packet per stream */
|
||||
static STREAMFILE* setup_opus_interleave_streamfile(STREAMFILE* sf, off_t start_offset, int stream_number, int stream_count) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = start_offset;
|
||||
cfg.step_start = stream_number;
|
||||
cfg.step_count = stream_count;
|
||||
{
|
||||
int i;
|
||||
off_t offset = start_offset;
|
||||
/* read full size from NXOPUS header N */
|
||||
for (i = 0; i < stream_number + 1; i++) {
|
||||
off_t start = read_s32le(offset + 0x10, sf);
|
||||
off_t size = read_s32le(offset + start + 0x04, sf);
|
||||
|
||||
if (i == stream_number)
|
||||
cfg.logical_size = 0x08 + start + size;
|
||||
offset += 0x08 + start;
|
||||
}
|
||||
}
|
||||
cfg.block_callback = block_callback;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
//new_sf = open_buffer_streamfile_f(new_sf, 0);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _OPUS_INTERLEAVE_STREAMFILE_H_ */
|
||||
|
@ -1,86 +1,67 @@
|
||||
#ifndef _SQEX_SEAD_STREAMFILE_H_
|
||||
#define _SQEX_SEAD_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_sqex_sead_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, int encryption, size_t header_size, size_t key_start);
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t header_size;
|
||||
size_t key_start;
|
||||
} sqex_sead_decryption_data;
|
||||
|
||||
|
||||
static size_t sqex_sead_decryption_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, sqex_sead_decryption_data* data) {
|
||||
/* Found in FFXII_TZA.exe (same key in SCD Ogg V3) */
|
||||
static const uint8_t encryption_key[0x100] = {
|
||||
0x3A,0x32,0x32,0x32,0x03,0x7E,0x12,0xF7,0xB2,0xE2,0xA2,0x67,0x32,0x32,0x22,0x32, // 00-0F
|
||||
0x32,0x52,0x16,0x1B,0x3C,0xA1,0x54,0x7B,0x1B,0x97,0xA6,0x93,0x1A,0x4B,0xAA,0xA6, // 10-1F
|
||||
0x7A,0x7B,0x1B,0x97,0xA6,0xF7,0x02,0xBB,0xAA,0xA6,0xBB,0xF7,0x2A,0x51,0xBE,0x03, // 20-2F
|
||||
0xF4,0x2A,0x51,0xBE,0x03,0xF4,0x2A,0x51,0xBE,0x12,0x06,0x56,0x27,0x32,0x32,0x36, // 30-3F
|
||||
0x32,0xB2,0x1A,0x3B,0xBC,0x91,0xD4,0x7B,0x58,0xFC,0x0B,0x55,0x2A,0x15,0xBC,0x40, // 40-4F
|
||||
0x92,0x0B,0x5B,0x7C,0x0A,0x95,0x12,0x35,0xB8,0x63,0xD2,0x0B,0x3B,0xF0,0xC7,0x14, // 50-5F
|
||||
0x51,0x5C,0x94,0x86,0x94,0x59,0x5C,0xFC,0x1B,0x17,0x3A,0x3F,0x6B,0x37,0x32,0x32, // 60-6F
|
||||
0x30,0x32,0x72,0x7A,0x13,0xB7,0x26,0x60,0x7A,0x13,0xB7,0x26,0x50,0xBA,0x13,0xB4, // 70-7F
|
||||
0x2A,0x50,0xBA,0x13,0xB5,0x2E,0x40,0xFA,0x13,0x95,0xAE,0x40,0x38,0x18,0x9A,0x92, // 80-8F
|
||||
0xB0,0x38,0x00,0xFA,0x12,0xB1,0x7E,0x00,0xDB,0x96,0xA1,0x7C,0x08,0xDB,0x9A,0x91, // 90-9F
|
||||
0xBC,0x08,0xD8,0x1A,0x86,0xE2,0x70,0x39,0x1F,0x86,0xE0,0x78,0x7E,0x03,0xE7,0x64, // A0-AF
|
||||
0x51,0x9C,0x8F,0x34,0x6F,0x4E,0x41,0xFC,0x0B,0xD5,0xAE,0x41,0xFC,0x0B,0xD5,0xAE, // B0-BF
|
||||
0x41,0xFC,0x3B,0x70,0x71,0x64,0x33,0x32,0x12,0x32,0x32,0x36,0x70,0x34,0x2B,0x56, // C0-CF
|
||||
0x22,0x70,0x3A,0x13,0xB7,0x26,0x60,0xBA,0x1B,0x94,0xAA,0x40,0x38,0x00,0xFA,0xB2, // D0-DF
|
||||
0xE2,0xA2,0x67,0x32,0x32,0x12,0x32,0xB2,0x32,0x32,0x32,0x32,0x75,0xA3,0x26,0x7B, // E0-EF
|
||||
0x83,0x26,0xF9,0x83,0x2E,0xFF,0xE3,0x16,0x7D,0xC0,0x1E,0x63,0x21,0x07,0xE3,0x01, // F0-FF
|
||||
};
|
||||
size_t bytes_read;
|
||||
off_t encrypted_offset = data->header_size;
|
||||
int i;
|
||||
|
||||
bytes_read = streamfile->read(streamfile, dest, offset, length);
|
||||
|
||||
/* decrypt data (xor) */
|
||||
if (offset >= encrypted_offset) {
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
dest[i] ^= encryption_key[(data->key_start + (offset - encrypted_offset) + i) % 0x100];
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
/* decrypts subfile if neccessary */
|
||||
static STREAMFILE* setup_sqex_sead_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, int encryption, size_t header_size, size_t key_start) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
if (encryption) {
|
||||
sqex_sead_decryption_data io_data = {0};
|
||||
size_t io_data_size = sizeof(sqex_sead_decryption_data);
|
||||
|
||||
io_data.header_size = header_size;
|
||||
io_data.key_start = key_start;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, sqex_sead_decryption_read,NULL);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
}
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"hca");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _SQEX_SEAD_STREAMFILE_H_ */
|
||||
#ifndef _SQEX_SEAD_STREAMFILE_H_
|
||||
#define _SQEX_SEAD_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t start;
|
||||
size_t key_start;
|
||||
} sqex_sead_io_data;
|
||||
|
||||
|
||||
static size_t sqex_sead_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, sqex_sead_io_data* data) {
|
||||
/* Found in FFXII_TZA.exe (same key in SCD Ogg V3) */
|
||||
static const uint8_t key[0x100] = {
|
||||
0x3A,0x32,0x32,0x32,0x03,0x7E,0x12,0xF7,0xB2,0xE2,0xA2,0x67,0x32,0x32,0x22,0x32, // 00-0F
|
||||
0x32,0x52,0x16,0x1B,0x3C,0xA1,0x54,0x7B,0x1B,0x97,0xA6,0x93,0x1A,0x4B,0xAA,0xA6, // 10-1F
|
||||
0x7A,0x7B,0x1B,0x97,0xA6,0xF7,0x02,0xBB,0xAA,0xA6,0xBB,0xF7,0x2A,0x51,0xBE,0x03, // 20-2F
|
||||
0xF4,0x2A,0x51,0xBE,0x03,0xF4,0x2A,0x51,0xBE,0x12,0x06,0x56,0x27,0x32,0x32,0x36, // 30-3F
|
||||
0x32,0xB2,0x1A,0x3B,0xBC,0x91,0xD4,0x7B,0x58,0xFC,0x0B,0x55,0x2A,0x15,0xBC,0x40, // 40-4F
|
||||
0x92,0x0B,0x5B,0x7C,0x0A,0x95,0x12,0x35,0xB8,0x63,0xD2,0x0B,0x3B,0xF0,0xC7,0x14, // 50-5F
|
||||
0x51,0x5C,0x94,0x86,0x94,0x59,0x5C,0xFC,0x1B,0x17,0x3A,0x3F,0x6B,0x37,0x32,0x32, // 60-6F
|
||||
0x30,0x32,0x72,0x7A,0x13,0xB7,0x26,0x60,0x7A,0x13,0xB7,0x26,0x50,0xBA,0x13,0xB4, // 70-7F
|
||||
0x2A,0x50,0xBA,0x13,0xB5,0x2E,0x40,0xFA,0x13,0x95,0xAE,0x40,0x38,0x18,0x9A,0x92, // 80-8F
|
||||
0xB0,0x38,0x00,0xFA,0x12,0xB1,0x7E,0x00,0xDB,0x96,0xA1,0x7C,0x08,0xDB,0x9A,0x91, // 90-9F
|
||||
0xBC,0x08,0xD8,0x1A,0x86,0xE2,0x70,0x39,0x1F,0x86,0xE0,0x78,0x7E,0x03,0xE7,0x64, // A0-AF
|
||||
0x51,0x9C,0x8F,0x34,0x6F,0x4E,0x41,0xFC,0x0B,0xD5,0xAE,0x41,0xFC,0x0B,0xD5,0xAE, // B0-BF
|
||||
0x41,0xFC,0x3B,0x70,0x71,0x64,0x33,0x32,0x12,0x32,0x32,0x36,0x70,0x34,0x2B,0x56, // C0-CF
|
||||
0x22,0x70,0x3A,0x13,0xB7,0x26,0x60,0xBA,0x1B,0x94,0xAA,0x40,0x38,0x00,0xFA,0xB2, // D0-DF
|
||||
0xE2,0xA2,0x67,0x32,0x32,0x12,0x32,0xB2,0x32,0x32,0x32,0x32,0x75,0xA3,0x26,0x7B, // E0-EF
|
||||
0x83,0x26,0xF9,0x83,0x2E,0xFF,0xE3,0x16,0x7D,0xC0,0x1E,0x63,0x21,0x07,0xE3,0x01, // F0-FF
|
||||
};
|
||||
int i;
|
||||
size_t bytes = read_streamfile(dest, offset, length, sf);
|
||||
|
||||
/* decrypt data (xor) */
|
||||
//if (offset >= data->start) {
|
||||
for (i = 0; i < bytes; i++) {
|
||||
if (offset + i >= data->start) { //todo recheck
|
||||
dest[i] ^= key[(data->key_start + (offset - data->start) + i) % sizeof(key)];
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/* decrypts subfile if needed */
|
||||
static STREAMFILE* setup_sqex_sead_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, int encryption, size_t header_size, size_t key_start) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
|
||||
/* setup sf */
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size);
|
||||
if (encryption) {
|
||||
sqex_sead_io_data io_data = {0};
|
||||
|
||||
io_data.start = header_size;
|
||||
io_data.key_start = key_start;
|
||||
|
||||
new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(sqex_sead_io_data), sqex_sead_io_read, NULL);
|
||||
}
|
||||
|
||||
new_sf = open_fakename_streamfile_f(new_sf, NULL, "hca");
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _SQEX_SEAD_STREAMFILE_H_ */
|
||||
|
@ -1,9 +1,8 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "ubi_lyn_ogg_streamfile.h"
|
||||
#include "ubi_lyn_streamfile.h"
|
||||
|
||||
static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size);
|
||||
|
||||
/* LyN RIFF - from Ubisoft LyN engine games [Red Steel 2 (Wii), Adventures of Tintin (Multi), From Dust (Multi), Just Dance 3/4 (multi)] */
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
|
||||
@ -111,7 +110,7 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x3157: { /* Ogg (PC), interleaved 1ch */
|
||||
size_t interleave_size, stride_size;
|
||||
size_t interleave_size;
|
||||
layered_layout_data* data = NULL;
|
||||
int i;
|
||||
|
||||
@ -119,7 +118,6 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
interleave_size = read_32bitLE(start_offset+0x04,streamFile);
|
||||
stride_size = interleave_size * channel_count;
|
||||
/* interleave is adjusted so there is no smaller last block, it seems */
|
||||
|
||||
vgmstream->coding_type = coding_OGG_VORBIS;
|
||||
@ -132,15 +130,15 @@ VGMSTREAM * init_vgmstream_ubi_lyn(STREAMFILE *streamFile) {
|
||||
|
||||
/* open each layer subfile */
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
size_t total_size = read_32bitLE(start_offset+0x08 + 0x04*i,streamFile);
|
||||
off_t layer_offset = start_offset+0x08 + 0x04*channel_count + interleave_size*i;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
size_t logical_size = read_32bitLE(start_offset+0x08 + 0x04*i,streamFile);
|
||||
off_t layer_offset = start_offset + 0x08 + 0x04*channel_count; //+ interleave_size*i;
|
||||
|
||||
temp_streamFile = setup_lyn_ogg_streamfile(streamFile, layer_offset, interleave_size, stride_size, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_sf = setup_ubi_lyn_streamfile(streamFile, layer_offset, interleave_size, i, channel_count, logical_size);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
data->layers[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
data->layers[i] = init_vgmstream_ogg_vorbis(temp_sf);
|
||||
close_streamfile(temp_sf);
|
||||
if (!data->layers[i]) goto fail;
|
||||
|
||||
/* could validate between layers, meh */
|
||||
@ -229,7 +227,7 @@ fail:
|
||||
/* LyN RIFF in containers */
|
||||
VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
off_t subfile_offset;
|
||||
size_t subfile_size;
|
||||
|
||||
@ -259,35 +257,16 @@ VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE *streamFile) {
|
||||
|
||||
subfile_size = read_32bitLE(subfile_offset+0x04,streamFile) + 0x04+0x04;
|
||||
|
||||
temp_streamFile = setup_lyn_streamfile(streamFile, subfile_offset,subfile_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_sf = setup_subfile_streamfile(streamFile, subfile_offset, subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ubi_lyn(temp_streamFile);
|
||||
vgmstream = init_vgmstream_ubi_lyn(temp_sf);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static STREAMFILE* setup_lyn_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,92 +0,0 @@
|
||||
#ifndef _LYN_OGG_STREAMFILE_H_
|
||||
#define _LYN_OGG_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
off_t start_physical_offset; /* interleaved data start, for this substream */
|
||||
size_t interleave_block_size; /* max size that can be read before encountering other substreams */
|
||||
size_t stride_size; /* step size between interleave blocks (interleave*channels) */
|
||||
size_t total_size; /* final size of the deinterleaved substream */
|
||||
} lyn_ogg_io_data;
|
||||
|
||||
|
||||
/* Handles deinterleaving of complete files, skipping portions or other substreams. */
|
||||
static size_t lyn_ogg_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, lyn_ogg_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
while (length > 0) {
|
||||
size_t to_read;
|
||||
size_t length_available;
|
||||
off_t block_num;
|
||||
off_t intrablock_offset;
|
||||
off_t physical_offset;
|
||||
|
||||
block_num = offset / data->interleave_block_size;
|
||||
intrablock_offset = offset % data->interleave_block_size;
|
||||
physical_offset = data->start_physical_offset + block_num*data->stride_size + intrablock_offset;
|
||||
length_available = data->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);
|
||||
total_read += bytes_read;
|
||||
|
||||
if (bytes_read != to_read) {
|
||||
return total_read;
|
||||
}
|
||||
|
||||
dest += bytes_read;
|
||||
offset += bytes_read;
|
||||
length -= bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t lyn_ogg_io_size(STREAMFILE *streamfile, lyn_ogg_io_data* data) {
|
||||
return data->total_size;
|
||||
}
|
||||
|
||||
|
||||
static STREAMFILE* setup_lyn_ogg_streamfile(STREAMFILE *streamFile, off_t start_offset, size_t interleave_block_size, size_t stride_size, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
lyn_ogg_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(lyn_ogg_io_data);
|
||||
|
||||
io_data.start_physical_offset = start_offset;
|
||||
io_data.interleave_block_size = interleave_block_size;
|
||||
io_data.stride_size = stride_size;
|
||||
io_data.total_size = total_size;
|
||||
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(temp_streamFile, &io_data,io_data_size, lyn_ogg_io_read,lyn_ogg_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,"ogg");
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _LYN_OGG_STREAMFILE_H_ */
|
23
src/meta/ubi_lyn_streamfile.h
Normal file
23
src/meta/ubi_lyn_streamfile.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef _UBI_LYN_STREAMFILE_H_
|
||||
#define _UBI_LYN_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
/* Deinterleaves LYN streams */
|
||||
static STREAMFILE* setup_ubi_lyn_streamfile(STREAMFILE* sf, off_t stream_offset, size_t interleave_size, int stream_number, int stream_count, size_t logical_size) {
|
||||
STREAMFILE *new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
VGM_LOG("so=%lx, chu=%x, n=%i, c=%i, lo=%x\n", stream_offset, interleave_size, stream_number, stream_count, logical_size);
|
||||
cfg.stream_start = stream_offset;
|
||||
cfg.chunk_size = interleave_size;
|
||||
cfg.step_start = stream_number;
|
||||
cfg.step_count = stream_count;
|
||||
cfg.logical_size = logical_size;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
//new_sf = open_buffer_streamfile_f(new_sf, 0);
|
||||
new_sf = open_fakename_streamfile_f(new_sf, NULL, "ogg");
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _UBI_LYN_STREAMFILE_H_ */
|
@ -1,125 +1,26 @@
|
||||
#ifndef _XWMA_KONAMI_STREAMFILE_H_
|
||||
#define _XWMA_KONAMI_STREAMFILE_H_
|
||||
#include "../streamfile.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* config */
|
||||
off_t stream_offset;
|
||||
size_t stream_size;
|
||||
size_t block_align;
|
||||
|
||||
/* state */
|
||||
off_t logical_offset; /* fake offset */
|
||||
off_t physical_offset; /* actual offset */
|
||||
size_t block_size; /* current size */
|
||||
size_t skip_size; /* size from block start to reach data */
|
||||
size_t data_size; /* usable size in a block */
|
||||
|
||||
size_t logical_size;
|
||||
} xwma_konami_io_data;
|
||||
|
||||
|
||||
static size_t xwma_konami_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, size_t length, xwma_konami_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
|
||||
/* re-start when previous offset (can't map logical<>physical offsets) */
|
||||
if (data->logical_offset < 0 || offset < data->logical_offset) {
|
||||
data->physical_offset = data->stream_offset;
|
||||
data->logical_offset = 0x00;
|
||||
data->data_size = 0;
|
||||
}
|
||||
|
||||
/* read blocks */
|
||||
while (length > 0) {
|
||||
|
||||
/* ignore EOF */
|
||||
if (offset < 0 || data->physical_offset >= data->stream_offset + data->stream_size) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* process new block */
|
||||
if (data->data_size == 0) {
|
||||
data->block_size = align_size_to_block(data->block_align, 0x10);
|
||||
data->data_size = data->block_align;
|
||||
data->skip_size = 0x00;
|
||||
}
|
||||
|
||||
/* move to next block */
|
||||
if (data->data_size == 0 || offset >= data->logical_offset + data->data_size) {
|
||||
data->physical_offset += data->block_size;
|
||||
data->logical_offset += data->data_size;
|
||||
data->data_size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read data */
|
||||
{
|
||||
size_t bytes_consumed, bytes_done, to_read;
|
||||
|
||||
bytes_consumed = offset - data->logical_offset;
|
||||
to_read = data->data_size - bytes_consumed;
|
||||
if (to_read > length)
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, streamfile);
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
length -= bytes_done;
|
||||
|
||||
if (bytes_done != to_read || bytes_done == 0) {
|
||||
break; /* error/EOF */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t xwma_konami_io_size(STREAMFILE *streamfile, xwma_konami_io_data* data) {
|
||||
uint8_t buf[1];
|
||||
|
||||
if (data->logical_size)
|
||||
return data->logical_size;
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
xwma_konami_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
return data->logical_size;
|
||||
}
|
||||
|
||||
/* Handles de-padding Konami XWMA blocked streams */
|
||||
static STREAMFILE* setup_xwma_konami_streamfile(STREAMFILE *streamFile, off_t stream_offset, size_t block_align) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
xwma_konami_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(xwma_konami_io_data);
|
||||
|
||||
io_data.stream_offset = stream_offset;
|
||||
io_data.stream_size = get_streamfile_size(streamFile) - stream_offset;
|
||||
io_data.block_align = block_align;
|
||||
io_data.logical_offset = -1; /* force phys offset reset */
|
||||
|
||||
/* setup subfile */
|
||||
new_streamFile = open_wrap_streamfile(streamFile);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_io_streamfile(new_streamFile, &io_data,io_data_size, xwma_konami_io_read,xwma_konami_io_size);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
new_streamFile = open_buffer_streamfile(new_streamFile,0);
|
||||
if (!new_streamFile) goto fail;
|
||||
temp_streamFile = new_streamFile;
|
||||
|
||||
return temp_streamFile;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* _XWMA_KONAMI_STREAMFILE_H_ */
|
||||
#ifndef _XWMA_KONAMI_STREAMFILE_H_
|
||||
#define _XWMA_KONAMI_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
|
||||
data->block_size = align_size_to_block(data->cfg.chunk_size, 0x10);
|
||||
data->data_size = data->cfg.chunk_size;
|
||||
data->skip_size = 0x00;
|
||||
}
|
||||
|
||||
/* De-pads Konami XWMA streams */
|
||||
static STREAMFILE* setup_xwma_konami_streamfile(STREAMFILE* sf, off_t stream_offset, size_t block_align) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = stream_offset;
|
||||
cfg.chunk_size = block_align;
|
||||
cfg.block_callback = block_callback;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
//new_sf = open_buffer_streamfile_f(new_sf, 0);
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _XWMA_KONAMI_STREAMFILE_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user