diff --git a/src/meta/str_wav.c b/src/meta/str_wav.c index fab8b333..bce26325 100644 --- a/src/meta/str_wav.c +++ b/src/meta/str_wav.c @@ -1,8 +1,9 @@ #include "meta.h" #include "../coding/coding.h" +#include "../util/layout_utils.h" -typedef enum { PSX, DSP, XBOX, WMA, IMA, XMA2 } strwav_codec; +typedef enum { PSX, DSP, XBOX, WMA, IMA, XMA2, MPEG } strwav_codec; typedef struct { int tracks; int channels; @@ -173,6 +174,26 @@ VGMSTREAM* init_vgmstream_str_wav(STREAMFILE* sf) { } #endif +#ifdef VGM_USE_MPEG + case MPEG: { + /* regular MP3 starting with ID2, stereo tracks xN (bgm + vocals) but assuming last (or only one) could be mono */ + int layers = (strwav.channels + 1) / 2; + + for (int i = 0; i < layers; i++) { + uint32_t size = strwav.interleave; + uint32_t offset = i * size; + const char* ext = "mp3"; + int layer_channels = ((layers % 2) && i + 1 == layers) ? 1 : 2; + + layered_add_subfile(vgmstream, layers, layer_channels, sf, offset, size, ext, init_vgmstream_mpeg); + } + + if (!layered_add_done(vgmstream)) + goto fail; + break; + } +#endif + default: goto fail; } @@ -712,6 +733,7 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa /* Tak and the Guardians of Gross (Wii)[2008] */ /* The House of the Dead: Overkill (Wii)[2009] (not Blitz but still the same format) */ /* All Star Karate (Wii)[2010] */ + /* Karaoke Revolution (Wii)[2010] */ if ((read_u32be(0x04,sf_h) == 0x00000800 || read_u32be(0x04,sf_h) == 0x00000700) && /* rare? */ read_u32be(0x08,sf_h) != 0x00000000 && @@ -730,11 +752,12 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa strwav->codec = DSP; strwav->coefs_table = 0x7c; strwav->interleave = strwav->channels > 4 ? 0x4000 : 0x8000; - ;VGM_LOG("STR+WAV: header TKGG/HOTDO/ASK (Wii)\n"); + ;VGM_LOG("STR+WAV: header TKGG/HOTDO/ASK/KR (Wii)\n"); return 1; } /* The House of the Dead: Overkill (PS3)[2009] (not Blitz but still the same format) */ + /* Karaoke Revolution (PS3)[2010] */ if ((read_u32be(0x04,sf_h) == 0x00000800 || read_u32be(0x04,sf_h) == 0x00000700) && /* rare? */ read_u32be(0x08,sf_h) != 0x00000000 && @@ -747,10 +770,24 @@ static int parse_header(STREAMFILE* sf_h, STREAMFILE* sf_b, strwav_header* strwa strwav->sample_rate = read_s32be(0x38,sf_h); strwav->flags = read_u32be(0x3c,sf_h); - strwav->channels = read_s32be(0x70,sf_h); /* tracks of 1ch */ - strwav->interleave = strwav->channels > 4 ? 0x4000 : 0x8000; + strwav->channels = read_s32be(0x70,sf_h); + + /* possible flags/ch numbers at 0x4A/61 */ + if (read_s32be(0x78,sf_h) != 0) { /* KRev */ + strwav->tracks = strwav->channels / 2; + strwav->num_samples = strwav->loop_end; /* num_samples here seems to be data size */ + strwav->interleave = read_s32be(0xA0,sf_h); /* one size per file, but CBR = same for all */ + //C0: stream samples (same as num_samples) + + strwav->codec = MPEG; /* full CBR MP3 one after other */ + } + else { /* HOTD */ + strwav->channels = read_s32be(0x70,sf_h); /* tracks of 1ch */ + strwav->interleave = strwav->channels > 4 ? 0x4000 : 0x8000; + + strwav->codec = PSX; + } - strwav->codec = PSX; ;VGM_LOG("STR+WAV: header HOTDO (PS3)\n"); return 1; } diff --git a/src/util/layout_utils.c b/src/util/layout_utils.c index 70d39358..4c6feb38 100644 --- a/src/util/layout_utils.c +++ b/src/util/layout_utils.c @@ -2,9 +2,17 @@ #include "../vgmstream.h" #include "../layout/layout.h" +#include "../coding/coding.h" -bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels) { - if (!vs || !vs->codec_data) { + +typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*); + +bool layered_add_subfile(VGMSTREAM* vs, int layers, int layer_channels, STREAMFILE* sf, uint32_t offset, uint32_t size, const char* ext, init_vgmstream_t init_vgmstream) { + int i; + layered_layout_data* data; + STREAMFILE* temp_sf; + + if (!vs) { goto fail; } @@ -13,9 +21,54 @@ bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels) { if (!layers) layers = vs->channels / layer_channels; + switch(vs->layout_type) { + case layout_segmented: //to be improved + goto fail; + + case layout_layered: + data = vs->layout_data; + + i = data->curr_layer; + break; + + default: + data = init_layout_layered(layers); + if (!data) goto fail; + vs->layout_data = data; + vs->layout_type = layout_layered; + + i = 0; + break; + } + + temp_sf = setup_subfile_streamfile(sf, offset, size, ext); + if (!temp_sf) goto fail; + + data->layers[i] = init_vgmstream(temp_sf); + close_streamfile(temp_sf); + if (!data->layers[i]) goto fail; + + data->curr_layer++; + + return true; +fail: + return false; +} + + +bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels) { int i; layered_layout_data* data; + if (!vs || !vs->codec_data) { + goto fail; + } + + if (!layer_channels) + layer_channels = 1; + if (!layers) + layers = vs->channels / layer_channels; + switch(vs->layout_type) { case layout_segmented: //to be improved goto fail; @@ -65,6 +118,11 @@ bool layered_add_done(VGMSTREAM* vs) { if (!setup_layout_layered(vs->layout_data)) goto fail; + if (!vs->coding_type) { + layered_layout_data* data = vs->layout_data; + vs->coding_type = data->layers[0]->coding_type; + } + return true; fail: return false; diff --git a/src/util/layout_utils.h b/src/util/layout_utils.h index d5247219..28a66ea2 100644 --- a/src/util/layout_utils.h +++ b/src/util/layout_utils.h @@ -3,6 +3,11 @@ #include "../vgmstream.h" +typedef VGMSTREAM* (*init_vgmstream_t)(STREAMFILE*); + +/* add a new layer from subfile (setups layout if needed) */ +bool layered_add_subfile(VGMSTREAM* vs, int layers, int layer_channels, STREAMFILE* sf, uint32_t offset, uint32_t size, const char* ext, init_vgmstream_t init_vgmstream); + /* add a new layer from codec data (setups layout if needed) * codec is passed in the vs for easier free/etc control */ bool layered_add_codec(VGMSTREAM* vs, int layers, int layer_channels);