Merge pull request #335 from bnnm/vs-mul-hca

vs mul hca
This commit is contained in:
Christopher Snowhill 2018-12-23 14:14:52 -08:00 committed by GitHub
commit f4551cda37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 530 additions and 380 deletions

View File

@ -87,8 +87,8 @@ mode = layers
```
### Channel mapping
TXTP can swap channels for custom channel mappings. Note that channel masking applies after mappings. Format is:
### Channel swapping/mapping
TXTP can swap channels for custom channel mappings. It does "swapping" rather than simpler "mapping" since vgmstream can't read a format's mappings or guess which channel is which. Format is:
```
#ch1 = first
file1.ext#m2-3 # "FL BL FR BR" to "FL FR BL BR"
@ -96,6 +96,7 @@ file1.ext#m2-3 # "FL BL FR BR" to "FL FR BL BR"
#do note the order specified affects swapping
file2.ext#m2-3,4-5,4-6 # ogg "FL CN FR BL BR SB" to wav "FL FR CN SB BL BR"
```
Note that channel masking applies after mappings.
### Custom play settings

View File

@ -9,8 +9,9 @@ static const int EA_XA_TABLE[20] = {
0, -1, -3, -4
};
/* EA-XAS, evolution of EA-XA and cousin of MTA2. Layout: blocks of 0x4c per channel (128 samples),
* divided into 4 headers + 4 vertical groups of 15 bytes (for parallelism?).
/* EA-XAS, evolution of EA-XA and cousin of MTA2. From FFmpeg (general info) + MTA2 (layout) + EA-XA (decoding)
*
* Layout: blocks of 0x4c per channel (128 samples), divided into 4 headers + 4 vertical groups of 15 bytes (for parallelism?).
* To simplify, always decodes the block and discards unneeded samples, so doesn't use external hist. */
void decode_ea_xas(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
int group, row, i;

View File

@ -151,15 +151,22 @@ void free_hca(hca_codec_data * data) {
}
#define HCA_KEY_MAX_BLANK_FRAMES 15 /* ignored up to N blank frames (not uncommon to have ~10, if more something is off) */
#define HCA_KEY_MAX_TEST_FRAMES 10 /* 5~15 should be enough, but mostly silent or badly mastered files may need more */
#define HCA_KEY_MAX_ACCEPTABLE_SCORE 150 /* more is unlikely to work correctly, 10~30 isn't uncommon */
/* arbitrary scale to simplify score comparisons */
#define HCA_KEY_SCORE_SCALE 10
/* ignores beginning frames (~10 is not uncommon, Dragalia Lost vocal layers have lots) */
#define HCA_KEY_MAX_SKIP_BLANKS 1200
/* 5~15 should be enough, but almost silent or badly mastered files may need tweaks */
#define HCA_KEY_MIN_TEST_FRAMES 5
#define HCA_KEY_MAX_TEST_FRAMES 10
/* score of 10~30 isn't uncommon in a single frame, too many frames over that is unlikely */
#define HCA_KEY_MAX_FRAME_SCORE 150
#define HCA_KEY_MAX_TOTAL_SCORE (HCA_KEY_MAX_TEST_FRAMES * 50*HCA_KEY_SCORE_SCALE)
/* Test a number of frames if key decrypts correctly.
* Returns score: <0: error/wrong, 0: unknown/silent file, >0: good (the closest to 1 the better). */
int test_hca_key(hca_codec_data * data, unsigned long long keycode) {
size_t test_frame = 0, current_frame = 0, blank_frames = 0;
int total_score = 0;
size_t test_frames = 0, current_frame = 0, blank_frames = 0;
int total_score = 0, found_regular_frame = 0;
const unsigned int blockSize = data->info.blockSize;
/* Due to the potentially large number of keys this must be tuned for speed.
@ -168,43 +175,56 @@ int test_hca_key(hca_codec_data * data, unsigned long long keycode) {
clHCA_SetKey(data->handle, keycode);
while (test_frame < HCA_KEY_MAX_TEST_FRAMES && current_frame < data->info.blockCount) {
/* Test up to N non-blank frames or until total frames. */
/* A final score of 0 (=silent) is only possible for short files with all blank frames */
while (test_frames < HCA_KEY_MAX_TEST_FRAMES && current_frame < data->info.blockCount) {
off_t offset = data->info.headerSize + current_frame * blockSize;
int score;
size_t bytes;
/* read frame */
/* read and test frame */
bytes = read_streamfile(data->data_buffer, offset, blockSize, data->streamfile);
if (bytes != blockSize) {
total_score = -1;
break;
}
/* test frame */
score = clHCA_TestBlock(data->handle, (void*)(data->data_buffer), blockSize);
if (score < 0) {
if (score < 0 || score > HCA_KEY_MAX_FRAME_SCORE) {
total_score = -1;
break;
}
current_frame++;
/* skip blank block at the beginning */
if (score == 0 && blank_frames < HCA_KEY_MAX_BLANK_FRAMES) {
/* ignore silent frames at the beginning, up to a point */
if (score == 0 && blank_frames < HCA_KEY_MAX_SKIP_BLANKS && !found_regular_frame) {
blank_frames++;
continue;
}
test_frame++;
found_regular_frame = 1;
test_frames++;
/* scale values to make scores of perfect frames more detectable */
switch(score) {
case 1: score = 1; break;
case 0: score = 3*HCA_KEY_SCORE_SCALE; break; /* blanks after non-blacks aren't very trustable */
default: score = score*HCA_KEY_SCORE_SCALE;
}
total_score += score;
/* too far, don't bother checking more frames */
if (total_score > HCA_KEY_MAX_ACCEPTABLE_SCORE)
/* don't bother checking more frames, other keys will get better scores */
if (total_score > HCA_KEY_MAX_TOTAL_SCORE)
break;
}
//;VGM_LOG("HCA KEY: blanks=%i, tests=%i, score=%i\n", blank_frames, test_frames, total_score);
/* signal best possible score */
if (total_score > 0 && total_score <= HCA_KEY_MAX_TEST_FRAMES) {
/* signal best possible score (many perfect frames and few blank frames) */
if (test_frames > HCA_KEY_MIN_TEST_FRAMES && total_score > 0 && total_score <= test_frames) {
total_score = 1;
}

View File

@ -113,20 +113,28 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
frame_size = read_16bitBE(stream->offset+0x06,stream->streamfile); /* not including this header */
/* 0x08(8): null */
/* EOF: 0-fill buffer (or, as track_channels = 0 > divs by 0) */
if (num_track < 0) {
VGM_ASSERT(frame_size == 0, "MTA2: empty frame at %x\n", (uint32_t)stream->offset);
/* frame_size 0 means silent/empty frame (rarely found near EOF for one track but not others)
* negative track only happens for truncated files (EOF) */
if (frame_size == 0 || num_track < 0) {
for (i = 0; i < samples_to_do; i++)
outbuf[i * channelspacing] = 0;
stream->offset += 0x10;
return;
}
track_channels = 0;
for (i = 0; i < 8; i++) {
if ((channel_layout >> i) & 0x01)
track_channels++;
}
if (track_channels == 0) { /* bad data, avoid div by 0 */
VGM_LOG("track_channels 0 at %x\n", (uint32_t)stream->offset);
return;
}
/* assumes tracks channels are divided evenly in all tracks (ex. not 2ch + 1ch + 1ch) */
if (channel / track_channels == num_track)
break; /* channel belongs to this track */

View File

@ -129,7 +129,7 @@ static const char* extension_list[] = {
"e4x",
"eam",
"eda", //txth/reserved [Project Eden (PS2)]
"emff",
"emff", //fake extension for .mul (to be removed)
"enm",
"eno",
"ens",
@ -175,6 +175,7 @@ static const char* extension_list[] = {
"idx",
"ikm",
"ild",
"imc",
"int",
"isd",
"isws",
@ -249,6 +250,7 @@ static const char* extension_list[] = {
"msvp",
"mta2",
"mtaf",
"mul",
"mus",
"musc",
"musx",
@ -681,9 +683,8 @@ static const layout_info layout_info_list[] = {
{layout_blocked_ws_aud, "blocked (Westwood Studios .aud)"},
{layout_blocked_matx, "blocked (Matrix .matx)"},
{layout_blocked_dec, "blocked (DEC)"},
{layout_blocked_vs, "blocked (vs)"},
{layout_blocked_emff_ps2, "blocked (EMFF PS2)"},
{layout_blocked_emff_ngc, "blocked (EMFF NGC)"},
{layout_blocked_vs, "blocked (Melbourne House VS)"},
{layout_blocked_mul, "blocked (MUL)"},
{layout_blocked_gsb, "blocked (GSB)"},
{layout_blocked_thp, "blocked (THP Movie Audio)"},
{layout_blocked_filp, "blocked (FILP)"},
@ -692,7 +693,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_bdsp, "blocked (BDSP)"},
{layout_blocked_ivaud, "blocked (IVAUD)"},
{layout_blocked_ps2_iab, "blocked (IAB)"},
{layout_blocked_ps2_strlr, "blocked (The Bouncer STR)"},
{layout_blocked_vs_str, "blocked (STR VS)"},
{layout_blocked_rws, "blocked (RWS)"},
{layout_blocked_hwas, "blocked (HWAS)"},
{layout_blocked_tra, "blocked (TRA)"},
@ -706,7 +707,7 @@ static const layout_info layout_info_list[] = {
{layout_blocked_sthd, "blocked (STHD)"},
{layout_blocked_h4m, "blocked (H4M)"},
{layout_blocked_xa_aiff, "blocked (XA AIFF)"},
{layout_blocked_vs_ffx, "blocked (Square VS)"},
{layout_blocked_vs_square, "blocked (Square VS)"},
};
static const meta_info meta_info_list[] = {
@ -832,7 +833,7 @@ static const meta_info meta_info_list[] = {
{meta_NGC_WVS, "Metal Arms WVS Header (GameCube)"},
{meta_XBOX_MATX, "assumed Matrix file by .matx extension"},
{meta_DEC, "Falcom DEC RIFF header"},
{meta_VS, "Men in Black VS Header"},
{meta_VS, "Melbourne House .VS header"},
{meta_DC_STR, "Sega Stream Asset Builder header"},
{meta_DC_STR_V2, "variant of Sega Stream Asset Builder header"},
{meta_XBOX_XMU, "XMU header"},
@ -888,8 +889,7 @@ static const meta_info meta_info_list[] = {
{meta_VGS, "Guitar Hero VGS Header"},
{meta_DC_DCSW_DCS, "Evil Twin DCS file with helper"},
{meta_WII_SMP, "SMP DSP Header"},
{meta_EMFF_PS2, "Eidos Music File Format Header"},
{meta_EMFF_NGC, "Eidos Music File Format Header"},
{meta_MUL, "Crystal Dynamics .MUL header"},
{meta_THP, "THP Movie File Format Header"},
{meta_STS_WII, "Shikigami no Shiro (WII) Header"},
{meta_PS2_P2BT, "Pop'n'Music 7 Header"},
@ -908,7 +908,7 @@ static const meta_info meta_info_list[] = {
{meta_ADS, "dhSS Header"},
{meta_PS2_MCG, "Gunvari MCG Header"},
{meta_ZSD, "ZSD Header"},
{meta_RedSpark, "RedSpark Header"},
{meta_REDSPARK, "RedSpark Header"},
{meta_IVAUD, "Rockstar .ivaud header"},
{meta_DSP_WII_WSD, ".WSD header"},
{meta_WII_NDP, "Icon Games NDP header"},
@ -986,7 +986,7 @@ static const meta_info meta_info_list[] = {
{meta_X360_TRA, "Terminal Reality .TRA raw header"},
{meta_PS2_VGS, "Princess Soft VGS header"},
{meta_PS2_IAB, "Runtime .IAB header"},
{meta_PS2_STRLR, "The Bouncer STR header"},
{meta_VS_STR, "Square .VS STR* header"},
{meta_LSF_N1NJ4N, ".lsf !n1nj4n header"},
{meta_VAWX, "feelplus VAWX header"},
{meta_PC_SNDS, "assumed Heavy Iron IMA by .snds extension"},
@ -1126,7 +1126,7 @@ static const meta_info meta_info_list[] = {
{meta_XWMA, "Microsoft XWMA RIFF header"},
{meta_VA3, "Konami VA3 header" },
{meta_XOPUS, "Exient XOPUS header"},
{meta_VS_FFX, "Square VS header"},
{meta_VS_SQUARE, "Square VS header"},
{meta_NWAV, "Chunsoft NWAV header"},
{meta_XPCM, "Circus XPCM header"},
{meta_MSF_TAMASOFT, "Tama-Soft MSF header"},
@ -1134,6 +1134,7 @@ static const meta_info meta_info_list[] = {
{meta_ZSND, "Vicarious Visions ZSND header"},
{meta_DSP_ADPCMX, "AQUASTYLE ADPY header"},
{meta_OGG_OPUS, "Ogg Opus header"},
{meta_IMC, "iNiS .IMC header"},
};

View File

@ -127,11 +127,8 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_dec:
block_update_dec(block_offset,vgmstream);
break;
case layout_blocked_emff_ps2:
block_update_emff_ps2(block_offset,vgmstream);
break;
case layout_blocked_emff_ngc:
block_update_emff_ngc(block_offset,vgmstream);
case layout_blocked_mul:
block_update_mul(block_offset,vgmstream);
break;
case layout_blocked_gsb:
block_update_gsb(block_offset,vgmstream);
@ -166,8 +163,8 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_ps2_iab:
block_update_ps2_iab(block_offset,vgmstream);
break;
case layout_blocked_ps2_strlr:
block_update_ps2_strlr(block_offset,vgmstream);
case layout_blocked_vs_str:
block_update_vs_str(block_offset,vgmstream);
break;
case layout_blocked_rws:
block_update_rws(block_offset,vgmstream);
@ -205,8 +202,8 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
case layout_blocked_xa_aiff:
block_update_xa_aiff(block_offset,vgmstream);
break;
case layout_blocked_vs_ffx:
block_update_vs_ffx(block_offset,vgmstream);
case layout_blocked_vs_square:
block_update_vs_square(block_offset,vgmstream);
break;
default: /* not a blocked layout */
break;

View File

@ -1,34 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitLE(
vgmstream->current_block_offset+0x10,
vgmstream->ch[0].streamfile);
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x20;
vgmstream->current_block_size/=vgmstream->channels;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x20+(vgmstream->current_block_size*i);
}
}
void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitBE(
vgmstream->current_block_offset+0x20,
vgmstream->ch[0].streamfile);
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size+0x40;
vgmstream->current_block_size/=vgmstream->channels;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset+0x40+(vgmstream->current_block_size*i);
}
}

50
src/layout/blocked_mul.c Normal file
View File

@ -0,0 +1,50 @@
#include "layout.h"
#include "../vgmstream.h"
/* process headered blocks with sub-headers */
void block_update_mul(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i, block_type;
size_t block_size, block_header, data_size, data_header;
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
block_type = read_32bit(block_offset + 0x00,streamFile);
block_size = read_32bit(block_offset + 0x04,streamFile); /* not including main header */
switch(vgmstream->coding_type) {
case coding_NGC_DSP:
block_header = 0x20;
data_header = 0x20;
break;
default:
block_header = 0x10;
data_header = 0x10;
break;
}
if (block_type == 0x00 && block_size == 0) {
/* oddity in some vid+audio files? bad extraction? */
block_header = 0x10;
data_header = 0x00;
data_size = 0;
}
if (block_type == 0x00 && block_size != 0) {
/* read audio sub-header */
data_size = read_32bit(block_offset + block_header + 0x00,streamFile);
}
else {
/* non-audio or empty audio block */
data_header = 0x00;
data_size = 0;
}
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = data_size / vgmstream->channels;
vgmstream->next_block_offset = block_offset + block_header + block_size;
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->ch[i].offset = block_offset + block_header + data_header + vgmstream->current_block_size*i;
//VGM_LOG("ch%i of=%lx\n", i, vgmstream->ch[i].offset);
}
//getchar();
}

View File

@ -1,17 +1,16 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
/* mini-blocks of size + data */
void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i;
for (i=0;i<vgmstream->channels;i++) {
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitLE(
vgmstream->current_block_offset,
vgmstream->ch[0].streamfile);
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 0x4;
vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x4;
if(i==0) block_offset=vgmstream->next_block_offset;
for (i = 0; i < vgmstream->channels; i++) {
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitLE(vgmstream->current_block_offset,streamFile);
vgmstream->next_block_offset = vgmstream->current_block_offset + vgmstream->current_block_size + 0x04;
vgmstream->ch[i].offset = vgmstream->current_block_offset + 0x04;
if (i == 0) block_offset=vgmstream->next_block_offset;
}
}

View File

@ -2,13 +2,13 @@
#include "../vgmstream.h"
/* Square "VS" headered blocks */
void block_update_vs_ffx(off_t block_offset, VGMSTREAM * vgmstream) {
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
size_t block_size = 0x800;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = block_size - 0x20;
vgmstream->next_block_offset = block_offset + block_size;
vgmstream->next_block_offset = block_offset + block_size*vgmstream->channels;
/* 0x08: number of remaning blocks, 0x0c: blocks left */
for (i = 0; i < vgmstream->channels; i++) {

View File

@ -2,7 +2,7 @@
#include "../vgmstream.h"
/* The Bouncer STRx blocks, one block per channel when stereo */
void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream) {
void block_update_vs_str(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i;

View File

@ -21,8 +21,7 @@ void block_update_ws_aud(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_matx(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_dec(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_emff_ps2(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_emff_ngc(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_mul(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_gsb(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_xvas(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_thp(off_t block_offset, VGMSTREAM * vgmstream);
@ -33,7 +32,7 @@ void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_bdsp(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_tra(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ps2_iab(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ps2_strlr(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_str(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_rws(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_hwas(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream);
@ -46,7 +45,7 @@ void block_update_ea_wve_ad10(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_sthd(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_ffx(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

View File

@ -525,7 +525,7 @@
>
</File>
<File
RelativePath=".\meta\emff.c"
RelativePath=".\meta\mul.c"
>
</File>
<File
@ -619,6 +619,10 @@
<File
RelativePath=".\meta\nub_idsp.c"
>
</File>
<File
RelativePath=".\meta\imc.c"
>
</File>
<File
RelativePath=".\meta\ios_psnd.c"
@ -1175,7 +1179,7 @@
>
</File>
<File
RelativePath=".\meta\ps2_strlr.c"
RelativePath=".\meta\vs_str.c"
>
</File>
<File
@ -1227,7 +1231,7 @@
>
</File>
<File
RelativePath=".\meta\vs_ffx.c"
RelativePath=".\meta\vs_square.c"
>
</File>
<File
@ -2007,7 +2011,7 @@
>
</File>
<File
RelativePath=".\layout\blocked_vs_ffx.c"
RelativePath=".\layout\blocked_vs_square.c"
>
</File>
<File
@ -2031,7 +2035,7 @@
>
</File>
<File
RelativePath=".\layout\blocked_emff.c"
RelativePath=".\layout\blocked_mul.c"
>
</File>
<File
@ -2079,7 +2083,7 @@
>
</File>
<File
RelativePath=".\layout\blocked_ps2_strlr.c"
RelativePath=".\layout\blocked_vs_str.c"
>
</File>
<File

View File

@ -134,7 +134,7 @@
<ClCompile Include="coding\mtaf_decoder.c" />
<ClCompile Include="coding\mta2_decoder.c" />
<ClCompile Include="layout\blocked_ps2_iab.c" />
<ClCompile Include="layout\blocked_ps2_strlr.c" />
<ClCompile Include="layout\blocked_vs_str.c" />
<ClCompile Include="layout\layered.c" />
<ClCompile Include="layout\blocked_tra.c" />
<ClCompile Include="meta\akb.c" />
@ -146,6 +146,7 @@
<ClCompile Include="meta\ezw.c" />
<ClCompile Include="meta\ffmpeg.c" />
<ClCompile Include="meta\g1l.c" />
<ClCompile Include="meta\imc.c" />
<ClCompile Include="meta\ios_psnd.c" />
<ClCompile Include="meta\ktss.c" />
<ClCompile Include="meta\lsf.c" />
@ -170,7 +171,7 @@
<ClCompile Include="meta\mss.c" />
<ClCompile Include="meta\ps2_mtaf.c" />
<ClCompile Include="meta\ps2_spm.c" />
<ClCompile Include="meta\ps2_strlr.c" />
<ClCompile Include="meta\vs_str.c" />
<ClCompile Include="meta\ps2_wmus.c" />
<ClCompile Include="meta\ps3_ivag.c" />
<ClCompile Include="meta\ps3_past.c" />
@ -251,7 +252,7 @@
<ClCompile Include="meta\ea_eaac.c" />
<ClCompile Include="meta\ea_wve_au00.c" />
<ClCompile Include="meta\ea_wve_ad10.c" />
<ClCompile Include="meta\emff.c" />
<ClCompile Include="meta\mul.c" />
<ClCompile Include="meta\exakt_sc.c" />
<ClCompile Include="meta\ffw.c" />
<ClCompile Include="meta\flx.c" />
@ -398,7 +399,7 @@
<ClCompile Include="meta\ps2_vms.c" />
<ClCompile Include="meta\ps2_voi.c" />
<ClCompile Include="meta\vpk.c" />
<ClCompile Include="meta\vs_ffx.c" />
<ClCompile Include="meta\vs_square.c" />
<ClCompile Include="meta\ps2_wad.c" />
<ClCompile Include="meta\ps2_wb.c" />
<ClCompile Include="meta\ps2_xa2.c" />
@ -546,7 +547,7 @@
<ClCompile Include="layout\blocked_awc.c" />
<ClCompile Include="layout\blocked_ea_1snh.c" />
<ClCompile Include="layout\blocked_vgs.c" />
<ClCompile Include="layout\blocked_vs_ffx.c" />
<ClCompile Include="layout\blocked_vs_square.c" />
<ClCompile Include="layout\blocked_vawx.c" />
<ClCompile Include="layout\blocked_xvag.c" />
<ClCompile Include="layout\blocked_caf.c" />
@ -555,7 +556,7 @@
<ClCompile Include="layout\blocked_ea_sns.c" />
<ClCompile Include="layout\blocked_ea_wve_au00.c" />
<ClCompile Include="layout\blocked_ea_wve_ad10.c" />
<ClCompile Include="layout\blocked_emff.c" />
<ClCompile Include="layout\blocked_mul.c" />
<ClCompile Include="layout\blocked_filp.c" />
<ClCompile Include="layout\blocked_gsb.c" />
<ClCompile Include="layout\blocked_h4m.c" />

View File

@ -334,7 +334,7 @@
<ClCompile Include="meta\ea_wve_ad10.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\emff.c">
<ClCompile Include="meta\mul.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\exakt_sc.c">
@ -760,7 +760,7 @@
<ClCompile Include="meta\vpk.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\vs_ffx.c">
<ClCompile Include="meta\vs_square.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_wad.c">
@ -1192,7 +1192,7 @@
<ClCompile Include="layout\blocked_vgs.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_vs_ffx.c">
<ClCompile Include="layout\blocked_vs_square.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_vawx.c">
@ -1213,7 +1213,7 @@
<ClCompile Include="layout\blocked_ea_sns.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_emff.c">
<ClCompile Include="layout\blocked_mul.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_filp.c">
@ -1303,7 +1303,7 @@
<ClCompile Include="meta\ps2_spm.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ps2_strlr.c">
<ClCompile Include="meta\vs_str.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wii_ras.c">
@ -1315,7 +1315,7 @@
<ClCompile Include="meta\ps2_iab.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_ps2_strlr.c">
<ClCompile Include="layout\blocked_vs_str.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_ps2_iab.c">
@ -1360,6 +1360,9 @@
<ClCompile Include="meta\ios_psnd.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\imc.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\pc_adp.c">
<Filter>meta\Source Files</Filter>
</ClCompile>

View File

@ -1,179 +0,0 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util.h"
/* EMFF - Eidos Music File Format (PS2),
Legacy of Kain - Defiance, possibly more... */
VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
int frequency;
int i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("emff",filename_extension(filename))) goto fail;
/* do some checks on the file, cause we have no magic words to check the header...
it seems if 0x800 and 0x804 = 0 then the file has only audio, if 0x800 = 1
it has a text section, if both are 1 it's video with a text section included... */
if (read_32bitBE(0x800,streamFile) == 0x01000000 || /* "0x01000000" */
read_32bitBE(0x804,streamFile) == 0x01000000) /* "0x01000000" */
goto fail;
frequency = read_32bitLE(0x0,streamFile);
channel_count = read_32bitLE(0xC,streamFile);
if (frequency > 48000 ||
channel_count > 8) {
goto fail;
}
loop_flag = (read_32bitLE(0x4,streamFile) != 0xFFFFFFFF);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x800;
vgmstream->sample_rate = frequency;
vgmstream->channels = channel_count;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_emff_ps2;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_EMFF_PS2;
/* open the file for reading */
{
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
}
}
/* Calc num_samples */
block_update_emff_ps2(start_offset,vgmstream);
vgmstream->num_samples = read_32bitLE(0x8,streamFile);
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x28,streamFile)-start_offset)*28/16/channel_count;
vgmstream->loop_end_sample = read_32bitLE(0x8,streamFile);
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* EMFF - Eidos Music File Format (NGC/WII),
found in Tomb Raider Legend/Anniversary/Underworld, possibly more... */
VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
int frequency;
int i;
int j;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("emff",filename_extension(filename))) goto fail;
/* do some checks on the file, cause we have no magic words to check the header...
it seems if 0x800 and 0x804 = 0 then the file has only audio, if 0x800 = 1
it has a text section, if both are 1 it's video with a text section included... */
if (read_32bitBE(0x800,streamFile) == 0x00000001 || /* "0x00000001" */
read_32bitBE(0x804,streamFile) == 0x00000001) /* "0x00000001" */
goto fail;
frequency = read_32bitBE(0x0,streamFile);
channel_count = read_32bitBE(0xC,streamFile);
if (frequency > 48000 ||
channel_count > 8) {
goto fail;
}
loop_flag = (read_32bitBE(0x4,streamFile) != 0xFFFFFFFF);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x800;
vgmstream->sample_rate = frequency;
vgmstream->channels = channel_count;
vgmstream->coding_type = coding_NGC_DSP;
/* Retrieving coefs and loops, depending on the file layout... */
/* Found in Tomb Raider - Legend for GameCube */
if (read_32bitBE(0xC8,streamFile) > 0x0) {
off_t coef_table[8] = {0xC8,0xF6,0x124,0x152,0x180,0x1AE,0x1DC,0x20A};
for (j=0;j<vgmstream->channels;j++) {
for (i=0;i<16;i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
}
}
/* Found in Tomb Raider - Anniversary for WII */
} else if (read_32bitBE(0xCC,streamFile) > 0x0) {
off_t coef_table[8] = {0xCC,0xFA,0x128,0x156,0x184,0x1B2,0x1E0,0x20E};
for (j=0;j<vgmstream->channels;j++) {
for (i=0;i<16;i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
}
}
/* Found in Tomb Raider - Underworld for WII */
} else if (read_32bitBE(0x2D0,streamFile) > 0x0) {
off_t coef_table[8] = {0x2D0,0x2FE,0x32C,0x35A,0x388,0x3B6,0x3E4,0x412};
for (j=0;j<vgmstream->channels;j++) {
for (i=0;i<16;i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_table[j]+i*2,streamFile);
}
}
} else {
goto fail;
}
vgmstream->layout_type = layout_blocked_emff_ngc;
vgmstream->interleave_block_size = 0x10;
vgmstream->meta_type = meta_EMFF_NGC;
/* open the file for reading */
{
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
}
}
/* Calc num_samples */
block_update_emff_ngc(start_offset,vgmstream);
vgmstream->num_samples = read_32bitBE(0x8,streamFile);;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x28,streamFile))*14/8/channel_count;
vgmstream->loop_end_sample = read_32bitBE(0x8,streamFile);
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -88,8 +88,8 @@ static inline void test_key(hca_codec_data * hca_data, uint64_t key, uint16_t su
if (score < 0)
return;
/* score 0 is not trustable, update too if something better is found */
if (*best_score < 0 || (score < *best_score && score > 0) || (*best_score == 0 && score == 1)) {
/* update if something better is found */
if (*best_score <= 0 || (score < *best_score && score > 0)) {
*best_score = score;
*best_keycode = key;
}

View File

@ -228,7 +228,7 @@ static const hcakey_info hcakey_list[] = {
// Taga Tame no Alchemist (iOS/Android)
{5047159794308}, // 00000497222AAA84
// Shin Tennis no Ouji-sama: Rising Beat (iOS/Android)
// Shin Tennis no Ouji-sama: Rising Beat (iOS/Android) voices?
{4902201417679}, // 0000047561F95FCF
// Kai-ri-Sei Million Arthur (Vita)

130
src/meta/imc.c Normal file
View File

@ -0,0 +1,130 @@
#include "meta.h"
#include "../coding/coding.h"
/* .IMC - from iNiS Gitaroo Man (PS2) */
VGMSTREAM * init_vgmstream_imc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, sample_rate, interleave, blocks;
size_t file_size, data_size;
/* checks */
/* .imc: extension from the main container */
if (!check_extensions(streamFile, "imc"))
goto fail;
channel_count = read_32bitLE(0x00, streamFile);
sample_rate = read_32bitLE(0x04, streamFile);
interleave = read_32bitLE(0x08, streamFile) * 0x10; /* number of frames in a block */
blocks = read_32bitLE(0x0c, streamFile); /* number of interleave blocks (even in mono) */
file_size = get_streamfile_size(streamFile);
loop_flag = 0;
start_offset = 0x10;
VGM_LOG("3\n");
/* extra checks since the header is so simple */
if (channel_count < 1 || channel_count > 8 || sample_rate < 22000 || sample_rate > 48000)
goto fail;
VGM_LOG("4\n");
if (interleave*blocks + start_offset != file_size)
goto fail;
VGM_LOG("5\n");
/* remove padding (important to play gapless subsongs, happens even for mono) */
{
off_t min_offset = file_size - interleave;
off_t offset = file_size - 0x10;
data_size = file_size - start_offset;
while (offset > min_offset) {
if (read_32bitLE(offset, streamFile) != 0)
break;
data_size -= 0x10*channel_count;
offset -= 0x10;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_IMC;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* ****************************************************************************** */
/* .IMC in containers */
VGMSTREAM * init_vgmstream_imc_container(STREAMFILE *streamFile) {
VGMSTREAM *vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t header_offset, subfile_offset, next_offset, name_offset;
uint32_t flags1, flags2;
size_t subfile_size;
int total_subsongs, target_subsong = streamFile->stream_index;
/* checks */
if (!check_extensions(streamFile, "imc"))
goto fail;
total_subsongs = read_32bitLE(0x00, streamFile);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
header_offset = 0x04 + 0x20*(target_subsong-1);
name_offset = header_offset + 0x00;
//flags1 = (uint32_t)read_32bitLE(header_offset + 0x08, streamFile);
/* 0x0c: same for all songs in single .imc but varies between .imc */
subfile_offset = read_32bitLE(header_offset + 0x10,streamFile);
//flags2 = (uint32_t)read_32bitLE(header_offset + 0x14, streamFile);
/* 0x18: same for all songs in single .imc but varies between .imc */
/* 0x1c: flags? (0 or 2) */
//VGM_LOG("1: %x, %x\n", flags1, flags2);
// if (!(flags1 == 0x77DE2A70 || flags1 == 0x77DE2A00 || flags1 == 0x00000020 || flags1 == 0x00000000))
// goto fail;
// if (!(flags2 == 0x0000F095 || flags2 == 0x0012FA3C))
// goto fail;
//VGM_LOG("2\n");
if (target_subsong == total_subsongs) {
next_offset = get_streamfile_size(streamFile);
}
else {
next_offset = read_32bitLE(header_offset + 0x20 + 0x10,streamFile);
}
subfile_size = next_offset - subfile_offset;
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
if (!temp_streamFile) goto fail;
vgmstream = init_vgmstream_imc(temp_streamFile);
if (!vgmstream) goto fail;
close_streamfile(temp_streamFile);
vgmstream->num_streams = total_subsongs;
read_string(vgmstream->stream_name,0x08+1, name_offset,streamFile);
return vgmstream;
fail:
close_streamfile(temp_streamFile);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -361,8 +361,7 @@ VGMSTREAM * init_vgmstream_dc_dcsw_dcs(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wii_smp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_emff_ps2(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_emff_ngc(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_mul(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_thp(STREAMFILE *streamFile);
@ -401,7 +400,7 @@ VGMSTREAM * init_vgmstream_zsd(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ps2_vgs(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_RedSpark(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_redspark(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_ivaud(STREAMFILE *streamFile);
@ -534,7 +533,7 @@ VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_iab(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_vs_str(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_lsf_n1nj4n(STREAMFILE* streamFile);
@ -802,7 +801,7 @@ VGMSTREAM * init_vgmstream_xwma(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_xopus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_vs_square(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_msf_banpresto_wmsf(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_msf_banpresto_2msf(STREAMFILE * streamFile);
@ -822,4 +821,7 @@ VGMSTREAM * init_vgmstream_ogg_opus(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_imc(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_imc_container(STREAMFILE * streamFile);
#endif /*_META_H*/

164
src/meta/mul.c Normal file
View File

@ -0,0 +1,164 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
typedef enum { NONE, PSX, DSP, XBOX } mul_codec;
/* .MUL - from Crystal Dynamics games [Legacy of Kain: Defiance (PS2), Tomb Raider Underworld (multi)] */
VGMSTREAM * init_vgmstream_mul(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, coefs_offset = 0;
int loop_flag, channel_count, sample_rate, num_samples, loop_start;
int big_endian;
mul_codec codec = NONE;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
/* checks */
/* .mul: found in the exe, used by the bigfile extractor (Gibbed.TombRaider)
* (some files have companion .mus/sam files but seem to be sequences/control stuff)
* .(extensionless): filenames as found in the bigfile
* .emff: fake extension ('Eidos Music File Format') */
if (!check_extensions(streamFile, "mul,,emff"))
goto fail;
if (read_32bitBE(0x10,streamFile) != 0 ||
read_32bitBE(0x14,streamFile) != 0 ||
read_32bitBE(0x18,streamFile) != 0 ||
read_32bitBE(0x1c,streamFile) != 0)
goto fail;
big_endian = guess_endianness32bit(0x00, streamFile);
read_32bit = big_endian ? read_32bitBE : read_32bitLE;
sample_rate = read_32bit(0x00,streamFile);
loop_start = read_32bit(0x04,streamFile);
num_samples = read_32bit(0x08,streamFile);
channel_count = read_32bit(0x0C,streamFile);
if (sample_rate < 8000 || sample_rate > 48000 || channel_count > 8)
goto fail;
/* 0x20: flag when file has non-audio blocks (ignored by the layout) */
/* 0x24: same? */
/* 0x28: loop offset within audio data (not file offset) */
/* 0x2c: some value related to loop? */
/* 0x34: id? */
/* 0x38+: channel config until ~0x100? (multiple 0x3F800000 depending on the number of channels) */
/* test known versions (later versions start from 0x24 instead of 0x20) */
if (!(read_32bit(0x38,streamFile) == 0x3F800000 ||
read_32bit(0x3c,streamFile) == 0x3F800000)) /* Tomb Raider Underworld */
goto fail;
loop_flag = (loop_start >= 0); /* 0xFFFFFFFF when not looping */
start_offset = 0x800;
/* format is pretty limited so we need to guess codec */
if (big_endian) {
/* test DSP (GC/Wii): check known coef locations */
if (read_32bitBE(0xC8,streamFile) != 0) { /* Tomb Raider Legend (GC) */
codec = DSP;
coefs_offset = 0xC8;
}
else if (read_32bitBE(0xCC,streamFile) != 0) { /* Tomb Raider Anniversary (Wii) */
codec = DSP;
coefs_offset = 0xCC;
}
else if (read_32bitBE(0x2D0,streamFile) != 0) { /* Tomb Raider Underworld (Wii) */
codec = DSP;
coefs_offset = 0x2D0;
}
// todo test XMA1 (X360): mono streams, each block has 1 sub-blocks of 0x800 packet per channel
// todo test ? (PS3)
}
else {
int i;
off_t offset = start_offset;
size_t file_size = get_streamfile_size(streamFile);
size_t frame_size;
/* check first audio frame */
while (offset < file_size) {
uint32_t block_type = read_32bit(offset+0x00, streamFile);
uint32_t block_size = read_32bit(offset+0x04, streamFile);
uint32_t data_size = read_32bit(offset+0x10, streamFile);
if (block_type != 0x00) {
offset += 0x10 + block_size;
continue; /* not audio */
}
/* test PS-ADPCM (PS2/PSP): flag is always 2 in .mul */
frame_size = 0x10;
for (i = 0; i < data_size / frame_size; i++) {
if (read_8bit(offset + 0x20 + frame_size*i + 0x01, streamFile) != 0x02)
break;
}
if (i == data_size / frame_size) {
codec = PSX;
break;
}
/* test XBOX-IMA (PC/Xbox): reserved frame header value is always 0 */
frame_size = 0x24;
for (i = 0; i < data_size / frame_size; i++) {
if (read_8bit(offset + 0x20 + frame_size*i + 0x03, streamFile) != 0x00)
break;
}
if (i == data_size / frame_size) {
codec = XBOX;
break;
}
break;
}
}
if (codec == NONE) {
VGM_LOG("MUL: unknown codec\n");
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_MUL;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = num_samples;
vgmstream->codec_endian = big_endian;
switch(codec) {
case PSX:
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_mul;
break;
case DSP:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_mul;
dsp_read_coefs_be(vgmstream,streamFile,coefs_offset+0x00,0x2e);
dsp_read_hist_be (vgmstream,streamFile,coefs_offset+0x24,0x2e);
break;
case XBOX:
vgmstream->coding_type = coding_XBOX_IMA_int;
vgmstream->layout_type = layout_blocked_mul;
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -13,7 +13,7 @@ static uint32_t find_key(uint32_t firstword) {
/* RSD - RedSpark (MadWorld)
RS3D - RedSpark (Mario & Luigi: Dream Team I fi*/
VGMSTREAM * init_vgmstream_RedSpark(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_redspark(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
@ -105,7 +105,7 @@ VGMSTREAM * init_vgmstream_RedSpark(STREAMFILE *streamFile) {
} else {
vgmstream->layout_type = layout_none;
}
vgmstream->meta_type = meta_RedSpark;
vgmstream->meta_type = meta_REDSPARK;
{

View File

@ -1,75 +1,52 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util.h"
#include "../coding/coding.h"
/* VS (from Men in Black) */
/* .VS - from Melbourne House games [Men in Black II (PS2), Grand Prix Challenge (PS2) */
VGMSTREAM * init_vgmstream_vs(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count;
int i;
int loop_flag, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("vs",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0xC8000000) /* "0xC8000000" */
/* checks */
if (!check_extensions(streamFile, "vs"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0xC8000000)
goto fail;
loop_flag = 0;
channel_count = 2;
start_offset = 0x08;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x08;
vgmstream->channels = channel_count;
vgmstream->interleave_block_size=0x10;
vgmstream->meta_type = meta_VS;
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs;
#if 0
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = (read_32bitLE(0x0c,streamFile)-start_offset);
}
#endif
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
vgmstream->layout_type = layout_blocked_vs;
vgmstream->meta_type = meta_VS;
/* open the file for reading */
{
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(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));
block_update(start_offset, vgmstream);
}
/* Calc num_samples */
block_update_vs(start_offset,vgmstream);
vgmstream->num_samples=0;
do {
vgmstream->num_samples += vgmstream->current_block_size*28/16;
block_update_vs(vgmstream->next_block_offset,vgmstream);
} while (vgmstream->next_block_offset<get_streamfile_size(streamFile));
block_update_vs(start_offset,vgmstream);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -3,10 +3,10 @@
#include "../coding/coding.h"
/* VS - VagStream from Square games [Final Fantasy X (PS2) voices, Unlimited Saga (PS2) voices] */
VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
/* VS - VagStream from Square games [Final Fantasy X (PS2) voices, Unlimited Saga (PS2) voices, All Star Pro-Wrestling 2/3 (PS2) music] */
VGMSTREAM * init_vgmstream_vs_square(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag, pitch;
int channel_count, loop_flag, pitch, flags;
off_t start_offset;
@ -17,7 +17,7 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
if (read_32bitBE(0x00,streamFile) != 0x56530000) /* "VS\0\0" */
goto fail;
/* 0x04: null (flags? used in SVS) */
flags = read_32bitLE(0x04,streamFile);
/* 0x08: block number */
/* 0x0c: blocks left in the subfile */
pitch = read_32bitLE(0x10,streamFile); /* usually 0x1000 = 48000 */
@ -25,8 +25,13 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
/* 0x18: null */
/* 0x1c: null */
if (flags != 0x00 && flags != 0x01) {
VGM_LOG("VS: unknown flags\n");
goto fail;
}
loop_flag = 0;
channel_count = 1;
channel_count = (flags & 1) ? 2 : 1;
start_offset = 0x00;
@ -34,10 +39,10 @@ VGMSTREAM * init_vgmstream_vs_ffx(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_FFX;
vgmstream->meta_type = meta_VS_SQUARE;
vgmstream->sample_rate = round10((48000 * pitch) / 4096); /* needed for rare files */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_ffx;
vgmstream->layout_type = layout_blocked_vs_square;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;

View File

@ -3,7 +3,7 @@
#include "../coding/coding.h"
/* .vs/STRx - from The Bouncer (PS2) */
VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
VGMSTREAM * init_vgmstream_vs_str(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
@ -29,10 +29,10 @@ VGMSTREAM * init_vgmstream_ps2_strlr(STREAMFILE *streamFile) {
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_PS2_STRLR;
vgmstream->meta_type = meta_VS_STR;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_ps2_strlr;
vgmstream->layout_type = layout_blocked_vs_str;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;

View File

@ -108,9 +108,11 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
name_size = 0;
switch(sample_rate) {
case 0x0800: sample_rate = 22050; break;
case 0x0687: sample_rate = 18000; break;
case 0x05ce: sample_rate = 16000; break;
case 0x0400: sample_rate = 11025; break;
default:
VGM_LOG("ZSND: unknown sample_rate\n");
VGM_LOG("ZSND: unknown sample_rate %x at %x\n", sample_rate, (uint32_t)header2_offset);
goto fail;
}
break;

View File

@ -192,8 +192,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_vgs,
init_vgmstream_dc_dcsw_dcs,
init_vgmstream_wii_smp,
init_vgmstream_emff_ps2,
init_vgmstream_emff_ngc,
init_vgmstream_mul,
init_vgmstream_thp,
init_vgmstream_wii_sts,
init_vgmstream_ps2_p2bt,
@ -213,7 +212,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_mcg,
init_vgmstream_zsd,
init_vgmstream_ps2_vgs,
init_vgmstream_RedSpark,
init_vgmstream_redspark,
init_vgmstream_ivaud,
init_vgmstream_wii_wsd,
init_vgmstream_wii_ndp,
@ -290,7 +289,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ps2_spm,
init_vgmstream_x360_tra,
init_vgmstream_ps2_iab,
init_vgmstream_ps2_strlr,
init_vgmstream_vs_str,
init_vgmstream_lsf_n1nj4n,
init_vgmstream_vawx,
init_vgmstream_ps2_wmus,
@ -445,7 +444,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_ue4opus,
init_vgmstream_xwma,
init_vgmstream_xopus,
init_vgmstream_vs_ffx,
init_vgmstream_vs_square,
init_vgmstream_msf_banpresto_wmsf,
init_vgmstream_msf_banpresto_2msf,
init_vgmstream_nwav,
@ -458,6 +457,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_dsp_adpcmx,
init_vgmstream_ogg_opus,
init_vgmstream_nus3audio,
init_vgmstream_imc,
init_vgmstream_imc_container,
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
@ -1006,8 +1007,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_matx:
case layout_blocked_dec:
case layout_blocked_vs:
case layout_blocked_emff_ps2:
case layout_blocked_emff_ngc:
case layout_blocked_mul:
case layout_blocked_gsb:
case layout_blocked_xvas:
case layout_blocked_thp:
@ -1018,7 +1018,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_bdsp:
case layout_blocked_tra:
case layout_blocked_ps2_iab:
case layout_blocked_ps2_strlr:
case layout_blocked_vs_str:
case layout_blocked_rws:
case layout_blocked_hwas:
case layout_blocked_ea_sns:
@ -1031,7 +1031,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_sthd:
case layout_blocked_h4m:
case layout_blocked_xa_aiff:
case layout_blocked_vs_ffx:
case layout_blocked_vs_square:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_aix:

View File

@ -229,8 +229,7 @@ typedef enum {
layout_blocked_dec,
layout_blocked_xvas,
layout_blocked_vs,
layout_blocked_emff_ps2,
layout_blocked_emff_ngc,
layout_blocked_mul,
layout_blocked_gsb,
layout_blocked_thp,
layout_blocked_filp,
@ -241,7 +240,7 @@ typedef enum {
layout_blocked_ivaud, /* GTA IV .ivaud blocks */
layout_blocked_tra, /* DefJam Rapstar .tra blocks */
layout_blocked_ps2_iab,
layout_blocked_ps2_strlr,
layout_blocked_vs_str,
layout_blocked_rws,
layout_blocked_hwas,
layout_blocked_ea_sns, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
@ -254,7 +253,7 @@ typedef enum {
layout_blocked_sthd, /* Dream Factory STHD */
layout_blocked_h4m, /* H4M video */
layout_blocked_xa_aiff, /* XA in AIFF files [Crusader: No Remorse (SAT), Road Rash (3DO)] */
layout_blocked_vs_ffx,
layout_blocked_vs_square,
/* otherwise odd */
layout_aix, /* CRI AIX's wheels within wheels */
@ -441,8 +440,7 @@ typedef enum {
meta_DC_DCSW_DCS, /* Evil Twin - Cypriens Chronicles (DC) */
meta_WII_SMP, /* Mushroom Men - The Spore Wars */
meta_WII_SNG, /* Excite Trucks */
meta_EMFF_PS2, /* Eidos Music File Format for PS2*/
meta_EMFF_NGC, /* Eidos Music File Format for NGC/WII */
meta_MUL,
meta_SAT_BAKA, /* Crypt Killer */
meta_PS2_VSF, /* Musashi: Samurai Legend */
meta_PS2_VSF_TTA, /* Tiny Toon Adventures: Defenders of the Universe */
@ -502,8 +500,8 @@ typedef enum {
meta_PS2_TK5, /* Tekken 5 Stream Files */
meta_PS2_MCG, /* Gunvari MCG Files (was name .GCM on disk) */
meta_ZSD, /* Dragon Booster ZSD */
meta_RedSpark, /* "RedSpark" RSD (MadWorld) */
meta_IVAUD, /* .ivaud GTA IV */
meta_REDSPARK, /* "RedSpark" RSD (MadWorld) */
meta_IVAUD, /* .ivaud GTA IV */
meta_NDS_HWAS, /* Spider-Man 3, Tony Hawk's Downhill Jam, possibly more... */
meta_NGC_LPS, /* Rave Master (Groove Adventure Rave)(GC) */
meta_NAOMI_ADPCM, /* NAOMI/NAOMI2 ARcade games */
@ -567,7 +565,7 @@ typedef enum {
meta_X360_TRA, /* Def Jam Rapstar */
meta_PS2_VGS, /* Princess Soft PS2 games */
meta_PS2_IAB, /* Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */
meta_PS2_STRLR, /* The Bouncer */
meta_VS_STR, /* The Bouncer */
meta_LSF_N1NJ4N, /* .lsf n1nj4n Fastlane Street Racing (iPhone) */
meta_VAWX, /* feelplus: No More Heroes Heroes Paradise, Moon Diver */
meta_PC_SNDS, /* Incredibles PC .snds */
@ -702,14 +700,15 @@ typedef enum {
meta_XWMA,
meta_VA3, /* DDR Supernova 2 AC */
meta_XOPUS,
meta_VS_FFX,
meta_VS_SQUARE,
meta_NWAV,
meta_XPCM,
meta_MSF_TAMASOFT,
meta_XPS_DAT,
meta_ZSND,
meta_DSP_ADPCMX,
meta_OGG_OPUS
meta_OGG_OPUS,
meta_IMC,
} meta_t;