mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 09:37:21 +01:00
Add streamed .xnb [Clan N (Switch), Guncraft: Blocked and Loaded (X360)]
This commit is contained in:
parent
95709ce3c2
commit
34fcec9fab
144
src/meta/xnb.c
144
src/meta/xnb.c
@ -12,13 +12,14 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
int big_endian, flags, codec, sample_rate, block_align, bps;
|
int big_endian, flags, codec, sample_rate, block_align, bps;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
char platform;
|
char platform;
|
||||||
int is_ogg = 0, is_at9 = 0;
|
int is_sound = 0, is_ogg = 0, is_at9 = 0, is_song = 0;
|
||||||
|
char song_name[255+1];
|
||||||
|
|
||||||
|
|
||||||
/* checks */
|
/* checks */
|
||||||
if (!check_extensions(sf,"xnb"))
|
if (!check_extensions(sf,"xnb"))
|
||||||
goto fail;
|
goto fail;
|
||||||
if ((read_32bitBE(0x00, sf) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */
|
if ((read_u32be(0x00, sf) & 0xFFFFFF00) != get_id32be("XNB\0"))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360
|
/* XNA Studio platforms: 'w' = Windows, 'm' = Windows Phone 7, 'x' = X360
|
||||||
@ -34,7 +35,7 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
//if (flags & 0x01) goto fail; /* "HiDef profile" content (no actual difference) */
|
//if (flags & 0x01) goto fail; /* "HiDef profile" content (no actual difference) */
|
||||||
|
|
||||||
/* full size */
|
/* full size */
|
||||||
if (read_32bitLE(0x06, sf) != get_streamfile_size(sf)) {
|
if (read_u32le(0x06, sf) != get_streamfile_size(sf)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,49 +60,73 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
/* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */
|
/* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */
|
||||||
{
|
{
|
||||||
char reader_name[255+1];
|
char reader_name[255+1];
|
||||||
size_t reader_string_len;
|
size_t string_len;
|
||||||
uint32_t fmt_chunk_size;
|
uint8_t type_count;
|
||||||
const char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
const static char* type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||||
const char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
const static char* type_ogg = "SoundEffectFromOggReader"; /* has extra text info after base part */
|
||||||
//const char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
const static char* type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* references a companion .wma */
|
||||||
|
const static char* type_int32 = "Microsoft.Xna.Framework.Content.Int32Reader"; /* extra crap */
|
||||||
|
|
||||||
/* type reader count, accept only one for now */
|
type_count = read_u8(offset++, sf_h);
|
||||||
if (read_u8(offset++, sf_h) != 1)
|
|
||||||
|
/* check type reader string */
|
||||||
|
string_len = read_u8(offset++, sf_h); /* doesn't count null */
|
||||||
|
if (read_string(reader_name, string_len+1, offset, sf_h) != string_len)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
reader_string_len = read_u8(offset++, sf_h); /* doesn't count null */
|
if (strcmp(reader_name, type_sound) == 0) {
|
||||||
if (reader_string_len > 255) goto fail;
|
if (type_count != 1) goto fail;
|
||||||
|
is_sound = 1;
|
||||||
/* check SoundEffect type string */
|
}
|
||||||
if (read_string(reader_name, reader_string_len+1, offset, sf_h) != reader_string_len)
|
else if (strncmp(reader_name, type_ogg, strlen(type_ogg)) == 0) { /* has extra info after base string */
|
||||||
|
if (type_count != 1) goto fail;
|
||||||
|
is_ogg = 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(reader_name, type_song) == 0) {
|
||||||
|
if (type_count != 2) goto fail;
|
||||||
|
is_song = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
goto fail;
|
goto fail;
|
||||||
if (strcmp(reader_name, type_sound) != 0) {
|
|
||||||
is_ogg = strncmp(reader_name, type_ogg, strlen(type_ogg)) == 0;
|
|
||||||
if (!is_ogg)
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += reader_string_len + 1;
|
offset += string_len + 1;
|
||||||
|
|
||||||
|
if (is_song) {
|
||||||
|
offset += 3;
|
||||||
|
|
||||||
|
string_len = read_u8(offset++, sf_h);
|
||||||
|
if (read_string(reader_name, string_len+1, offset, sf_h) != string_len)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (strcmp(reader_name, type_int32) != 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
offset += string_len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
offset += 0x04; /* reader version, 0 */
|
offset += 0x04; /* reader version, 0 */
|
||||||
|
|
||||||
/* shared resource count */
|
/* shared resource number 1 */
|
||||||
if (read_u8(offset++, sf_h) != 1)
|
if (read_u8(offset++, sf_h) != 1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* shared resource: partial "fmt" chunk */
|
/* read shared resource */
|
||||||
fmt_chunk_size = read_32bitLE(offset, sf_h);
|
if (is_sound || is_ogg) {
|
||||||
offset += 0x04;
|
/* partial "fmt" chunk */
|
||||||
|
uint32_t (*read_u32)(off_t,STREAMFILE*) = big_endian ? read_u32be : read_u32le;
|
||||||
|
uint16_t (*read_u16)(off_t,STREAMFILE*) = big_endian ? read_u16be : read_u16le;
|
||||||
|
uint32_t fmt_chunk_size;
|
||||||
|
|
||||||
{
|
fmt_chunk_size = read_u32le(offset, sf_h);
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
offset += 0x04;
|
||||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
|
||||||
|
|
||||||
codec = (uint16_t)read_16bit(offset+0x00, sf_h);
|
codec = read_u16(offset+0x00, sf_h);
|
||||||
channel_count = read_16bit(offset+0x02, sf_h);
|
channel_count = read_u16(offset+0x02, sf_h);
|
||||||
sample_rate = read_32bit(offset+0x04, sf_h);
|
sample_rate = read_u32(offset+0x04, sf_h);
|
||||||
/* 0x08: byte rate */
|
/* 0x08: byte rate */
|
||||||
block_align = read_16bit(offset+0x0c, sf_h);
|
block_align = read_u16(offset+0x0c, sf_h);
|
||||||
bps = read_16bit(offset+0x0e, sf_h);
|
bps = read_u16(offset+0x0e, sf_h);
|
||||||
|
|
||||||
if (codec == 0x0002) {
|
if (codec == 0x0002) {
|
||||||
if (!msadpcm_check_coefs(sf_h, offset + 0x14))
|
if (!msadpcm_check_coefs(sf_h, offset + 0x14))
|
||||||
@ -115,7 +140,7 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
|
|
||||||
if (codec == 0xFFFF) {
|
if (codec == 0xFFFF) {
|
||||||
if (platform != 'S') goto fail;
|
if (platform != 'S') goto fail;
|
||||||
sample_rate = read_32bit(offset+fmt_chunk_size+0x04+0x08, sf_h);
|
sample_rate = read_u32(offset+fmt_chunk_size+0x04+0x08, sf_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mini-fmt has AT9 stuff then a regular RIFF [Square Heroes (PS4)] */
|
/* mini-fmt has AT9 stuff then a regular RIFF [Square Heroes (PS4)] */
|
||||||
@ -123,15 +148,29 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
is_at9 = 1;
|
is_at9 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* regular (with loop tags) Ogg poses as PCM [Little Savior (PC)] */
|
/* Ogg (with loop tags) poses as PCM [Little Savior (PC)] */
|
||||||
|
|
||||||
|
offset += fmt_chunk_size;
|
||||||
|
|
||||||
|
data_size = read_u32le(offset, sf_h);
|
||||||
|
offset += 0x04;
|
||||||
|
|
||||||
|
start_offset = offset;
|
||||||
}
|
}
|
||||||
|
else if (is_song) {
|
||||||
|
/* filename (typically same as .xnb but .wma) */
|
||||||
|
string_len = read_u8(offset++, sf_h);
|
||||||
|
|
||||||
offset += fmt_chunk_size;
|
if (read_string(song_name, string_len+1, offset, sf_h) != string_len + 1)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
data_size = read_32bitLE(offset, sf_h);
|
start_offset = 0;
|
||||||
offset += 0x04;
|
data_size = 0;
|
||||||
|
/* after name is shared resource number 1 + 32b int (durationMs?) */
|
||||||
start_offset = offset;
|
}
|
||||||
|
else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* container handling */
|
/* container handling */
|
||||||
@ -158,6 +197,31 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
if (sf_h != sf) close_streamfile(sf_h);
|
if (sf_h != sf) close_streamfile(sf_h);
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
}
|
}
|
||||||
|
else if (is_song) {
|
||||||
|
STREAMFILE* sf_body = open_streamfile_by_filename(sf, song_name);
|
||||||
|
if (!sf_body) goto fail;
|
||||||
|
|
||||||
|
if (read_u32be(0x00, sf_body) == 0x01000080) {
|
||||||
|
STREAMFILE* temp_sf = setup_subfile_streamfile(sf_body, 0x00, get_streamfile_size(sf_body), "opus");
|
||||||
|
if (!temp_sf) goto fail;
|
||||||
|
|
||||||
|
/* MonoGame with NXOpus [Clan N (Switch)] */
|
||||||
|
vgmstream = init_vgmstream_opus_std(temp_sf);
|
||||||
|
close_streamfile(temp_sf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef VGM_USE_FFMPEG
|
||||||
|
/* XNA with WMA [Guncraft: Blocked and Loaded (X360)] */
|
||||||
|
vgmstream = init_vgmstream_ffmpeg(sf_body);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
close_streamfile(sf_body);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->meta_type = meta_XNB;
|
||||||
|
if (sf_h != sf) close_streamfile(sf_h);
|
||||||
|
return vgmstream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
@ -221,7 +285,7 @@ VGMSTREAM* init_vgmstream_xnb(STREAMFILE* sf) {
|
|||||||
vgmstream->coding_type = coding_NGC_DSP;
|
vgmstream->coding_type = coding_NGC_DSP;
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->layout_type = layout_interleave;
|
||||||
vgmstream->interleave_block_size = data_size / channel_count;
|
vgmstream->interleave_block_size = data_size / channel_count;
|
||||||
vgmstream->num_samples = read_32bitLE(start_offset + 0x00, sf_h);
|
vgmstream->num_samples = read_s32le(start_offset + 0x00, sf_h);
|
||||||
//vgmstream->num_samples = dsp_bytes_to_samples(data_size - 0x60*channel_count, channel_count);
|
//vgmstream->num_samples = dsp_bytes_to_samples(data_size - 0x60*channel_count, channel_count);
|
||||||
|
|
||||||
dsp_read_coefs(vgmstream, sf_h, start_offset + 0x1c, vgmstream->interleave_block_size, big_endian);
|
dsp_read_coefs(vgmstream, sf_h, start_offset + 0x1c, vgmstream->interleave_block_size, big_endian);
|
||||||
|
Loading…
Reference in New Issue
Block a user