mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 15:54:05 +01:00
Add .mups [Pier Solar (PC), Ghost Blade HD (PC/Switch)]
This commit is contained in:
parent
1a4de84b1f
commit
2a6babc70a
@ -323,6 +323,7 @@ static const char* extension_list[] = {
|
||||
"mta2",
|
||||
"mtaf",
|
||||
"mul",
|
||||
"mups",
|
||||
"mus",
|
||||
"musc",
|
||||
"musx",
|
||||
|
@ -304,6 +304,10 @@
|
||||
RelativePath=".\meta\mul_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mups_streamfile.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mzrt_streamfile.h"
|
||||
>
|
||||
@ -672,10 +676,14 @@
|
||||
RelativePath=".\meta\encrypted.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mul.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mul.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\mups.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\exakt_sc.c"
|
||||
>
|
||||
|
@ -123,6 +123,7 @@
|
||||
<ClInclude Include="meta\xnb_lz4mg.h" />
|
||||
<ClInclude Include="meta\mta2_streamfile.h" />
|
||||
<ClInclude Include="meta\mul_streamfile.h" />
|
||||
<ClInclude Include="meta\mups_streamfile.h" />
|
||||
<ClInclude Include="meta\mzrt_streamfile.h" />
|
||||
<ClInclude Include="meta\nus3bank_streamfile.h" />
|
||||
<ClInclude Include="meta\ogg_vorbis_streamfile.h" />
|
||||
@ -316,6 +317,7 @@
|
||||
<ClCompile Include="meta\ea_wve_ad10.c" />
|
||||
<ClCompile Include="meta\encrypted.c" />
|
||||
<ClCompile Include="meta\mul.c" />
|
||||
<ClCompile Include="meta\mups.c" />
|
||||
<ClCompile Include="meta\exakt_sc.c" />
|
||||
<ClCompile Include="meta\ffw.c" />
|
||||
<ClCompile Include="meta\flx.c" />
|
||||
|
@ -125,6 +125,9 @@
|
||||
<ClInclude Include="meta\mul_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\mups_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="meta\mzrt_streamfile.h">
|
||||
<Filter>meta\Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -460,6 +463,9 @@
|
||||
<ClCompile Include="meta\mul.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\mups.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\exakt_sc.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
//todo move to utils or something
|
||||
|
||||
static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
|
||||
static void block_callback_default(STREAMFILE* sf, deblock_io_data* data) {
|
||||
data->block_size = data->cfg.chunk_size;
|
||||
data->skip_size = data->cfg.skip_size;
|
||||
data->data_size = data->block_size - data->skip_size;
|
||||
@ -10,7 +10,7 @@ static void block_callback_default(STREAMFILE *sf, deblock_io_data *data) {
|
||||
//;VGM_LOG("DEBLOCK: of=%lx, bs=%lx, ss=%lx, ds=%lx\n", data->physical_offset, data->block_size, data->skip_size, data->data_size);
|
||||
}
|
||||
|
||||
static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, deblock_io_data* data) {
|
||||
static size_t deblock_io_read(STREAMFILE* sf, uint8_t* dest, off_t offset, size_t length, deblock_io_data* data) {
|
||||
size_t total_read = 0;
|
||||
|
||||
//;VGM_LOG("DEBLOCK: of=%lx, sz=%x, po=%lx\n", offset, length, data->physical_offset);
|
||||
@ -25,9 +25,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||
data->skip_size = 0;
|
||||
|
||||
data->step_count = data->cfg.step_start;
|
||||
/*
|
||||
data->read_count = data->cfg.read_count;
|
||||
*/
|
||||
//data->read_count = data->cfg.read_count;
|
||||
}
|
||||
|
||||
/* read blocks */
|
||||
@ -98,6 +96,10 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||
to_read = length;
|
||||
bytes_done = read_streamfile(dest, data->physical_offset + data->skip_size + bytes_consumed, to_read, sf);
|
||||
|
||||
if (data->cfg.read_callback) {
|
||||
data->cfg.read_callback(dest, data, bytes_consumed, bytes_done);
|
||||
}
|
||||
|
||||
total_read += bytes_done;
|
||||
dest += bytes_done;
|
||||
offset += bytes_done;
|
||||
@ -112,7 +114,7 @@ static size_t deblock_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_
|
||||
return total_read;
|
||||
}
|
||||
|
||||
static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
||||
static size_t deblock_io_size(STREAMFILE* sf, deblock_io_data* data) {
|
||||
uint8_t buf[0x04];
|
||||
|
||||
if (data->logical_size)
|
||||
@ -124,7 +126,7 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
||||
}
|
||||
|
||||
/* force a fake read at max offset, to get max logical_offset (will be reset next read) */
|
||||
deblock_io_read(streamfile, buf, 0x7FFFFFFF, 1, data);
|
||||
deblock_io_read(sf, buf, 0x7FFFFFFF, 1, data);
|
||||
data->logical_size = data->logical_offset;
|
||||
|
||||
//todo tests:
|
||||
@ -141,8 +143,8 @@ static size_t deblock_io_size(STREAMFILE *streamfile, deblock_io_data* data) {
|
||||
* decoder can't easily use blocked layout, or some other weird feature. It "filters" data so
|
||||
* reader only sees clean data without blocks. Must pass setup config and a callback that sets
|
||||
* sizes of a single block. */
|
||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg) {
|
||||
STREAMFILE *new_sf = NULL;
|
||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t *cfg) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_io_data io_data = {0};
|
||||
|
||||
/* prepare data */
|
||||
|
@ -34,7 +34,9 @@ struct deblock_config_t {
|
||||
size_t interleave_last_count;
|
||||
|
||||
/* callback that setups deblock_io_data state, normally block_size and data_size */
|
||||
void (*block_callback)(STREAMFILE *sf, deblock_io_data *data);
|
||||
void (*block_callback)(STREAMFILE* sf, deblock_io_data* data);
|
||||
/* callback that alters block, with the current position into the block (0=beginning) */
|
||||
void (*read_callback)(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size);
|
||||
} ;
|
||||
|
||||
struct deblock_io_data {
|
||||
@ -56,6 +58,6 @@ struct deblock_io_data {
|
||||
off_t physical_end;
|
||||
};
|
||||
|
||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE *sf, deblock_config_t *cfg);
|
||||
STREAMFILE* open_io_deblock_streamfile_f(STREAMFILE* sf, deblock_config_t* cfg);
|
||||
|
||||
#endif /* _DEBLOCK_STREAMFILE_H_ */
|
||||
|
@ -900,4 +900,6 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_ktsr(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
39
src/meta/mups.c
Normal file
39
src/meta/mups.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "mups_streamfile.h"
|
||||
|
||||
|
||||
/* MUPS - from Watermelon/HUCARD games (same programmer) [Pier Solar and the Great Architects (PC), Ghost Blade HD (PC/Switch)] */
|
||||
VGMSTREAM* init_vgmstream_mups(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE *temp_sf = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* mups: header id?
|
||||
* (extensionless): default? */
|
||||
if (!check_extensions(sf, "mups,"))
|
||||
goto fail;
|
||||
|
||||
if (read_u32be(0x00,sf) != 0x4D555053) /* "MUPS" */
|
||||
goto fail;
|
||||
if (read_u32be(0x08,sf) != 0x50737348) /* "PssH" */
|
||||
goto fail;
|
||||
|
||||
/* just an Ogg with changed OggS/vorbis words (see streamfile) */
|
||||
|
||||
temp_sf = setup_mups_streamfile(sf, 0x08);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
102
src/meta/mups_streamfile.h
Normal file
102
src/meta/mups_streamfile.h
Normal file
@ -0,0 +1,102 @@
|
||||
#ifndef _MUPS_STREAMFILE_H_
|
||||
#define _MUPS_STREAMFILE_H_
|
||||
#include "deblock_streamfile.h"
|
||||
|
||||
static inline int32_t max32(int32_t val1, int32_t val2) {
|
||||
if (val1 > val2)
|
||||
return val2;
|
||||
return val1;
|
||||
}
|
||||
|
||||
static void read_callback(uint8_t* dst, deblock_io_data* data, size_t block_pos, size_t read_size) {
|
||||
static const uint8_t oggs[] = { 0x4F, 0x67, 0x67, 0x53 };
|
||||
static const uint8_t vorbis[] = { 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73 };
|
||||
int i, j, min, max;
|
||||
|
||||
/* Swaps Xiph magic words back (resulting page checksum is ok).
|
||||
* Reads can start/end anywhere, but block_pos = 0 is always page start */
|
||||
|
||||
/* change "PssH" back to "OggS" */
|
||||
if (block_pos < 0x04) {
|
||||
min = block_pos;
|
||||
if (min < 0x00)
|
||||
min = 0x00;
|
||||
|
||||
max = block_pos + read_size;
|
||||
if (max > 0x04)
|
||||
max = 0x04;
|
||||
|
||||
for (i = min; i < max; i++) {
|
||||
dst[i] = oggs[i - 0x00];
|
||||
}
|
||||
}
|
||||
|
||||
/* first page also needs "psolar" to "vorbis" */
|
||||
if (data->logical_offset == 0 && block_pos < 0x23) {
|
||||
min = block_pos;
|
||||
if (min < 0x1d)
|
||||
min = 0x1d;
|
||||
|
||||
max = block_pos + read_size;
|
||||
if (max > 0x23)
|
||||
max = 0x23;
|
||||
|
||||
for (i = min; i < max; i++, j++) {
|
||||
dst[i] = vorbis[i - 0x1d];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int get_page_size(STREAMFILE* sf, off_t page_offset) {
|
||||
static const int base_size = 0x1b;
|
||||
uint8_t page[0x1b + 0x100];
|
||||
uint8_t segments;
|
||||
size_t page_size;
|
||||
int i, bytes;
|
||||
|
||||
bytes = read_streamfile(page + 0x00, page_offset + 0x00, base_size, sf);
|
||||
if (bytes != base_size) goto fail;
|
||||
|
||||
if (get_u32be(page + 0x00) != 0x50737348) /* "PssH" */
|
||||
goto fail;
|
||||
|
||||
segments = get_u8(page + 0x1a);
|
||||
|
||||
bytes = read_streamfile(page + base_size, page_offset + base_size, segments, sf);
|
||||
if (bytes != segments) goto fail;
|
||||
|
||||
page_size = base_size + segments;
|
||||
for (i = 0; i < segments; i++) {
|
||||
uint8_t segment_size = get_u8(page + base_size + i);
|
||||
page_size += segment_size;
|
||||
}
|
||||
|
||||
return page_size;
|
||||
fail:
|
||||
return -1; /* not a valid page */
|
||||
}
|
||||
|
||||
static void block_callback(STREAMFILE* sf, deblock_io_data* data) {
|
||||
off_t page_offset = data->physical_offset;
|
||||
|
||||
/* block size = OggS page size as we need read_callback called on page starts */
|
||||
data->data_size = get_page_size(sf, page_offset);
|
||||
data->block_size = data->data_size;
|
||||
}
|
||||
|
||||
/* Fixes MUPS streams that contain mutated OggS */
|
||||
static STREAMFILE* setup_mups_streamfile(STREAMFILE* sf, off_t stream_offset) {
|
||||
STREAMFILE* new_sf = NULL;
|
||||
deblock_config_t cfg = {0};
|
||||
|
||||
cfg.stream_start = stream_offset;
|
||||
cfg.block_callback = block_callback;
|
||||
cfg.read_callback = read_callback;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
new_sf = open_io_deblock_streamfile_f(new_sf, &cfg);
|
||||
new_sf = open_fakename_streamfile_f(new_sf, NULL, "ogg");
|
||||
return new_sf;
|
||||
}
|
||||
|
||||
#endif /* _MUPS_STREAMFILE_H_ */
|
@ -496,6 +496,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_diva,
|
||||
init_vgmstream_imuse,
|
||||
init_vgmstream_ktsr,
|
||||
init_vgmstream_mups,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
Loading…
x
Reference in New Issue
Block a user