mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
commit
d438b1e299
@ -94,7 +94,7 @@ export CFLAGS LDFLAGS
|
||||
### targets
|
||||
|
||||
vgmstream_cli: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||
$(CC) $(CFLAGS) "-DVERSION=\"`../version.sh`\"" test.c $(LDFLAGS) -o $(OUTPUT_CLI)
|
||||
$(CC) $(CFLAGS) "-DVERSION=\"`../version.sh`\"" vgmstream_cli.c $(LDFLAGS) -o $(OUTPUT_CLI)
|
||||
$(STRIP) $(OUTPUT_CLI)
|
||||
|
||||
vgmstream123: libvgmstream.a $(TARGET_EXT_LIBS)
|
||||
|
@ -9,7 +9,7 @@ endif
|
||||
AM_CFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_srcdir)/ext_includes/ $(AO_CFLAGS)
|
||||
AM_MAKEFLAGS = -f Makefile.autotools
|
||||
|
||||
vgmstream_cli_SOURCES = test.c
|
||||
vgmstream_cli_SOURCES = vgmstream_cli.c
|
||||
vgmstream_cli_LDADD = ../src/libvgmstream.la
|
||||
|
||||
vgmstream123_SOURCES = vgmstream123.c
|
||||
|
@ -182,7 +182,7 @@
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\test.c"
|
||||
RelativePath=".\vgmstream_cli.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
|
@ -121,7 +121,7 @@
|
||||
</PreBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="test.c" />
|
||||
<ClCompile Include="vgmstream_cli.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\dependencies\fdk-aac\msvc\fdk-aac.vcxproj">
|
||||
|
@ -15,7 +15,7 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="test.c">
|
||||
<ClCompile Include="vgmstream_cli.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
@ -530,8 +530,8 @@ static int ealayer3_rebuild_mpeg_frame(vgm_bitstream* is_0, ealayer3_frame_info*
|
||||
VGM_LOG("MPEG EAL3: written 0x%lx but expected less than 0x%x at 0x%lx\n", os->b_off/8, expected_frame_size, os->info_offset);
|
||||
}
|
||||
else {
|
||||
/* fill ancillary data (ignored) */
|
||||
memset(os->buf + os->b_off/8, 0x77, expected_frame_size - os->b_off/8);
|
||||
/* fill ancillary data (should be ignored, but 0x00 seems to improve mpg123's free bitrate detection) */
|
||||
memset(os->buf + os->b_off/8, 0x00, expected_frame_size - os->b_off/8);
|
||||
}
|
||||
|
||||
os->b_off = expected_frame_size*8;
|
||||
|
@ -620,7 +620,11 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) {
|
||||
ch0_header.loop_flag != ch1_header.loop_flag ||
|
||||
ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
|
||||
ch0_header.loop_end_offset != ch1_header.loop_end_offset
|
||||
) goto fail;
|
||||
) {
|
||||
/* Timesplitters 2 GC's ts2_atom_smasher_44_fx.mss differs slightly in samples but plays ok */
|
||||
if (meta_type != meta_DSP_MSS)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ch0_header.loop_flag) {
|
||||
off_t loop_off;
|
||||
|
@ -5,12 +5,12 @@
|
||||
/* SXD - Sony/SCE's SNDX lib format (cousin of SGXD) [Gravity Rush, Freedom Wars, Soul Sacrifice PSV] */
|
||||
VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
STREAMFILE * streamHeader = NULL, *streamData = NULL;
|
||||
off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0;
|
||||
size_t chunk_size, stream_size = 0;
|
||||
|
||||
int is_separate;
|
||||
int loop_flag, channels, codec;
|
||||
int is_dual, is_external;
|
||||
int loop_flag, channels, codec, location;
|
||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||
uint32_t at9_config_data = 0;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
@ -19,10 +19,10 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
/* check extension, case insensitive */
|
||||
/* .sxd: header+data (SXDF), .sxd1: header (SXDF) + .sxd2 = data (SXDS) */
|
||||
if (!check_extensions(streamFile,"sxd,sxd2")) goto fail;
|
||||
is_separate = !check_extensions(streamFile,"sxd");
|
||||
is_dual = !check_extensions(streamFile,"sxd");
|
||||
|
||||
/* sxd1+sxd2: use sxd1 as header; otherwise use the current file as header */
|
||||
if (is_separate) {
|
||||
if (is_dual) {
|
||||
if (read_32bitBE(0x00,streamFile) != 0x53584453) /* "SXDS" */
|
||||
goto fail;
|
||||
streamHeader = open_stream_ext(streamFile, "sxd1");
|
||||
@ -50,10 +50,10 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
table_offset = chunk_offset + 0x08 + 4*(target_subsong-1);
|
||||
header_offset = table_offset + read_32bitLE(table_offset,streamHeader);
|
||||
|
||||
/* 0x00(4): type/location? (00/01=sxd/RAM?, 02/03=sxd2/stream?) */
|
||||
codec = read_8bit (header_offset+0x04,streamHeader);
|
||||
channels = read_8bit (header_offset+0x05,streamHeader);
|
||||
sample_rate = read_32bitLE(header_offset+0x08,streamHeader);
|
||||
location = read_32bitLE(header_offset+0x00,streamHeader);
|
||||
codec = read_8bit (header_offset+0x04,streamHeader);
|
||||
channels = read_8bit (header_offset+0x05,streamHeader);
|
||||
sample_rate = read_32bitLE(header_offset+0x08,streamHeader);
|
||||
/* 0x0c(4): unknown size? (0x4000/0x3999/0x3333/etc, not related to extra data) */
|
||||
/* 0x10(4): ? + volume? + pan? (can be 0 for music) */
|
||||
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
|
||||
@ -69,7 +69,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
off_t max_offset = chunk_offset + chunk_size;
|
||||
|
||||
/* manually try to find certain tag, no idea about the actual format
|
||||
* (most variable in Soul Sacrifice; extra size isn't found in the SXD AFAIK) */
|
||||
* (most variable in Soul Sacrifice; extra data size isn't found in the header AFAIK) */
|
||||
while (extra_offset < max_offset) {
|
||||
uint32_t tag = read_32bitBE(extra_offset, streamHeader);
|
||||
if (tag == 0x0A010000 || tag == 0x0A010600) {
|
||||
@ -85,16 +85,33 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
|
||||
loop_flag = loop_start_sample != -1 && loop_end_sample != -1;
|
||||
|
||||
/* from current offset in sxd, absolute in sxd2 */
|
||||
if (is_separate) {
|
||||
start_offset = stream_offset;
|
||||
/* usually sxd=header+data and sxd1=header + sxd2=data, but rarely sxd1 contain data [The Last Guardian (PS4)] */
|
||||
switch(location) { /* might not be exact but seems the only difference in TLG */
|
||||
case 0x00: /* some Chaos Rings 2 sfx */
|
||||
case 0x01: /* most common */
|
||||
case 0x05: /* some Gradity Rush 2 sfx */
|
||||
is_external = 0; /* RAM asset? */
|
||||
break;
|
||||
|
||||
case 0x02: /* some Chaos Rings 3 sfx */
|
||||
case 0x03: /* most common */
|
||||
is_external = 1; /* stream asset? */
|
||||
break;
|
||||
|
||||
default:
|
||||
VGM_LOG("SXD: unknown location 0x%x\n", location);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (is_external) {
|
||||
start_offset = stream_offset; /* absolute if external */
|
||||
} else {
|
||||
start_offset = header_offset+0x24 + stream_offset;
|
||||
start_offset = header_offset+0x24 + stream_offset; /* from current entry offset if internal */
|
||||
}
|
||||
}
|
||||
|
||||
/* get stream name (NAME is tied to REQD/cues, and SFX cues repeat WAVEs, but should work ok for streams) */
|
||||
if (is_separate && find_chunk_le(streamHeader, 0x4E414D45,first_offset,0, &chunk_offset,NULL)) { /* "NAME" */
|
||||
if (is_dual && find_chunk_le(streamHeader, 0x4E414D45,first_offset,0, &chunk_offset,NULL)) { /* "NAME" */
|
||||
/* table: relative offset (32b) + hash? (32b) + cue index (32b) */
|
||||
int i;
|
||||
int num_entries = read_16bitLE(chunk_offset+0x04,streamHeader); /* can be bigger than streams */
|
||||
@ -107,6 +124,22 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_external && !is_dual) {
|
||||
VGM_LOG("SXD: found single sxd with external data\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (is_external) {
|
||||
streamData = streamFile;
|
||||
} else {
|
||||
streamData = streamHeader;
|
||||
}
|
||||
|
||||
if (start_offset > get_streamfile_size(streamData)) {
|
||||
VGM_LOG("SXD: wrong location?\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
@ -136,7 +169,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
case 0x42: { /* ATRAC9 [Soul Sacrifice (Vita), Freedom Wars (Vita)] */
|
||||
case 0x42: { /* ATRAC9 [Soul Sacrifice (Vita), Freedom Wars (Vita), Gravity Rush 2 (PS4)] */
|
||||
atrac9_config cfg = {0};
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
@ -157,14 +190,14 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,streamData,start_offset))
|
||||
goto fail;
|
||||
|
||||
if (is_separate && streamHeader) close_streamfile(streamHeader);
|
||||
if (is_dual) close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (is_separate && streamHeader) close_streamfile(streamHeader);
|
||||
if (is_dual) close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -474,7 +474,6 @@ static int parse_keyval(STREAMFILE * streamFile, STREAMFILE * streamText, txth_h
|
||||
else if (0==strcmp(key,"interleave")) {
|
||||
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;
|
||||
|
@ -5,9 +5,10 @@
|
||||
VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count;
|
||||
int flags, codec, sample_rate, block_size, bps;
|
||||
size_t xnb_size, data_size;
|
||||
int loop_flag = 0, channel_count, num_samples = 0, loop_start = 0, loop_end = 0;
|
||||
int big_endian, flags, codec, sample_rate, block_size, bps;
|
||||
size_t data_size;
|
||||
char platform;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
@ -17,65 +18,77 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
/* check header */
|
||||
if ((read_32bitBE(0,streamFile) & 0xFFFFFF00) != 0x584E4200) /* "XNB" */
|
||||
goto fail;
|
||||
/* 0x04: platform: ‘w’ = Microsoft Windows, ‘m’ = Windows Phone 7, ‘x’ = Xbox 360, 'a' = Android */
|
||||
|
||||
/* 0x04: platform: ‘w’ = Windows, ‘m’ = Windows Phone 7, ‘x’ = X360, 'a' = Android, 'P': PS4 */
|
||||
platform = read_8bit(0x03,streamFile);
|
||||
big_endian = (platform == 'x');
|
||||
|
||||
if (read_8bit(0x04,streamFile) != 0x05) /* XNA 4.0 version only */
|
||||
goto fail;
|
||||
|
||||
flags = read_8bit(0x05,streamFile);
|
||||
if (flags & 0x80) goto fail; /* compressed with XMemCompress */
|
||||
//if (flags & 0x01) goto fail; /* XMA/big endian flag? */
|
||||
//if (flags & 0x01) goto fail; /* "HiDef profile" content (no actual difference) */
|
||||
if (flags & 0x80) goto fail; /* compressed with XMemCompress (at 0x0a is decompressed size) */
|
||||
if (flags & 0x40) goto fail; /* custom compression? seen in Square Heroes (PS4) */
|
||||
|
||||
/* full size */
|
||||
if (read_32bitLE(0x06,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
/* "check for truncated XNB" (???) */
|
||||
xnb_size = read_32bitLE(0x06,streamFile);
|
||||
if (get_streamfile_size(streamFile) < xnb_size) goto fail;
|
||||
|
||||
/* XNB contains "type reader" class references to parse "shared resource" data (can be any implemented filetype) */
|
||||
{
|
||||
char reader_name[255+1];
|
||||
off_t current_chunk = 0xa;
|
||||
off_t current_offset = 0x0a;
|
||||
int reader_string_len;
|
||||
uint32_t fmt_chunk_size;
|
||||
const char * type_sound = "Microsoft.Xna.Framework.Content.SoundEffectReader"; /* partial "fmt" chunk or XMA */
|
||||
//const char * type_song = "Microsoft.Xna.Framework.Content.SongReader"; /* just references a companion .wma */
|
||||
|
||||
/* type reader count, accept only one for now */
|
||||
if (read_8bit(current_chunk++, streamFile) != 1)
|
||||
if (read_8bit(current_offset++, streamFile) != 1)
|
||||
goto fail;
|
||||
|
||||
reader_string_len = read_8bit(current_chunk++, streamFile); /* doesn't count null */
|
||||
reader_string_len = read_8bit(current_offset++, streamFile); /* doesn't count null */
|
||||
if (reader_string_len > 255) goto fail;
|
||||
|
||||
/* check SoundEffect type string */
|
||||
if (read_string(reader_name,reader_string_len+1,current_chunk,streamFile) != reader_string_len)
|
||||
if (read_string(reader_name,reader_string_len+1,current_offset,streamFile) != reader_string_len)
|
||||
goto fail;
|
||||
if ( strcmp(reader_name, type_sound) != 0 )
|
||||
goto fail;
|
||||
current_chunk += reader_string_len + 1;
|
||||
current_chunk += 4; /* reader version */
|
||||
current_offset += reader_string_len + 1;
|
||||
current_offset += 4; /* reader version */
|
||||
|
||||
/* shared resource count */
|
||||
if (read_8bit(current_chunk++, streamFile) != 1)
|
||||
if (read_8bit(current_offset++, streamFile) != 1)
|
||||
goto fail;
|
||||
|
||||
/* shared resource: partial "fmt" chunk */
|
||||
fmt_chunk_size = read_32bitLE(current_chunk, streamFile);
|
||||
current_chunk += 4;
|
||||
fmt_chunk_size = read_32bitLE(current_offset, streamFile);
|
||||
current_offset += 4;
|
||||
|
||||
{
|
||||
codec = read_16bitLE(current_chunk+0x00, streamFile);
|
||||
channel_count = read_16bitLE(current_chunk+0x02, streamFile);
|
||||
sample_rate = read_32bitLE(current_chunk+0x04, streamFile);
|
||||
block_size = read_16bitLE(current_chunk+0x0c, streamFile);
|
||||
bps = read_16bitLE(current_chunk+0x0e, streamFile);
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||
|
||||
codec = read_16bit(current_offset+0x00, streamFile);
|
||||
channel_count = read_16bit(current_offset+0x02, streamFile);
|
||||
sample_rate = read_32bit(current_offset+0x04, streamFile);
|
||||
block_size = read_16bit(current_offset+0x0c, streamFile);
|
||||
bps = read_16bit(current_offset+0x0e, streamFile);
|
||||
|
||||
if (codec == 0x166) {
|
||||
xma2_parse_fmt_chunk_extra(streamFile, current_offset, &loop_flag, &num_samples, &loop_start, &loop_end, big_endian);
|
||||
}
|
||||
}
|
||||
|
||||
current_chunk += fmt_chunk_size;
|
||||
current_offset += fmt_chunk_size;
|
||||
|
||||
data_size = read_32bitLE(current_chunk, streamFile);
|
||||
current_chunk += 4;
|
||||
data_size = read_32bitLE(current_offset, streamFile);
|
||||
current_offset += 4;
|
||||
|
||||
start_offset = current_chunk;
|
||||
start_offset = current_offset;
|
||||
}
|
||||
|
||||
|
||||
@ -87,14 +100,14 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
vgmstream->meta_type = meta_XNB;
|
||||
|
||||
switch (codec) {
|
||||
case 0x01:
|
||||
case 0x01: /* Dragon's Blade (Android) */
|
||||
vgmstream->coding_type = bps == 8 ? coding_PCM8_U_int : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = block_size / channel_count;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bps);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
case 0x02: /* White Noise Online (PC) */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->interleave_block_size = block_size;
|
||||
@ -108,6 +121,29 @@ VGMSTREAM * init_vgmstream_xnb(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = ms_ima_bytes_to_samples(data_size, block_size, channel_count);
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x166: { /* Terraria (X360) */
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes, block_size, block_count;
|
||||
|
||||
block_size = 0x10000; /* guessed */
|
||||
block_count = data_size / block_size + (data_size % block_size ? 1 : 0);
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf,0x100, num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
if (bytes <= 0) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
VGM_LOG("XNB: unknown codec 0x%x\n", codec);
|
||||
goto fail;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,3 +9,4 @@
|
||||
#define IDC_THREAD_PRIORITY_TEXT 1007
|
||||
#define IDC_DEFAULT_BUTTON 1008
|
||||
#define IDC_DISABLE_SUBSONGS 1009
|
||||
#define IDC_DOWNMIX 1010
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <windows.h>
|
||||
#define IDC_STATIC -1
|
||||
|
||||
//elements: text, id, x, y, width, height [, style [, extended-style]]
|
||||
IDD_CONFIG DIALOGEX 0, 0, 187, 164
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "in_vgmstream configuration"
|
||||
@ -23,8 +24,9 @@ BEGIN
|
||||
CONTROL "Loop forever",IDC_LOOP_FOREVER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,70,77,10
|
||||
CONTROL "Ignore looping",IDC_IGNORE_LOOP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,83,77,10
|
||||
CONTROL "Disable subsongs",IDC_DISABLE_SUBSONGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,99,87,10
|
||||
LTEXT "Thread Priority",IDC_STATIC,21,119,46,8
|
||||
CONTROL "Slider1",IDC_THREAD_PRIORITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,7,127,77,10
|
||||
CTEXT "DATARIFIC",IDC_THREAD_PRIORITY_TEXT,7,140,77,18
|
||||
CONTROL "Downmix",IDC_DOWNMIX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,112,87,10
|
||||
LTEXT "Thread Priority",IDC_STATIC,21,132,46,8
|
||||
CONTROL "Slider1",IDC_THREAD_PRIORITY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,7,140,77,10
|
||||
CTEXT "DATARIFIC",IDC_THREAD_PRIORITY_TEXT,7,153,77,18
|
||||
END
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user