2010-02-05 19:25:31 +01:00
|
|
|
#include "meta.h"
|
2021-08-22 12:20:55 +02:00
|
|
|
#include "../coding/coding.h"
|
2021-08-26 19:52:19 +02:00
|
|
|
#include "../util/chunks.h"
|
2021-08-22 12:20:55 +02:00
|
|
|
|
|
|
|
enum {
|
|
|
|
CHUNK_RIFF = 0x52494646, /* "RIFF" */
|
|
|
|
CHUNK_LIST = 0x4C495354, /* "LIST" */
|
|
|
|
CHUNK_segh = 0x73656768, /* "segh" */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* DMSG - DirectMusic Segment with streams [Nightcaster II: Equinox (Xbox), Wildfire (PC)] */
|
|
|
|
VGMSTREAM* init_vgmstream_dmsg(STREAMFILE* sf) {
|
|
|
|
VGMSTREAM* vgmstream = NULL;
|
|
|
|
//int loop_flag, channels, sample_rate;
|
|
|
|
//int found_data = 0;
|
|
|
|
//int32_t num_samples, loop_start, loop_end;
|
|
|
|
//off_t start_offset;
|
|
|
|
off_t offset = 0, name_offset = 0, name_size = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* checks */
|
|
|
|
/* .sgt: common
|
|
|
|
* .dmsg: header id */
|
|
|
|
if (!check_extensions(sf, "sgt,dmsg"))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (!is_id32be(0x00,sf, "RIFF"))
|
|
|
|
goto fail;
|
|
|
|
if (!is_id32be(0x08,sf, "DMSG"))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* A DirectMusic segment usually has lots of chunks then data pointing to .dls soundbank.
|
|
|
|
* This accepts .sgt with a RIFF WAVE inside (less common). */
|
2010-02-05 19:25:31 +01:00
|
|
|
{
|
2021-08-22 12:20:55 +02:00
|
|
|
chunk_t rc = {0};
|
|
|
|
chunk_t dc = {0};
|
|
|
|
|
|
|
|
rc.current = 0x0c;
|
|
|
|
while (next_chunk(&rc, sf)) {
|
|
|
|
switch(rc.type) {
|
|
|
|
/* "segh" has loopnum/samplesloop */
|
|
|
|
case CHUNK_segh:
|
|
|
|
//todo: missing TMusicTime format
|
|
|
|
/* 0x00: dwRepeats (>0 or -1=inf)
|
|
|
|
* 0x04: mtLength
|
|
|
|
* 0x08: mtPlayStart
|
|
|
|
* 0x0c: mtLoopStart
|
|
|
|
* 0x10: mtLoopEnd
|
|
|
|
* 0x14: dwResolution
|
|
|
|
* 0x18: rtLength (optional)
|
|
|
|
* .. */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHUNK_LIST:
|
|
|
|
if (is_id32be(rc.offset + 0x00, sf, "UNFO") && is_id32be(rc.offset + 0x04, sf, "UNAM")) {
|
|
|
|
name_offset = rc.offset + 0x0c;
|
|
|
|
name_size = read_u32le(rc.offset + 0x08, sf);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CHUNK_RIFF:
|
|
|
|
if (!is_id32be(rc.offset, sf, "DMCN"))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
dc.current = rc.offset + 0x04;
|
|
|
|
while (next_chunk(&dc, sf)) {
|
|
|
|
switch(dc.type) {
|
|
|
|
case CHUNK_LIST:
|
|
|
|
/* abridged, there are some sublists */
|
|
|
|
if (is_id32be(dc.offset + 0x00, sf, "cosl") && is_id32be(dc.offset + 0x30, sf, "WAVE")) {
|
|
|
|
offset = dc.offset + 0x34;
|
|
|
|
dc.current = -1;
|
|
|
|
rc.current = -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2010-02-05 19:25:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-22 12:20:55 +02:00
|
|
|
if (!offset)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
|
|
/* subfile has a few extra chunks (guid, wavh) but otherwise standard (seen PCM and MS-ADPCM, with fact chunks) */
|
2010-02-05 19:25:31 +01:00
|
|
|
{
|
2021-08-22 12:20:55 +02:00
|
|
|
STREAMFILE* temp_sf = NULL;
|
|
|
|
off_t subfile_offset = offset;
|
|
|
|
size_t subfile_size = read_u32le(offset + 0x04, sf) + 0x08;
|
|
|
|
|
|
|
|
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wav");
|
|
|
|
if (!temp_sf) goto fail;
|
|
|
|
|
|
|
|
vgmstream = init_vgmstream_riff(temp_sf);
|
|
|
|
close_streamfile(temp_sf);
|
|
|
|
if (!vgmstream) goto fail;
|
|
|
|
|
|
|
|
if (name_offset) {
|
|
|
|
if (name_size >= STREAM_NAME_SIZE)
|
|
|
|
name_size = STREAM_NAME_SIZE;
|
|
|
|
read_string_utf16le(vgmstream->stream_name,name_size, name_offset, sf);
|
2010-02-05 19:25:31 +01:00
|
|
|
}
|
|
|
|
|
2021-08-22 12:20:55 +02:00
|
|
|
return vgmstream;
|
|
|
|
}
|
2010-02-05 19:25:31 +01:00
|
|
|
|
|
|
|
fail:
|
2021-08-22 12:20:55 +02:00
|
|
|
close_vgmstream(vgmstream);
|
2010-02-05 19:25:31 +01:00
|
|
|
return NULL;
|
|
|
|
}
|