mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-13 18:20:50 +01:00
commit
5c26b9f192
7
BUILD.md
7
BUILD.md
@ -139,7 +139,8 @@ vgmstream uses C (C89 when possible), and C++ for the foobar2000 and Audacious p
|
||||
|
||||
C should be restricted to features VS2010 understands. This mainly means declaring variables at the start of a { .. } block (declare+initialize is fine, as long as it doesn't reference variables declared in the same block) and avoiding C99 features like variable-length arrays (but certain others like // comments are fine).
|
||||
|
||||
There are no hard coding rules but for consistency should follow general C conventions and the style used in most files: 4 spaces instead of tabs, underscore_and_lowercase_names, brackets starting in the same line (`if (..) { CRLF ... }`), etc. Some of the code may be a bit inefficient or duplicated at places, but it isn't much of a problem if gives clarity.
|
||||
There are no hard coding rules but for consistency should follow general C conventions and the style used in most files: 4 spaces instead of tabs, underscore_and_lowercase_names, brackets starting in the same line (`if (..) { CRLF ... }`), etc. Some of the code may be a bit inefficient or duplicated at places, but it isn't much of a problem if gives clarity. vgmstream's performance is fast enough (as it mainly deals with playing songs in real time) so that favors clarity over optimization. Similarly some code may segfault or even cause infinite loops on bad data, but it's fixed as encountered rather than worrying to much about improbable cases.
|
||||
|
||||
|
||||
### Structure
|
||||
|
||||
@ -180,7 +181,9 @@ Structs with I/O callbacks that vgmstream uses in place of stdio/FILEs. All I/O
|
||||
|
||||
Players should open a base STREAMFILE and pass it to init_vgmstream. Once it's done this STREAMFILE must be closed, as internally vgmstream opens its own copy (using the base one's callbacks).
|
||||
|
||||
Custom STREAMFILEs wrapping base STREAMFILEs may be used for complex I/O cases (ex. if data needs decryption, or a file is composed of multiple sub-files).
|
||||
For optimization purposes vgmstream may open a copy of the FILE per channel, as each has its own I/O buffer, and channel data can be too separate to fit a single buffer.
|
||||
|
||||
Custom STREAMFILEs wrapping base STREAMFILEs may be used for complex I/O cases (ex. if data needs decryption, parts needs to be skipped on the fly, or a file is composed of multiple sub-files), as some codecs are not easy to feed chunked data.
|
||||
|
||||
#### VGMSTREAM
|
||||
The VGMSTREAM (caps) is the main struct created during init when a file is successfully recognized and parsed. It holds the file's configuration (channels, sample rate, decoder, layout, samples, loop points, etc) and decoder state (STREAMFILEs, offsets per channel, current sample, etc), and is used to interact with the API.
|
||||
|
@ -171,6 +171,10 @@ Programs like VGMToolbox can help to create GENH.
|
||||
".txth" or ".(ext).txth" (for the whole folder), or "(name.ext).txth" (for a
|
||||
single file). Contains dynamic text commands to read data from the original
|
||||
file, or static values.
|
||||
|
||||
**TXTP**: a text playlist that works as a single song. Can contain a list of
|
||||
filenames to play as one (ex. "intro.vag" "loop.vag"), name with subsong index
|
||||
(ex. bgm.sxd#10), or mask channels to only play some (ex. "song.adx#c1,2").
|
||||
|
||||
|
||||
## Supported codec types
|
||||
|
@ -39,7 +39,8 @@ extern "C" {
|
||||
|
||||
input_vgmstream::input_vgmstream() {
|
||||
vgmstream = NULL;
|
||||
subsong = 1;
|
||||
subsong = 0; // 0 = not set, will be properly changed on first setup_vgmstream
|
||||
direct_subsong = false;
|
||||
|
||||
decoding = false;
|
||||
paused = 0;
|
||||
@ -64,6 +65,7 @@ input_vgmstream::~input_vgmstream() {
|
||||
vgmstream = NULL;
|
||||
}
|
||||
|
||||
// called first when a new file is opened
|
||||
void input_vgmstream::open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
|
||||
|
||||
if (!p_path) { // shouldn't be possible
|
||||
@ -104,6 +106,7 @@ void input_vgmstream::open(service_ptr_t<file> p_filehint,const char * p_path,t_
|
||||
}
|
||||
}
|
||||
|
||||
// called after opening file (possibly per subsong too)
|
||||
unsigned input_vgmstream::get_subsong_count() {
|
||||
// if the plugin uses input_factory_t template and returns > 1 here when adding a song to the playlist,
|
||||
// foobar will automagically "unpack" it by calling decode_initialize/get_info with all subsong indexes.
|
||||
@ -115,6 +118,11 @@ unsigned input_vgmstream::get_subsong_count() {
|
||||
int subsong_count = vgmstream->num_streams;
|
||||
if (subsong_count == 0)
|
||||
subsong_count = 1; // most formats don't have subsongs
|
||||
|
||||
// pretend we don't have subsongs as we don't want foobar to unpack the rest
|
||||
if (direct_subsong)
|
||||
subsong_count = 1;
|
||||
|
||||
return subsong_count;
|
||||
}
|
||||
|
||||
@ -167,12 +175,12 @@ t_filestats input_vgmstream::get_file_stats(abort_callback & p_abort) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
|
||||
// called right before actually playing (decoding) a song/subsong
|
||||
void input_vgmstream::decode_initialize(t_uint32 p_subsong, unsigned p_flags, abort_callback & p_abort) {
|
||||
force_ignore_loop = !!(p_flags & input_flag_no_looping);
|
||||
|
||||
// if subsong changes recreate vgmstream (subsong is only used on init)
|
||||
if (subsong != p_subsong) {
|
||||
// if subsong changes recreate vgmstream
|
||||
if (subsong != p_subsong && !direct_subsong) {
|
||||
subsong = p_subsong;
|
||||
setup_vgmstream(p_abort);
|
||||
}
|
||||
@ -331,6 +339,17 @@ void input_vgmstream::setup_vgmstream(abort_callback & p_abort) {
|
||||
return;
|
||||
}
|
||||
|
||||
// default subsong is 0, meaning first init (vgmstream should open first stream, but not set stream_index).
|
||||
// if the stream_index is already set, then the subsong was opened directly by some means (txtp, playlist, etc).
|
||||
// add flag as in that case we only want to play the subsong but not unpack subsongs (which foobar does by default).
|
||||
if (subsong == 0 && vgmstream->stream_index > 0) {
|
||||
subsong = vgmstream->stream_index;
|
||||
direct_subsong = true;
|
||||
}
|
||||
if (subsong == 0)
|
||||
subsong = 1;
|
||||
|
||||
|
||||
if (ignore_loop)
|
||||
vgmstream->loop_flag = 0;
|
||||
|
||||
@ -348,7 +367,9 @@ void input_vgmstream::get_subsong_info(t_uint32 p_subsong, pfc::string_base & ti
|
||||
char temp[1024];
|
||||
|
||||
// reuse current vgmstream if not querying a new subsong
|
||||
if (subsong != p_subsong) {
|
||||
// if it's a direct subsong then subsong may be N while p_subsong 1
|
||||
// there is no need to recreate the infostream, there is only one subsong used
|
||||
if (subsong != p_subsong && !direct_subsong) {
|
||||
infostream = init_vgmstream_foo(p_subsong, filename, p_abort);
|
||||
} else {
|
||||
// vgmstream ready as get_info is valid after open() with any reason
|
||||
@ -386,7 +407,7 @@ void input_vgmstream::get_subsong_info(t_uint32 p_subsong, pfc::string_base & ti
|
||||
title.set_string(p, e - p);
|
||||
|
||||
if (!disable_subsongs && infostream && infostream->num_streams > 1) {
|
||||
sprintf(temp,"#%d",p_subsong);
|
||||
sprintf(temp,"#%d",infostream->stream_index);
|
||||
title += temp;
|
||||
|
||||
if (infostream->stream_name[0] != '\0') {
|
||||
@ -397,7 +418,7 @@ void input_vgmstream::get_subsong_info(t_uint32 p_subsong, pfc::string_base & ti
|
||||
}
|
||||
|
||||
// and only close if was querying a new subsong
|
||||
if (subsong != p_subsong) {
|
||||
if (subsong != p_subsong && !direct_subsong) {
|
||||
close_vgmstream(infostream);
|
||||
infostream = NULL;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ class input_vgmstream : public input_stubs {
|
||||
/* state */
|
||||
VGMSTREAM * vgmstream;
|
||||
t_uint32 subsong;
|
||||
bool direct_subsong;
|
||||
|
||||
bool decoding;
|
||||
int paused;
|
||||
|
@ -78,6 +78,7 @@ void decode_psx_badflags(VGMSTREAMCHANNEL * stream, sample * outbuf, int channel
|
||||
void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int frame_size);
|
||||
void decode_hevag(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t ps_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels);
|
||||
|
||||
/* xa_decoder */
|
||||
void decode_xa(VGMSTREAM * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
@ -211,5 +211,9 @@ void decode_psx_configurable(VGMSTREAMCHANNEL * stream, sample * outbuf, int cha
|
||||
|
||||
|
||||
size_t ps_bytes_to_samples(size_t bytes, int channels) {
|
||||
return bytes / channels / 16 * 28;
|
||||
return bytes / channels / 0x10 * 28;
|
||||
}
|
||||
|
||||
size_t ps_cfg_bytes_to_samples(size_t bytes, size_t frame_size, int channels) {
|
||||
return bytes / channels / frame_size * 28;
|
||||
}
|
||||
|
@ -146,7 +146,12 @@ static int build_header_comment(uint8_t * buf, size_t bufsize) {
|
||||
static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id, STREAMFILE *streamFile) {
|
||||
int bytes;
|
||||
|
||||
/* try to load from external files first */
|
||||
/* try to locate from the precompiled list */
|
||||
bytes = load_fvs_array(buf, bufsize, setup_id, streamFile);
|
||||
if (bytes)
|
||||
return bytes;
|
||||
|
||||
/* try to load from external files */
|
||||
bytes = load_fvs_file_single(buf, bufsize, setup_id, streamFile);
|
||||
if (bytes)
|
||||
return bytes;
|
||||
@ -155,11 +160,6 @@ static int build_header_setup(uint8_t * buf, size_t bufsize, uint32_t setup_id,
|
||||
if (bytes)
|
||||
return bytes;
|
||||
|
||||
/* try to locate from the precompiled list */
|
||||
bytes = load_fvs_array(buf, bufsize, setup_id, streamFile);
|
||||
if (bytes)
|
||||
return bytes;
|
||||
|
||||
/* not found */
|
||||
VGM_LOG("FSB Vorbis: setup_id %08x not found\n", setup_id);
|
||||
return 0;
|
||||
|
@ -1098,13 +1098,13 @@ static unsigned int ww2ogg_tremor_book_maptype1_quantvals(unsigned int entries,
|
||||
static int load_wvc(uint8_t * ibuf, size_t ibufsize, uint32_t codebook_id, wwise_setup_t setup_type, STREAMFILE *streamFile) {
|
||||
size_t bytes;
|
||||
|
||||
/* try to load from external file (ignoring type, just use file if found) */
|
||||
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, streamFile);
|
||||
/* try to locate from the precompiled list */
|
||||
bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
|
||||
if (bytes)
|
||||
return bytes;
|
||||
|
||||
/* try to locate from the precompiled list */
|
||||
bytes = load_wvc_array(ibuf, ibufsize, codebook_id, setup_type);
|
||||
/* try to load from external file (ignoring type, just use file if found) */
|
||||
bytes = load_wvc_file(ibuf, ibufsize, codebook_id, streamFile);
|
||||
if (bytes)
|
||||
return bytes;
|
||||
|
||||
|
@ -110,6 +110,7 @@ static const char* extension_list[] = {
|
||||
"e4x",
|
||||
"eam",
|
||||
"emff",
|
||||
"eno",
|
||||
"enth",
|
||||
"exa",
|
||||
"ezw",
|
||||
@ -119,6 +120,7 @@ static const char* extension_list[] = {
|
||||
"filp",
|
||||
"flx",
|
||||
"fsb",
|
||||
"fsv",
|
||||
"fwav",
|
||||
|
||||
"g1l",
|
||||
@ -230,6 +232,7 @@ static const char* extension_list[] = {
|
||||
"omu",
|
||||
//"opus", //common
|
||||
"otm",
|
||||
"ovb",
|
||||
|
||||
"p1d", //txth/reserved [Farming Simulator 18 (3DS)]
|
||||
"p2bt",
|
||||
@ -253,6 +256,7 @@ static const char* extension_list[] = {
|
||||
"rkv",
|
||||
"rnd",
|
||||
"rof",
|
||||
"rpgmvo",
|
||||
"rrds",
|
||||
"rsd",
|
||||
"rsf",
|
||||
@ -296,6 +300,7 @@ static const char* extension_list[] = {
|
||||
"sl3",
|
||||
"slb", //txth/reserved [THE Nekomura no Hitobito (PS2)]
|
||||
"sli",
|
||||
"smc",
|
||||
"smp",
|
||||
"smpl", //fake extension (to be removed)
|
||||
"smv",
|
||||
@ -320,6 +325,7 @@ static const char* extension_list[] = {
|
||||
//"stm", //common
|
||||
"stma", //fake extension (to be removed)
|
||||
"str",
|
||||
"stream",
|
||||
"strm",
|
||||
"sts",
|
||||
"stx",
|
||||
@ -334,10 +340,10 @@ static const char* extension_list[] = {
|
||||
|
||||
"tec",
|
||||
"thp",
|
||||
"tk1",
|
||||
"tk5",
|
||||
"tra",
|
||||
"tun",
|
||||
"txtp",
|
||||
"tydsp",
|
||||
|
||||
"ulw",
|
||||
@ -665,7 +671,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
|
||||
{meta_CAF, "tri-Crescendo CAF Header"},
|
||||
{meta_PS2_VPK, "VPK Header"},
|
||||
{meta_GENH, "GENH Generic Header"},
|
||||
{meta_GENH, "GENH generic header"},
|
||||
{meta_DSP_SADB, "Procyon Studio SADB header"},
|
||||
{meta_SADL, "Procyon Studio SADL header"},
|
||||
{meta_PS2_BMDX, "Beatmania .bmdx header"},
|
||||
@ -885,7 +891,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_PS2_SPM, "SPM header"},
|
||||
{meta_X360_TRA, "Terminal Reality .TRA raw header"},
|
||||
{meta_PS2_VGS, "Princess Soft VGS header"},
|
||||
{meta_PS2_IAB, "IAB header"},
|
||||
{meta_PS2_IAB, "Runtime .IAB header"},
|
||||
{meta_PS2_STRLR, "STR L/R header"},
|
||||
{meta_LSF_N1NJ4N, ".lsf !n1nj4n header"},
|
||||
{meta_VAWX, "feelplus VAWX header"},
|
||||
@ -942,7 +948,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_NGC_ULW, "Criterion ULW raw header"},
|
||||
{meta_PC_XA30, "Reflections XA30 PC header"},
|
||||
{meta_WII_04SW, "Reflections 04SW header"},
|
||||
{meta_TXTH, "TXTH Generic Header"},
|
||||
{meta_TXTH, "TXTH generic header"},
|
||||
{meta_EA_BNK, "Electronic Arts BNK header"},
|
||||
{meta_SK_AUD, "Silicon Knights AUD header"},
|
||||
{meta_AHX, "CRI AHX header"},
|
||||
@ -989,7 +995,10 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_DSP_MCADPCM, "Bethesda .mcadpcm header"},
|
||||
{meta_UBI_LYN, "Ubisoft LyN RIFF header"},
|
||||
{meta_MSB_MSH, "Sony MSB+MSH header"},
|
||||
{meta_OGG_RPGMV, "Ogg Vorbis (RPGMV header)"},
|
||||
{meta_OGG_RPGMV, "Ogg Vorbis (RPGMV header)"},
|
||||
{meta_OGG_ENO, "Ogg Vorbis (ENO header)"},
|
||||
{meta_TXTP, "TXTP generic header"},
|
||||
{meta_SMC_SMH, "Genki SMC+SMH header"},
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{meta_FFmpeg, "FFmpeg supported file format"},
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
static void block_update(VGMSTREAM * vgmstream);
|
||||
|
||||
void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
|
||||
int samples_written=0;
|
||||
|
||||
@ -34,12 +36,13 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
}
|
||||
|
||||
/* probably block bug or EOF, next calcs would give wrong values and buffer segfaults */
|
||||
if (samples_this_block <= 0) {
|
||||
VGM_LOG("layout_blocked: empty/wrong block\n");
|
||||
if (samples_this_block < 0) {
|
||||
VGM_LOG("layout_blocked: wrong block at 0x%lx\n", vgmstream->current_block_offset);
|
||||
memset(buffer + samples_written*vgmstream->channels, 0, (sample_count - samples_written) * vgmstream->channels * sizeof(sample));
|
||||
break;
|
||||
break; /* probable infinite loop otherwise */
|
||||
}
|
||||
|
||||
/* samples_this_block = 0 is allowed (empty block), will do nothing then move to next block */
|
||||
|
||||
samples_to_do = vgmstream_samples_to_do(samples_this_block, samples_per_frame, vgmstream);
|
||||
if (samples_written + samples_to_do > sample_count)
|
||||
@ -49,7 +52,7 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
decode_vgmstream(vgmstream, samples_written, samples_to_do, buffer);
|
||||
}
|
||||
else {
|
||||
/* block end signal (used below): partially 0-set buffer */
|
||||
/* block end signal (used in halpst): partially 0-set buffer */
|
||||
int i;
|
||||
for (i = samples_written*vgmstream->channels; i < (samples_written+samples_to_do)*vgmstream->channels; i++) {
|
||||
buffer[i]=0;
|
||||
@ -64,124 +67,10 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
/* move to next block when all samples are consumed */
|
||||
if (vgmstream->samples_into_block==samples_this_block
|
||||
/*&& vgmstream->current_sample < vgmstream->num_samples*/) { /* don't go past last block */
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_blocked_ast:
|
||||
block_update_ast(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_mxch:
|
||||
block_update_mxch(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_halpst:
|
||||
if (vgmstream->next_block_offset>=0)
|
||||
block_update_halpst(vgmstream->next_block_offset,vgmstream);
|
||||
else
|
||||
vgmstream->current_block_offset = -1;
|
||||
break;
|
||||
case layout_blocked_xa:
|
||||
block_update_xa(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_schl:
|
||||
block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_1snh:
|
||||
block_update_ea_1snh(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_caf:
|
||||
block_update_caf(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_wsi:
|
||||
block_update_wsi(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_str_snds:
|
||||
block_update_str_snds(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ws_aud:
|
||||
block_update_ws_aud(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_matx:
|
||||
block_update_matx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_dec:
|
||||
block_update_dec(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_emff_ps2:
|
||||
block_update_emff_ps2(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_emff_ngc:
|
||||
block_update_emff_ngc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_gsb:
|
||||
block_update_gsb(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vs:
|
||||
block_update_vs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_xvas:
|
||||
block_update_xvas(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_thp:
|
||||
block_update_thp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_filp:
|
||||
block_update_filp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ivaud:
|
||||
block_update_ivaud(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_swvr:
|
||||
block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_adm:
|
||||
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_bdsp:
|
||||
block_update_bdsp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_tra:
|
||||
block_update_tra(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ps2_iab:
|
||||
block_update_ps2_iab(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ps2_strlr:
|
||||
block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_rws:
|
||||
block_update_rws(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_hwas:
|
||||
block_update_hwas(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_sns:
|
||||
block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_awc:
|
||||
block_update_awc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vgs:
|
||||
block_update_vgs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vawx:
|
||||
block_update_vawx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_xvag_subsong:
|
||||
block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_au00:
|
||||
block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_ad10:
|
||||
block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_sthd:
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
block_update(vgmstream);
|
||||
|
||||
/* for VBR these may change */
|
||||
frame_size = get_vgmstream_frame_size(vgmstream); /* for VBR these may change */
|
||||
frame_size = get_vgmstream_frame_size(vgmstream);
|
||||
samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
|
||||
|
||||
/* get samples in the current block */
|
||||
@ -198,3 +87,122 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void block_update(VGMSTREAM * vgmstream) {
|
||||
switch (vgmstream->layout_type) {
|
||||
case layout_blocked_ast:
|
||||
block_update_ast(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_mxch:
|
||||
block_update_mxch(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_halpst:
|
||||
if (vgmstream->next_block_offset>=0)
|
||||
block_update_halpst(vgmstream->next_block_offset,vgmstream);
|
||||
else
|
||||
vgmstream->current_block_offset = -1;
|
||||
break;
|
||||
case layout_blocked_xa:
|
||||
block_update_xa(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_schl:
|
||||
block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_1snh:
|
||||
block_update_ea_1snh(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_caf:
|
||||
block_update_caf(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_wsi:
|
||||
block_update_wsi(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_str_snds:
|
||||
block_update_str_snds(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ws_aud:
|
||||
block_update_ws_aud(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_matx:
|
||||
block_update_matx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_dec:
|
||||
block_update_dec(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_emff_ps2:
|
||||
block_update_emff_ps2(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_emff_ngc:
|
||||
block_update_emff_ngc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_gsb:
|
||||
block_update_gsb(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vs:
|
||||
block_update_vs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_xvas:
|
||||
block_update_xvas(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_thp:
|
||||
block_update_thp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_filp:
|
||||
block_update_filp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ivaud:
|
||||
block_update_ivaud(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_swvr:
|
||||
block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_adm:
|
||||
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_bdsp:
|
||||
block_update_bdsp(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_tra:
|
||||
block_update_tra(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ps2_iab:
|
||||
block_update_ps2_iab(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ps2_strlr:
|
||||
block_update_ps2_strlr(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_rws:
|
||||
block_update_rws(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_hwas:
|
||||
block_update_hwas(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_sns:
|
||||
block_update_ea_sns(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_awc:
|
||||
block_update_awc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vgs:
|
||||
block_update_vgs(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_vawx:
|
||||
block_update_vawx(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_xvag_subsong:
|
||||
block_update_xvag_subsong(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_au00:
|
||||
block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ea_wve_ad10:
|
||||
block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_sthd:
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,97 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
/* EA-style blocks */
|
||||
void block_update_ea_swvr(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size, header_size = 0, channel_size = 0, interleave = 0;
|
||||
uint32_t block_id;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_16bitBE : read_16bitLE;
|
||||
|
||||
block_id = read_32bit(block_offset+0x00, streamFile);
|
||||
block_size = read_32bit(block_offset+0x04, streamFile);
|
||||
|
||||
/* parse blocks (Freekstyle uses multiblocks) */
|
||||
switch(block_id) {
|
||||
case 0x5641474D: /* "VAGM" */
|
||||
if (read_16bit(block_offset+0x1a, streamFile) == 0x0024) {
|
||||
header_size = 0x40;
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
|
||||
/* ignore blocks of other subsongs */
|
||||
{
|
||||
int target_subsong = vgmstream->stream_index ? vgmstream->stream_index : 1;
|
||||
if (read_32bit(block_offset+0x0c, streamFile)+1 != target_subsong) {
|
||||
channel_size = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
header_size = 0x1c;
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
}
|
||||
break;
|
||||
case 0x56414742: /* "VAGB" */
|
||||
if (read_16bit(block_offset+0x1a, streamFile) == 0x6400) {
|
||||
header_size = 0x40;
|
||||
} else {
|
||||
header_size = 0x18;
|
||||
}
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
break;
|
||||
|
||||
case 0x4453504D: /* "DSPM" */
|
||||
header_size = 0x60;
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
|
||||
/* ignore blocks of other subsongs */
|
||||
{
|
||||
int target_subsong = vgmstream->stream_index ? vgmstream->stream_index : 1;
|
||||
if (read_32bit(block_offset+0x0c, streamFile)+1 != target_subsong) {
|
||||
channel_size = 0;
|
||||
}
|
||||
}
|
||||
dsp_read_coefs_be(vgmstream, streamFile, block_offset+0x1a, 0x22);
|
||||
//todo adpcm history?
|
||||
break;
|
||||
case 0x44535042: /* "DSPB" */
|
||||
header_size = 0x40;
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
dsp_read_coefs_be(vgmstream, streamFile, block_offset+0x18, 0x00);
|
||||
//todo adpcm history?
|
||||
break;
|
||||
|
||||
case 0x4D534943: /* "MSIC" */
|
||||
header_size = 0x1c;
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
break;
|
||||
case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
|
||||
header_size = 0x14; //todo the first block is 0x18
|
||||
channel_size = (block_size - header_size) / vgmstream->channels;
|
||||
break;
|
||||
|
||||
case 0x46494C4C: /* "FILL" (FILLs do that up to 0x6000, but at 0x5FFC don't actually have size) */
|
||||
if ((block_offset + 0x04) % 0x6000 == 0)
|
||||
block_size = 0x04;
|
||||
header_size = 0x08;
|
||||
break;
|
||||
|
||||
case 0xFFFFFFFF:
|
||||
channel_size = -1; /* signal bad block */
|
||||
break;
|
||||
|
||||
default: /* ignore, 0 samples */
|
||||
VGM_LOG("EA SWVR: ignored 0x%08x at 0x%lx\n", block_id, block_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size = channel_size;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bit(vgmstream->current_block_offset+0x04,streamFile)-0x1C;
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x1C;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x1C+(vgmstream->current_block_size*i);
|
||||
interleave = vgmstream->coding_type == coding_PCM8_U_int ? 0x1 : channel_size;
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + header_size + interleave*i;
|
||||
}
|
||||
}
|
||||
|
@ -6,37 +6,25 @@
|
||||
void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size = 0;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
size_t block_size, channel_size = 0, interleave = 0;
|
||||
uint32_t block_id;
|
||||
|
||||
block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
if (block_id == 0x41643130 || block_id == 0x41643131) { /* "Ad10/Ad11" audio block/footer found */
|
||||
break;
|
||||
}
|
||||
/* rest may be "MDEC" video blocks */
|
||||
|
||||
block_offset += block_size;
|
||||
/* accept "Ad10/Ad11" audio block/footer */
|
||||
if (block_id == 0x41643130 || block_id == 0x41643131) {
|
||||
channel_size = block_size - 0x08; /* one block per channel */
|
||||
interleave = block_size;
|
||||
block_size = block_size*vgmstream->channels;
|
||||
}
|
||||
/* rest could be "MDEC" video blocks with 0 size/samples */
|
||||
|
||||
/* EOF reads (unsure if this helps) */
|
||||
if (block_offset >= file_size) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + 0x04;
|
||||
vgmstream->current_block_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + block_size*i + 0x08;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size = block_size - 0x08; /* one block per channel */
|
||||
vgmstream->current_block_size = channel_size;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size*vgmstream->channels;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = (block_offset + 0x08) + interleave*i;
|
||||
}
|
||||
}
|
||||
|
@ -6,32 +6,24 @@
|
||||
void block_update_ea_wve_au00(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size = 0, interleave;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
size_t block_size, channel_size = 0;
|
||||
uint32_t block_id;
|
||||
|
||||
block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
while (block_offset < file_size) {
|
||||
uint32_t block_id = read_32bitBE(block_offset+0x00, streamFile);
|
||||
|
||||
block_size = read_32bitBE(block_offset+0x04, streamFile);
|
||||
|
||||
if (block_id == 0x61753030 || block_id == 0x61753031) { /* "au00/au01" audio block/footer found */
|
||||
break;
|
||||
}
|
||||
/* rest may be "MDEC" video blocks */
|
||||
|
||||
block_offset += block_size;
|
||||
/* accept "au00/au01" audio block/footer */
|
||||
if (block_id == 0x61753030 || block_id == 0x61753031) {
|
||||
/* adjusted to frame boundaries as blocks have padding */
|
||||
channel_size = ((block_size - 0x10) / vgmstream->interleave_block_size * vgmstream->interleave_block_size) / vgmstream->channels;
|
||||
}
|
||||
/* rest could be "MDEC" video blocks with 0 size/samples */
|
||||
|
||||
/* size adjusted to frame boundaries as blocks have padding */
|
||||
interleave = ((block_size - 0x10) / vgmstream->interleave_block_size * vgmstream->interleave_block_size) / vgmstream->channels;
|
||||
|
||||
/* set offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = (block_offset + 0x10) + interleave*i;
|
||||
}
|
||||
|
||||
vgmstream->current_block_size = interleave;
|
||||
vgmstream->current_block_size = channel_size;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = (block_offset + 0x10) + channel_size*i;
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,22 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* set up for the block at the given offset */
|
||||
/* blocks with mini header (0x48124812 + unknown + block data + block size) */
|
||||
void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int i;
|
||||
size_t block_size, channel_size;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = read_32bitLE(vgmstream->current_block_offset+0x08,vgmstream->ch[0].streamfile);
|
||||
vgmstream->next_block_offset = vgmstream->current_block_offset+vgmstream->current_block_size+0x10;
|
||||
vgmstream->current_block_size/=vgmstream->channels;
|
||||
channel_size = read_32bitLE(block_offset+0x08,streamFile) / vgmstream->channels;
|
||||
block_size = read_32bitLE(block_offset+0x0c,streamFile);
|
||||
if (!block_size)
|
||||
block_size = 0x10; /* happens on last block */
|
||||
|
||||
for (i=0;i<vgmstream->channels;i++) {
|
||||
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x10+(vgmstream->current_block_size*i);
|
||||
|
||||
vgmstream->current_block_size = channel_size;
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + 0x10 + channel_size*i;
|
||||
}
|
||||
}
|
||||
|
@ -1218,6 +1218,10 @@
|
||||
RelativePath=".\meta\sli.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\smc_smh.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\smv.c"
|
||||
>
|
||||
@ -1281,6 +1285,10 @@
|
||||
<File
|
||||
RelativePath=".\meta\txth.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\txtp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\ubi_ckd.c"
|
||||
|
@ -172,6 +172,7 @@
|
||||
<ClCompile Include="meta\sthd.c" />
|
||||
<ClCompile Include="meta\tun.c" />
|
||||
<ClCompile Include="meta\txth.c" />
|
||||
<ClCompile Include="meta\txtp.c" />
|
||||
<ClCompile Include="meta\wii_ras.c" />
|
||||
<ClCompile Include="meta\wpd.c" />
|
||||
<ClCompile Include="meta\x360_ast.c" />
|
||||
@ -388,6 +389,7 @@
|
||||
<ClCompile Include="meta\sdt.c" />
|
||||
<ClCompile Include="meta\sfl.c" />
|
||||
<ClCompile Include="meta\sli.c" />
|
||||
<ClCompile Include="meta\smc_smh.c" />
|
||||
<ClCompile Include="meta\smv.c" />
|
||||
<ClCompile Include="meta\sps_n1.c" />
|
||||
<ClCompile Include="meta\spt_spd.c" />
|
||||
|
@ -742,6 +742,9 @@
|
||||
<ClCompile Include="meta\sli.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\smc_smh.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\smv.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -1210,6 +1213,9 @@
|
||||
<ClCompile Include="meta\txth.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\txtp.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\wpd.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -112,7 +112,7 @@ VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE *streamFile) {
|
||||
|
||||
break;
|
||||
|
||||
case 0x696D6134: /* "ima4" */
|
||||
case 0x696D6134: /* "ima4" [Vectros (iOS), Dragon Quest (iOS)] */
|
||||
vgmstream->num_samples = valid_samples;
|
||||
if (!vgmstream->num_samples) /* rare [Endless Fables 2 (iOS) */
|
||||
vgmstream->num_samples = apple_ima4_bytes_to_samples(data_size, channel_count);
|
||||
@ -144,7 +144,9 @@ VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE *streamFile) {
|
||||
|
||||
break;
|
||||
|
||||
default: /* "aac " "alac" etc: probably parsed by FFMpeg... */
|
||||
case 0x61616320: /* "aac " [Ridge Racer Accelerated (iOS)] */
|
||||
case 0x616C6163: /* "alac" [Chrono Trigger v1 (iOS)] */
|
||||
default: /* should be parsed by FFMpeg in its meta (involves parsing complex chunks) */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -3,68 +3,151 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* SWVR - from EA games [Future Cop L.A.P.D. (PS/PC), Freekstyle (PS2/GC), EA Sports Supercross (PS)] */
|
||||
/* SWVR - from EA games, demuxed from .av/trk/mis/etc [Future Cop L.A.P.D. (PS/PC), Freekstyle (PS2/GC), EA Sports Supercross (PS)] */
|
||||
VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count;
|
||||
int big_endian;
|
||||
int loop_flag = 0, channel_count, sample_rate, big_endian;
|
||||
coding_t coding;
|
||||
uint32_t block_id;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile,"str"))
|
||||
/* checks */
|
||||
/* .stream: common (found inside files), .str: shortened, probably unnecessary */
|
||||
if (!check_extensions(streamFile,"stream,str"))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x53575652) { /* "SWVR" (GC) */
|
||||
big_endian = 1;
|
||||
read_32bit = read_32bitBE;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x52565753) { /* "RVWS" (PS/PS2) */
|
||||
/* blocks ids are in machine endianness */
|
||||
if (read_32bitBE(0x00,streamFile) == 0x52565753) { /* "RVWS" (PS1/PS2/PC) */
|
||||
big_endian = 0;
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
start_offset = read_32bit(0x04, streamFile);
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x53575652) { /* "SWVR" (GC) */
|
||||
big_endian = 1;
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
start_offset = read_32bit(0x04, streamFile);
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x4D474156) { /* "MGAV", Freekstyle (PS2) raw movies */
|
||||
big_endian = 0;
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
start_offset = 0x00;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x4453504D) { /* "DSPM", Freekstyle (GC) raw movies */
|
||||
big_endian = 1;
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
start_offset = 0x00;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
start_offset = read_32bit(0x04, streamFile);
|
||||
if (read_32bit(start_offset+0x00, streamFile) == 0x50414444) /* "PADD" (Freekstyle) */
|
||||
start_offset += read_32bit(start_offset+0x04, streamFile);
|
||||
else if (read_32bit(start_offset+0x10, streamFile) == 0x53484452) /* "SHDR" (Future Cop PC) */
|
||||
start_offset += read_32bit(start_offset+0x04, streamFile);
|
||||
|
||||
start_offset = read_32bit(0x04,streamFile);
|
||||
loop_flag = 1;
|
||||
channel_count = 2;
|
||||
total_subsongs = 1;
|
||||
block_id = read_32bit(start_offset, streamFile);
|
||||
|
||||
/* files are basically headerless so we inspect blocks the first block
|
||||
* Freekstyle uses multiblocks/subsongs (though some subsongs may be clones?) */
|
||||
switch(block_id) {
|
||||
case 0x5641474D: /* "VAGM" */
|
||||
coding = coding_PSX;
|
||||
if (read_16bit(start_offset+0x1a, streamFile) == 0x0024) {
|
||||
total_subsongs = read_32bit(start_offset+0x0c, streamFile)+1;
|
||||
sample_rate = 24000;
|
||||
}
|
||||
else {
|
||||
sample_rate = 14008;
|
||||
}
|
||||
channel_count = 2;
|
||||
break;
|
||||
case 0x56414742: /* "VAGB" */
|
||||
coding = coding_PSX;
|
||||
if (read_16bit(start_offset+0x1a, streamFile) == 0x6400) {
|
||||
sample_rate = 24000;
|
||||
}
|
||||
else {
|
||||
sample_rate = 14008;
|
||||
}
|
||||
channel_count = 1;
|
||||
break;
|
||||
case 0x4453504D: /* "DSPM" */
|
||||
coding = coding_NGC_DSP;
|
||||
total_subsongs = read_32bit(start_offset+0x0c, streamFile)+1;
|
||||
sample_rate = 24000;
|
||||
channel_count = 2;
|
||||
break;
|
||||
case 0x44535042: /* "DSPB" */
|
||||
coding = coding_NGC_DSP;
|
||||
channel_count = 1;
|
||||
sample_rate = 24000;
|
||||
break;
|
||||
case 0x4D534943: /* "MSIC" */
|
||||
coding = coding_PCM8_U_int;
|
||||
channel_count = 2;
|
||||
sample_rate = 14008;
|
||||
break;
|
||||
case 0x53484F43: /* "SHOC" (a generic block but hopefully has PC sounds) */
|
||||
coding = coding_PCM8_U_int;
|
||||
channel_count = 1;
|
||||
sample_rate = 14008;
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("EA SWVR: unknown block id\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
loop_flag = 0;//(channel_count > 1); /* some Future Cop LAPD tracks repeat but other games have fadeouts */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 16000;
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->codec_endian = big_endian;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = get_streamfile_size(streamFile) / total_subsongs; /* approx... */
|
||||
|
||||
vgmstream->meta_type = meta_EA_SWVR;
|
||||
vgmstream->coding_type = coding;
|
||||
vgmstream->layout_type = layout_blocked_ea_swvr;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
/* DSP coefs are loaded per block */
|
||||
/* some files (voices etc) decode with pops but seems a mastering problem */
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* calculate samples */
|
||||
/* calc num_samples manually */
|
||||
{
|
||||
off_t current_chunk = start_offset;
|
||||
|
||||
vgmstream->num_samples = 0;
|
||||
while ((current_chunk + start_offset) < (get_streamfile_size(streamFile))) {
|
||||
uint32_t block_id = (read_32bit(current_chunk,streamFile));
|
||||
if (block_id == 0x5641474D) { /* "VAGM" */
|
||||
block_update_ea_swvr(start_offset,vgmstream);
|
||||
vgmstream->num_samples += vgmstream->current_block_size/16*28;
|
||||
current_chunk += vgmstream->current_block_size + 0x1C;
|
||||
int num_samples;
|
||||
vgmstream->stream_index = target_subsong; /* needed to skip other subsong-blocks */
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
block_update_ea_swvr(vgmstream->next_block_offset,vgmstream);
|
||||
switch(vgmstream->coding_type) {
|
||||
case coding_PSX: num_samples = ps_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_NGC_DSP: num_samples = dsp_bytes_to_samples(vgmstream->current_block_size,1); break;
|
||||
case coding_PCM8_U_int: num_samples = pcm_bytes_to_samples(vgmstream->current_block_size,1,8); break;
|
||||
default: num_samples = 0; break;
|
||||
}
|
||||
current_chunk += 0x10;
|
||||
vgmstream->num_samples += num_samples;
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
if (loop_flag) {
|
||||
@ -72,6 +155,7 @@ VGMSTREAM * init_vgmstream_ea_swvr(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
block_update_ea_swvr(start_offset, vgmstream);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -37,11 +37,10 @@ VGMSTREAM * init_vgmstream_ea_wve_ad10(STREAMFILE *streamFile) {
|
||||
|
||||
/* calc num_samples manually */
|
||||
{
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_ea_wve_ad10(start_offset,vgmstream);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
block_update_ea_wve_ad10(vgmstream->next_block_offset,vgmstream);
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wve"))
|
||||
/* .wve: common, .fsv: Future Cop LAPD (PS1) */
|
||||
if (!check_extensions(streamFile, "wve,fsv"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x564C4330) /* "VLC0" */
|
||||
goto fail;
|
||||
@ -41,18 +42,15 @@ VGMSTREAM * init_vgmstream_ea_wve_au00(STREAMFILE *streamFile) {
|
||||
|
||||
/* calc num_samples manually */
|
||||
{
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_ea_wve_au00(start_offset,vgmstream);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
/* ps_cfg_bytes_to_samples */
|
||||
vgmstream->num_samples += vgmstream->current_block_size / vgmstream->interleave_block_size*channel_count * 28 / channel_count;
|
||||
block_update_ea_wve_au00(vgmstream->next_block_offset,vgmstream);
|
||||
vgmstream->num_samples += ps_cfg_bytes_to_samples(vgmstream->current_block_size, vgmstream->interleave_block_size, 1);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
block_update_ea_wve_au00(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
|
@ -103,7 +103,7 @@ typedef struct {
|
||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
uint8_t scd_xor;
|
||||
off_t scd_xor_length;
|
||||
uint32_t sngw_xor;
|
||||
uint32_t xor_value;
|
||||
|
||||
} ogg_vorbis_meta_info_t;
|
||||
|
||||
@ -734,4 +734,8 @@ VGMSTREAM * init_vgmstream_ubi_lyn_container(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_msb_msh(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_txtp(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
@ -2075,14 +2075,16 @@ VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) {
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mcadpcm"))
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile)) /* dsp sizes */
|
||||
goto fail;
|
||||
|
||||
/* could validate dsp sizes but only with +1ch, should be done below in check_dsp_samples */
|
||||
//if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile))
|
||||
// goto fail;
|
||||
|
||||
channel_count = read_32bitLE(0x00,streamFile);
|
||||
if (channel_count > MCADPCM_MAX_CHANNELS) goto fail;
|
||||
|
||||
header_offset = read_32bitLE(0x04,streamFile);
|
||||
header_spacing = read_32bitLE(0x0c,streamFile) - header_offset; /* channel 2 start */
|
||||
header_spacing = channel_count == 1 ? 0 : read_32bitLE(0x0c,streamFile) - header_offset; /* channel 2 start, only with Nch */
|
||||
start_offset = header_offset + 0x60;
|
||||
interleave = header_spacing;
|
||||
|
||||
@ -2105,7 +2107,7 @@ VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->meta_type = meta_DSP_MCADPCM;
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
setup_vgmstream_dsp(vgmstream, ch_header);
|
||||
|
||||
|
@ -124,7 +124,7 @@ static void sngw_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, v
|
||||
char *header_id = "OggS";
|
||||
uint8_t key[4];
|
||||
|
||||
put_32bitBE(key, ov_streamfile->sngw_xor);
|
||||
put_32bitBE(key, ov_streamfile->xor_value);
|
||||
|
||||
/* bytes are xor'd with key and nibble-swapped */
|
||||
{
|
||||
@ -199,6 +199,17 @@ static void rpgmvo_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb,
|
||||
}
|
||||
}
|
||||
|
||||
static void eno_ogg_decryption_callback(void *ptr, size_t size, size_t nmemb, void *datasource) {
|
||||
size_t bytes_read = size*nmemb;
|
||||
ogg_vorbis_streamfile * const ov_streamfile = datasource;
|
||||
int i;
|
||||
|
||||
/* bytes are xor'd with key */
|
||||
for (i = 0; i < bytes_read; i++) {
|
||||
((uint8_t*)ptr)[i] ^= (uint8_t)ov_streamfile->xor_value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ogg Vorbis, by way of libvorbisfile; may contain loop comments */
|
||||
VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
@ -213,6 +224,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
int is_isd = 0;
|
||||
int is_l2sd = 0;
|
||||
int is_rpgmvo = 0;
|
||||
int is_eno = 0;
|
||||
|
||||
|
||||
/* check extension */
|
||||
@ -232,6 +244,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
is_isd = 1;
|
||||
} else if (check_extensions(streamFile,"rpgmvo")) { /* .rpgmvo: RPG Maker MV games (PC) */
|
||||
is_rpgmvo = 1;
|
||||
} else if (check_extensions(streamFile,"eno")) { /* .eno: Metronomicon (PC) */
|
||||
is_eno = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
@ -275,7 +289,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
/* check SNGW (Capcom's MT Framework PC games), may be encrypted */
|
||||
if (is_sngw) {
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4f676753) { /* "OggS" */
|
||||
ovmi.sngw_xor = read_32bitBE(0x00,streamFile);
|
||||
ovmi.xor_value = read_32bitBE(0x00,streamFile);
|
||||
ovmi.decryption_callback = sngw_ogg_decryption_callback;
|
||||
}
|
||||
}
|
||||
@ -304,6 +318,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
start_offset = 0x10;
|
||||
}
|
||||
|
||||
/* check ENO [Metronomicon (PC)] */
|
||||
if (is_eno) {
|
||||
/* first byte probably derives into xor key, but this works too */
|
||||
ovmi.xor_value = read_8bit(0x05,streamFile); /* always zero = easy key */
|
||||
ovmi.decryption_callback = eno_ogg_decryption_callback;
|
||||
start_offset = 0x01;
|
||||
}
|
||||
|
||||
|
||||
if (is_um3) {
|
||||
@ -320,6 +341,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
|
||||
ovmi.meta_type = meta_OGG_L2SD;
|
||||
} else if (is_rpgmvo) {
|
||||
ovmi.meta_type = meta_OGG_RPGMV;
|
||||
} else if (is_eno) {
|
||||
ovmi.meta_type = meta_OGG_ENO;
|
||||
} else {
|
||||
ovmi.meta_type = meta_OGG_VORBIS;
|
||||
}
|
||||
@ -371,7 +394,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
|
||||
temp_streamfile.decryption_callback = ovmi->decryption_callback;
|
||||
temp_streamfile.scd_xor = ovmi->scd_xor;
|
||||
temp_streamfile.scd_xor_length = ovmi->scd_xor_length;
|
||||
temp_streamfile.sngw_xor = ovmi->sngw_xor;
|
||||
temp_streamfile.xor_value = ovmi->xor_value;
|
||||
|
||||
/* open the ogg vorbis file for testing */
|
||||
memset(&temp_ovf, 0, sizeof(temp_ovf));
|
||||
@ -401,7 +424,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callb
|
||||
data->ov_streamfile.decryption_callback = ovmi->decryption_callback;
|
||||
data->ov_streamfile.scd_xor = ovmi->scd_xor;
|
||||
data->ov_streamfile.scd_xor_length = ovmi->scd_xor_length;
|
||||
data->ov_streamfile.sngw_xor = ovmi->sngw_xor;
|
||||
data->ov_streamfile.xor_value = ovmi->xor_value;
|
||||
|
||||
/* open the ogg vorbis file for real */
|
||||
if (ov_open_callbacks(&data->ov_streamfile, &data->ogg_vorbis_file, NULL, 0, *callbacks_p))
|
||||
|
@ -11,7 +11,7 @@ VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
|
||||
int channel_count, loop_flag = 0;
|
||||
off_t start_offset, loop_start_offset = 0;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile,"adm"))
|
||||
goto fail;
|
||||
|
||||
@ -34,7 +34,6 @@ VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->sample_rate = 44100;
|
||||
vgmstream->meta_type = meta_PS2_ADM;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_adm;
|
||||
|
||||
@ -42,22 +41,21 @@ VGMSTREAM * init_vgmstream_ps2_adm(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples as playable data size varies between files/blocks */
|
||||
vgmstream->num_samples = 0; //ps_bytes_to_samples(get_streamfile_size(streamFile), channel_count);
|
||||
block_update_adm(start_offset,vgmstream);
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile)) {
|
||||
if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
|
||||
vgmstream->loop_start_sample = vgmstream->num_samples;
|
||||
{
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size * channel_count, channel_count);
|
||||
if (loop_flag && vgmstream->current_block_offset == loop_start_offset)
|
||||
vgmstream->loop_start_sample = vgmstream->num_samples;
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
|
||||
block_update_adm(vgmstream->next_block_offset,vgmstream);
|
||||
if (loop_flag)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
|
||||
if (loop_flag)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
|
||||
block_update_adm(start_offset,vgmstream);
|
||||
return vgmstream;
|
||||
|
||||
|
@ -1,70 +1,55 @@
|
||||
#include "meta.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* IAB: Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */
|
||||
/* .IAB - from Runtime(?) games [Ueki no Housoku - Taosu ze Robert Juudan!! (PS2), RPG Maker 3 (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag = 0;
|
||||
int channel_count;
|
||||
int i;
|
||||
off_t start_offset;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("iab",filename_extension(filename))) goto fail;
|
||||
|
||||
/* check header */
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile,"iab"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x10000000)
|
||||
goto fail;
|
||||
|
||||
/* check file size */
|
||||
if (read_32bitLE(0x1C,streamFile) != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
|
||||
start_offset = 0x40;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
start_offset = 0x40;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x4,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
|
||||
vgmstream->layout_type = layout_blocked_ps2_iab;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0xC, streamFile);
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
vgmstream->meta_type = meta_PS2_IAB;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_blocked_ps2_iab;
|
||||
//vgmstream->interleave_block_size = read_32bitLE(0x0C, streamFile); /* unneeded */
|
||||
|
||||
/* open the file for reading by each channel */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
/* calc num_samples */
|
||||
{
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename, vgmstream->interleave_block_size);
|
||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
block_update_ps2_iab(vgmstream->next_block_offset, vgmstream);
|
||||
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
}
|
||||
|
||||
/* Calc num_samples */
|
||||
block_update_ps2_iab(start_offset, vgmstream);
|
||||
vgmstream->num_samples=0;
|
||||
|
||||
do
|
||||
{
|
||||
vgmstream->num_samples += 0x4000 * 14 / 16;
|
||||
block_update_ps2_iab(vgmstream->next_block_offset, vgmstream);
|
||||
} while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
|
||||
block_update_ps2_iab(start_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -71,8 +71,7 @@ VGMSTREAM * init_vgmstream_ps2_tk1(STREAMFILE *streamFile) {
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
/* checks */
|
||||
/* .ovb: actual extension, tk1: fake extension */
|
||||
if (!check_extensions(streamFile, "ovb,tk1"))
|
||||
if (!check_extensions(streamFile, "ovb"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x544B3553)
|
||||
|
66
src/meta/smc_smh.c
Normal file
66
src/meta/smc_smh.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* SMC+SMH - from Wangan Midnight 1/R (System246) */
|
||||
VGMSTREAM * init_vgmstream_smc_smh(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset, header_offset = 0;
|
||||
size_t stream_size;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "smc"))
|
||||
goto fail;
|
||||
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "smh");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
|
||||
total_subsongs = read_32bitLE(0x00,streamHeader);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
if (total_subsongs*0x10 + 0x10 != get_streamfile_size(streamHeader))
|
||||
goto fail;
|
||||
|
||||
header_offset = 0x10 + (target_subsong-1)*0x10;
|
||||
|
||||
start_offset = read_32bitLE(header_offset+0x00, streamHeader);
|
||||
stream_size = read_32bitLE(header_offset+0x04, streamHeader);
|
||||
sample_rate = read_32bitLE(header_offset+0x08, streamHeader);
|
||||
/* 0x0c(2): always 0x10, frame size? */
|
||||
channel_count = read_16bitLE(header_offset+0x0e, streamHeader);
|
||||
|
||||
loop_flag = 0;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = ps_bytes_to_samples(stream_size,channel_count);
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SMC_SMH;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x04, streamHeader);
|
||||
|
||||
|
||||
close_streamfile(streamHeader);
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -43,17 +43,16 @@ VGMSTREAM * init_vgmstream_sthd(STREAMFILE *streamFile) {
|
||||
int loop_end_block = (uint16_t)read_16bitLE(0x1c,streamFile);
|
||||
int block_count = 1; /* header block = 0 */
|
||||
|
||||
vgmstream->num_samples = 0;
|
||||
block_update_sthd(start_offset,vgmstream);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
do {
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
|
||||
if (block_count == loop_start_block)
|
||||
vgmstream->loop_start_sample = vgmstream->num_samples;
|
||||
if (block_count == loop_end_block)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->num_samples += xbox_ima_bytes_to_samples(vgmstream->current_block_size, 1);
|
||||
block_update_sthd(vgmstream->next_block_offset,vgmstream);
|
||||
|
||||
block_count++;
|
||||
}
|
||||
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
#include "../util.h"
|
||||
|
||||
#define TXT_LINE_MAX 0x2000
|
||||
|
||||
@ -82,6 +81,11 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
coding_t coding;
|
||||
int i, j;
|
||||
|
||||
|
||||
/* reject .txth as the CLI can open and decode with itself */
|
||||
if (check_extensions(streamFile, "txth"))
|
||||
goto fail;
|
||||
|
||||
/* no need for ID or ext checks -- if a .TXTH exists all is good
|
||||
* (player still needs to accept the streamfile's ext, so at worst rename to .vgmstream) */
|
||||
streamText = open_txth(streamFile);
|
||||
|
357
src/meta/txtp.c
Normal file
357
src/meta/txtp.c
Normal file
@ -0,0 +1,357 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
|
||||
#define TXT_LINE_MAX 0x2000
|
||||
|
||||
typedef struct {
|
||||
char filename[TXT_LINE_MAX];
|
||||
int subsong;
|
||||
uint32_t channel_mask;
|
||||
} txtp_entry;
|
||||
|
||||
typedef struct {
|
||||
txtp_entry *entry;
|
||||
size_t entry_count;
|
||||
size_t entry_max;
|
||||
|
||||
size_t loop_start_segment;
|
||||
size_t loop_end_segment;
|
||||
} txtp_header;
|
||||
|
||||
static txtp_header* parse_txtp(STREAMFILE* streamFile);
|
||||
static void clean_txtp(txtp_header* txtp);
|
||||
|
||||
|
||||
/* TXTP - an artificial playlist-like format to play segmented files with config */
|
||||
VGMSTREAM * init_vgmstream_txtp(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
txtp_header* txtp = NULL;
|
||||
segmented_layout_data *data = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "txtp"))
|
||||
goto fail;
|
||||
|
||||
/* read .txtp text file to get segments */
|
||||
txtp = parse_txtp(streamFile);
|
||||
if (!txtp) goto fail;
|
||||
|
||||
|
||||
if (txtp->entry_count == 0)
|
||||
goto fail;
|
||||
|
||||
|
||||
if (txtp->entry_count == 1 && !txtp->loop_start_segment) {
|
||||
/* single file */
|
||||
STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[0].filename);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_streamFile->stream_index = txtp->entry[0].subsong;
|
||||
|
||||
vgmstream = init_vgmstream_from_STREAMFILE(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->channel_mask = txtp->entry[0].channel_mask;
|
||||
}
|
||||
else {
|
||||
/* multi file */
|
||||
int num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
int i;
|
||||
int loop_flag, channel_count;
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_segmented(txtp->entry_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < txtp->entry_count; i++) {
|
||||
STREAMFILE* temp_streamFile = open_streamfile_by_filename(streamFile, txtp->entry[i].filename);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_streamFile->stream_index = txtp->entry[i].subsong;
|
||||
|
||||
data->segments[i] = init_vgmstream_from_STREAMFILE(temp_streamFile);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->channel_mask = txtp->entry[0].channel_mask;
|
||||
}
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
/* get looping and samples */
|
||||
if (txtp->loop_start_segment && !txtp->loop_end_segment)
|
||||
txtp->loop_end_segment = txtp->entry_count;
|
||||
loop_flag = (txtp->loop_start_segment > 0 && txtp->loop_start_segment <= txtp->entry_count);
|
||||
num_samples = 0;
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
|
||||
if (loop_flag && txtp->loop_start_segment == i+1) {
|
||||
loop_start_sample = num_samples;
|
||||
}
|
||||
|
||||
num_samples += data->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && txtp->loop_end_segment == i+1) {
|
||||
loop_end_sample = num_samples;
|
||||
}
|
||||
}
|
||||
|
||||
channel_count = data->segments[0]->channels;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = data->segments[0]->sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
|
||||
vgmstream->meta_type = meta_TXTP;
|
||||
vgmstream->coding_type = data->segments[0]->coding_type;
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
|
||||
vgmstream->layout_data = data;
|
||||
if (loop_flag)
|
||||
data->loop_segment = txtp->loop_start_segment-1;
|
||||
}
|
||||
|
||||
|
||||
clean_txtp(txtp);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
clean_txtp(txtp);
|
||||
close_vgmstream(vgmstream);
|
||||
free_layout_segmented(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int add_filename(txtp_header * txtp, char *filename) {
|
||||
int i;
|
||||
uint32_t channel_mask = 0;
|
||||
size_t range_start, range_end;
|
||||
|
||||
//;VGM_LOG("TXTP: filename=%s\n", filename);
|
||||
|
||||
/* parse config:
|
||||
* - file.ext#2 = play subsong 2
|
||||
* - file.ext#2~10 = play subsongs in 2 to 10 range
|
||||
* - file.ext#c1,2 = play channels 1,2 */
|
||||
{
|
||||
char *config;
|
||||
|
||||
/* position in base extension */
|
||||
config = strrchr(filename,'.');
|
||||
if (!config) /* needed...? */
|
||||
config = filename;
|
||||
|
||||
range_start = 0;
|
||||
range_end = 1;
|
||||
do {
|
||||
/* get config pointer but remove config from filename */
|
||||
config = strchr(config, '#');
|
||||
if (!config)
|
||||
continue;
|
||||
|
||||
config[0] = '\0';
|
||||
config++;
|
||||
|
||||
|
||||
if (config[0] == 'c') {
|
||||
/* mask channels */
|
||||
int n, ch;
|
||||
|
||||
config++;
|
||||
channel_mask = 0;
|
||||
while (sscanf(config, "%d%n", &ch,&n) == 1) {
|
||||
if (ch > 0 && ch < 32)
|
||||
channel_mask |= (1 << (ch-1));
|
||||
|
||||
config += n;
|
||||
if (config[0]== ',')
|
||||
config++;
|
||||
else if (config[0] != '\0')
|
||||
break;
|
||||
};
|
||||
}
|
||||
else {
|
||||
/* subsong range */
|
||||
int subsong_start = 0, subsong_end = 0;
|
||||
|
||||
if (sscanf(config, "%d~%d", &subsong_start, &subsong_end) == 2) {
|
||||
if (subsong_start > 0 && subsong_end > 0) {
|
||||
range_start = subsong_start-1;
|
||||
range_end = subsong_end-1;
|
||||
}
|
||||
}
|
||||
else if (sscanf(config, "%u", &subsong_start) == 1) {
|
||||
if (subsong_start > 0) {
|
||||
range_start = subsong_start-1;
|
||||
range_end = subsong_start;
|
||||
}
|
||||
}
|
||||
else {
|
||||
config = NULL; /* wrong config, ignore */
|
||||
}
|
||||
}
|
||||
|
||||
} while (config != NULL);
|
||||
|
||||
//;VGM_LOG("TXTP: config: range %i~%i, mask=%x\n", range_start, range_end, channel_mask);
|
||||
}
|
||||
|
||||
|
||||
/* hack to allow relative paths in various OSs */
|
||||
{
|
||||
char c;
|
||||
|
||||
i = 0;
|
||||
while ((c = filename[i]) != '\0') {
|
||||
if ((c == '\\' && DIR_SEPARATOR == '/') || (c == '/' && DIR_SEPARATOR == '\\'))
|
||||
filename[i] = DIR_SEPARATOR;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* add filesnames */
|
||||
for (i = range_start; i < range_end; i++){
|
||||
/* resize in steps if not enough */
|
||||
if (txtp->entry_count+1 > txtp->entry_max) {
|
||||
txtp_entry *temp_entry;
|
||||
|
||||
txtp->entry_max += 5;
|
||||
temp_entry = realloc(txtp->entry, sizeof(txtp_entry) * txtp->entry_max);
|
||||
if (!temp_entry) goto fail;
|
||||
txtp->entry = temp_entry;
|
||||
}
|
||||
|
||||
/* new entry */
|
||||
memset(&txtp->entry[txtp->entry_count],0, sizeof(txtp_entry));
|
||||
|
||||
strcpy(txtp->entry[txtp->entry_count].filename, filename);
|
||||
txtp->entry[txtp->entry_count].channel_mask = channel_mask;
|
||||
txtp->entry[txtp->entry_count].subsong = (i+1);
|
||||
txtp->entry_count++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_num(const char * val, uint32_t * out_value) {
|
||||
int hex = (val[0]=='0' && val[1]=='x');
|
||||
if (sscanf(val, hex ? "%x" : "%u", out_value)!=1)
|
||||
goto fail;
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_keyval(txtp_header * txtp, const char * key, const char * val) {
|
||||
//;VGM_LOG("TXTP: key %s = val %s\n", key,val);
|
||||
|
||||
if (0==strcmp(key,"loop_start_segment")) {
|
||||
if (!parse_num(val, &txtp->loop_start_segment)) goto fail;
|
||||
}
|
||||
else if (0==strcmp(key,"loop_end_segment")) {
|
||||
if (!parse_num(val, &txtp->loop_end_segment)) goto fail;
|
||||
}
|
||||
else {
|
||||
VGM_LOG("TXTP: unknown key=%s, val=%s\n", key,val);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 1;
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static txtp_header* parse_txtp(STREAMFILE* streamFile) {
|
||||
txtp_header* txtp = NULL;
|
||||
off_t txt_offset = 0x00;
|
||||
off_t file_size = get_streamfile_size(streamFile);
|
||||
|
||||
|
||||
txtp = calloc(1,sizeof(txtp_header));
|
||||
if (!txtp) goto fail;
|
||||
|
||||
|
||||
/* empty file: use filename with config (ex. "song.ext#3.txtp") */
|
||||
if (get_streamfile_size(streamFile) == 0) {
|
||||
char filename[PATH_LIMIT] = {0};
|
||||
char* ext;
|
||||
get_streamfile_filename(streamFile, filename,PATH_LIMIT);
|
||||
|
||||
/* remove ".txtp" */
|
||||
ext = strrchr(filename,'.');
|
||||
if (!ext) goto fail; /* ??? */
|
||||
ext[0] = '\0';
|
||||
|
||||
if (!add_filename(txtp, filename))
|
||||
goto fail;
|
||||
|
||||
return txtp;
|
||||
}
|
||||
|
||||
|
||||
/* skip BOM if needed */
|
||||
if (read_16bitLE(0x00, streamFile) == 0xFFFE || read_16bitLE(0x00, streamFile) == 0xFEFF)
|
||||
txt_offset = 0x02;
|
||||
|
||||
/* read lines */
|
||||
while (txt_offset < file_size) {
|
||||
char line[TXT_LINE_MAX] = {0};
|
||||
char key[TXT_LINE_MAX] = {0}, val[TXT_LINE_MAX] = {0}; /* at least as big as a line to avoid overflows (I hope) */
|
||||
char filename[TXT_LINE_MAX] = {0};
|
||||
int ok, bytes_read, line_done;
|
||||
|
||||
bytes_read = get_streamfile_text_line(TXT_LINE_MAX,line, txt_offset,streamFile, &line_done);
|
||||
if (!line_done) goto fail;
|
||||
|
||||
txt_offset += bytes_read;
|
||||
|
||||
/* get key/val (ignores lead/trail spaces, stops at space/comment/separator) */
|
||||
ok = sscanf(line, " %[^ \t#=] = %[^ \t#\r\n] ", key,val);
|
||||
if (ok == 2) { /* no key=val */
|
||||
if (!parse_keyval(txtp, key, val)) /* read key/val */
|
||||
goto fail;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* must be a filename (only remove spaces from start/end, as filenames con contain mid spaces/#/etc) */
|
||||
ok = sscanf(line, " %[^\t\r\n] ", filename);
|
||||
if (ok != 1) /* not a filename either */
|
||||
continue;
|
||||
if (filename[0] == '#')
|
||||
continue; /* simple comment */
|
||||
|
||||
/* filename with config */
|
||||
if (!add_filename(txtp, filename))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
return txtp;
|
||||
fail:
|
||||
clean_txtp(txtp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void clean_txtp(txtp_header* txtp) {
|
||||
if (!txtp)
|
||||
return;
|
||||
|
||||
free(txtp->entry);
|
||||
free(txtp);
|
||||
}
|
@ -40,6 +40,18 @@ VGMSTREAM * init_vgmstream_ubi_jade(STREAMFILE *streamFile) {
|
||||
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &data_offset,&data_size, 0, 0)) /* "data" */
|
||||
goto fail;
|
||||
|
||||
/* ignore LyN RIFF (needed as codec 0xFFFE is reused) */
|
||||
{
|
||||
off_t fact_offset;
|
||||
size_t fact_size;
|
||||
|
||||
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
/* Jade doesn't use "fact", though */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse format */
|
||||
{
|
||||
|
@ -397,6 +397,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_ubi_lyn,
|
||||
init_vgmstream_ubi_lyn_container,
|
||||
init_vgmstream_msb_msh,
|
||||
init_vgmstream_txtp,
|
||||
init_vgmstream_smc_smh,
|
||||
|
||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -477,7 +479,9 @@ static VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile) {
|
||||
#endif
|
||||
|
||||
/* save info */
|
||||
vgmstream->stream_index = streamFile->stream_index;
|
||||
/* stream_index 0 may be used by plugins to signal "vgmstream default" (IOW don't force to 1) */
|
||||
if (!vgmstream->stream_index)
|
||||
vgmstream->stream_index = streamFile->stream_index;
|
||||
|
||||
/* save start things so we can restart for seeking */
|
||||
memcpy(vgmstream->start_ch,vgmstream->ch,sizeof(VGMSTREAMCHANNEL)*vgmstream->channels);
|
||||
@ -932,6 +936,20 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* channel bitmask to silence non-set channels (up to 32)
|
||||
* can be used for 'crossfading subsongs' or layered channels, where a set of channels make a song section */
|
||||
if (vgmstream->channel_mask) {
|
||||
int ch,s;
|
||||
for (s = 0; s < sample_count; s++) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
if ((vgmstream->channel_mask >> ch) & 1)
|
||||
continue;
|
||||
buffer[s*vgmstream->channels + ch] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the number of samples of a single frame (smallest self-contained sample group, 1/N channels) */
|
||||
|
@ -667,6 +667,9 @@ typedef enum {
|
||||
meta_UBI_LYN, /* Ubisoft LyN engine [The Adventures of Tintin (multi)] */
|
||||
meta_MSB_MSH, /* sfx companion of MIH+MIB */
|
||||
meta_OGG_RPGMV, /* Ogg Vorbis with encryption [RPG Maker MV games (PC)] */
|
||||
meta_OGG_ENO, /* Ogg Vorbis with encryption [Metronomicon (PC)] */
|
||||
meta_TXTP, /* generic text playlist */
|
||||
meta_SMC_SMH, /* Wangan Midnight (System 246) */
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
meta_FFmpeg,
|
||||
@ -737,6 +740,7 @@ typedef struct {
|
||||
int stream_index; /* selected stream (also 1-based) */
|
||||
char stream_name[STREAM_NAME_SIZE]; /* name of the current stream (info), if the file stores it and it's filled */
|
||||
size_t stream_size; /* info to properly calculate bitrate */
|
||||
uint32_t channel_mask; /* to silence crossfading subsongs/layers */
|
||||
|
||||
/* looping */
|
||||
int loop_flag; /* is this stream looped? */
|
||||
@ -811,7 +815,7 @@ typedef struct {
|
||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
uint8_t scd_xor;
|
||||
off_t scd_xor_length;
|
||||
uint32_t sngw_xor;
|
||||
uint32_t xor_value;
|
||||
|
||||
} ogg_vorbis_streamfile;
|
||||
|
||||
|
@ -643,8 +643,10 @@ static int split_subsongs(const in_char * filename, int stream_index, VGMSTREAM
|
||||
HWND hPlaylistWindow;
|
||||
|
||||
|
||||
if (config.disable_subsongs || vgmstream->num_streams <= 1 || (vgmstream->num_streams > 1 && stream_index > 0))
|
||||
return 0; /* no split if no subsongs or playing a subsong */
|
||||
if (config.disable_subsongs || vgmstream->num_streams <= 1)
|
||||
return 0; /* don't split if no subsongs */
|
||||
if (stream_index > 0 || vgmstream->stream_index > 0)
|
||||
return 0; /* no split if already playing subsong */
|
||||
|
||||
hPlaylistWindow = (HWND)SendMessage(input_module.hMainWindow, WM_WA_IPC, IPC_GETWND_PE, IPC_GETWND);
|
||||
playlist_index = SendMessage(input_module.hMainWindow,WM_WA_IPC,0,IPC_GETLISTPOS);
|
||||
|
Loading…
Reference in New Issue
Block a user