diff --git a/src/formats.c b/src/formats.c index 51e65490..eafd3ffd 100644 --- a/src/formats.c +++ b/src/formats.c @@ -653,8 +653,8 @@ static const meta_info meta_info_list[] = { {meta_CFN, "tri-Crescendo CAF Header"}, {meta_PS2_VPK, "VPK Header"}, {meta_GENH, "GENH Generic Header"}, - {meta_DSP_SADB, "sadb header"}, - {meta_SADL, "sadl header"}, + {meta_DSP_SADB, "Procyon Studio SADB header"}, + {meta_SADL, "Procyon Studio SADL header"}, {meta_PS2_BMDX, "Beatmania .bmdx header"}, {meta_DSP_WSI, ".wsi header"}, {meta_AIFC, "Audio Interchange File Format AIFF-C"}, @@ -795,8 +795,8 @@ static const meta_info meta_info_list[] = { {meta_ZSD, "ZSD Header"}, {meta_RedSpark, "RedSpark Header"}, {meta_PC_IVAUD, "assumed GTA IV Audio file by .ivaud extension"}, - {meta_DSP_WII_WSD, "Standard Nintendo DSP headers in .wsd"}, - {meta_WII_NDP, "Vertigo NDP Header"}, + {meta_DSP_WII_WSD, ".WSD header"}, + {meta_WII_NDP, "Icon Games NDP header"}, {meta_PS2_SPS, "Ape Escape 2 SPS Header"}, {meta_PS2_XA2_RRP, "Acclaim XA2 Header"}, {meta_NDS_HWAS, "Vicarious Visions HWAS header"}, @@ -815,7 +815,7 @@ static const meta_info meta_info_list[] = { {meta_MAXIS_XA, "Maxis XAI/XAJ Header"}, {meta_EXAKT_SC, "assumed Activision / EXAKT SC by extension"}, {meta_WII_BNS, "Nintendo BNS header"}, - {meta_WII_WAS, "WAS (iSWS) DSP header"}, + {meta_WII_WAS, "Sumo Digital iSWS header"}, {meta_XBOX_HLWAV, "Half Life 2 bgm header"}, {meta_STX, "Nintendo .stx header"}, {meta_MYSPD, "U-Sing .MYSPD header"}, @@ -825,7 +825,7 @@ static const meta_info meta_info_list[] = { {meta_DMSG, "RIFF/DMSGsegh header"}, {meta_PONA_3DO, "Policenauts BGM header"}, {meta_PONA_PSX, "Policenauts BGM header"}, - {meta_NGC_DSP_AAAP, "Double standard DSP header in 'AAAp'"}, + {meta_NGC_DSP_AAAP, "Acclaim Austin AAAp header"}, {meta_NGC_DSP_KONAMI, "Konami DSP header"}, {meta_PS2_STER, "STER Header"}, {meta_BNSF, "Namco Bandai BNSF header"}, @@ -838,12 +838,13 @@ static const meta_info meta_info_list[] = { {meta_PC_SMP, "Ghostbusters .smp Header"}, {meta_NGC_PDT, "PDT DSP header"}, {meta_NGC_BO2, "Blood Omen 2 DSP header"}, + {meta_DSP_DDSP, ".DDSP header"}, {meta_P3D, "Radical P3D header"}, {meta_PS2_TK1, "Tekken TK5STRM1 Header"}, {meta_PS2_ADSC, "ADSC Header"}, {meta_NGC_DSP_MPDS, "MPDS DSP header"}, - {meta_DSP_STR_IG, "Infogrames dual dsp header"}, - {meta_EA_SWVR, "Electronic Arts SWVR header"}, + {meta_DSP_STR_IG, "Infogrames .DSP header"}, + {meta_EA_SWVR, "Electronic Arts SWVR header"}, {meta_PS2_B1S, "B1S header"}, {meta_PS2_WAD, "WAD header"}, {meta_DSP_XIII, "XIII dsp header"}, @@ -855,7 +856,7 @@ static const meta_info meta_info_list[] = { {meta_XAU, "XPEC XAU header"}, {meta_GH3_BAR, "Guitar Hero III Mobile .bar"}, {meta_FFW, "Freedom Fighters BGM header"}, - {meta_DSP_DSPW, "DSPW dsp header"}, + {meta_DSP_DSPW, "Capcom DSPW header"}, {meta_PS2_JSTM, "JSTM Header"}, {meta_XVAG, "Sony XVAG header"}, {meta_PS3_CPS, "tri-Crescendo CPS Header"}, diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index dd9a58cd..3a8ffd93 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -28,55 +28,127 @@ struct dsp_header { int16_t block_size; }; -/* nonzero on failure */ +/* read the above struct; returns nonzero on failure */ static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) { int i; uint8_t buf[0x4e]; /* usually padded out to 0x60 */ - if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) return 1; - - header->sample_count = - get_32bitBE(buf+0x00); - header->nibble_count = - get_32bitBE(buf+0x04); - header->sample_rate = - get_32bitBE(buf+0x08); - header->loop_flag = - get_16bitBE(buf+0x0c); - header->format = - get_16bitBE(buf+0x0e); - header->loop_start_offset = - get_32bitBE(buf+0x10); - header->loop_end_offset = - get_32bitBE(buf+0x14); - header->ca = - get_32bitBE(buf+0x18); + if (read_streamfile(buf, offset, 0x4e, file) != 0x4e) + return 1; + header->sample_count = get_32bitBE(buf+0x00); + header->nibble_count = get_32bitBE(buf+0x04); + header->sample_rate = get_32bitBE(buf+0x08); + header->loop_flag = get_16bitBE(buf+0x0c); + header->format = get_16bitBE(buf+0x0e); + header->loop_start_offset = get_32bitBE(buf+0x10); + header->loop_end_offset = get_32bitBE(buf+0x14); + header->ca = get_32bitBE(buf+0x18); for (i=0; i < 16; i++) - header->coef[i] = - get_16bitBE(buf+0x1c+i*2); - header->gain = - get_16bitBE(buf+0x3c); - header->initial_ps = - get_16bitBE(buf+0x3e); - header->initial_hist1 = - get_16bitBE(buf+0x40); - header->initial_hist2 = - get_16bitBE(buf+0x42); - header->loop_ps = - get_16bitBE(buf+0x44); - header->loop_hist1 = - get_16bitBE(buf+0x46); - header->loop_hist2 = - get_16bitBE(buf+0x48); - header->channel_count = - get_16bitBE(buf+0x4a); - header->block_size = - get_16bitBE(buf+0x4c); - + header->coef[i] = get_16bitBE(buf+0x1c+i*0x2); + header->gain = get_16bitBE(buf+0x3c); + header->initial_ps = get_16bitBE(buf+0x3e); + header->initial_hist1 = get_16bitBE(buf+0x40); + header->initial_hist2 = get_16bitBE(buf+0x42); + header->loop_ps = get_16bitBE(buf+0x44); + header->loop_hist1 = get_16bitBE(buf+0x46); + header->loop_hist2 = get_16bitBE(buf+0x48); + header->channel_count = get_16bitBE(buf+0x4a); + header->block_size = get_16bitBE(buf+0x4c); return 0; } -/* the standard .dsp, as generated by DSPADPCM.exe */ +static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_header) { + int i, j; + + /* set coeffs and initial history (usually 0) */ + for (i = 0; i < vgmstream->channels; i++){ + for (j = 0; j < 16; j++) { + vgmstream->ch[i].adpcm_coef[j] = ch_header[i].coef[j]; + } + vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1; + vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2; + } +} + +static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + /* load standard dsp header per channel */ + for (i = 0; i < channels; i++) { + if (read_dsp_header(&ch_header[i], offset + i*spacing, streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_format(struct dsp_header* ch_header, int channels) { + int i; + + /* check type==0 and gain==0 */ + for (i = 0; i < channels; i++) { + if (ch_header[i].format || ch_header[i].gain) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_samples(struct dsp_header* ch_header, int channels) { + int i; + + /* check for agreement between channels */ + for (i = 0; i < channels - 1; i++) { + if (ch_header[i].sample_count != ch_header[i+1].sample_count || + ch_header[i].nibble_count != ch_header[i+1].nibble_count || + ch_header[i].sample_rate != ch_header[i+1].sample_rate || + ch_header[i].loop_flag != ch_header[i+1].loop_flag || + ch_header[i].loop_start_offset != ch_header[i+1].loop_start_offset || + ch_header[i].loop_end_offset != ch_header[i+1].loop_end_offset ) { + goto fail; + } + } + + return 1; +fail: + return 0; +} +static int check_dsp_initial_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + /* check initial predictor/scale */ + for (i = 0; i < channels; i++) { + if (ch_header[i].initial_ps != (uint8_t)read_8bit(offset + i*spacing, streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} +static int check_dsp_loop_ps(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + int i; + + if (!ch_header[0].loop_flag) + return 1; + + /* check loop predictor/scale */ + for (i = 0; i < channels; i++) { + off_t loop_offset = ch_header[i].loop_start_offset / 16 * 8; + if (ch_header[i].loop_ps != (uint8_t)read_8bit(offset + i*spacing + loop_offset,streamFile)) + goto fail; + } + + return 1; +fail: + return 0; +} + +/* ********************************* */ + +/* the standard .dsp, as generated by DSPADPCM.exe */ VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -523,7 +595,7 @@ VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) { streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("str",filename_extension(filename))) goto fail; - /* always 0xFAAF0001 @ offset 0 */ + /* always 0xFAAF0001 @ offset 0 */ if (read_32bitBE(0x00,streamFile)!=0xFAAF0001) goto fail; /* build the VGMSTREAM */ @@ -535,9 +607,9 @@ VGMSTREAM * init_vgmstream_ngc_str(STREAMFILE *streamFile) { vgmstream->num_samples = read_32bitBE(0x08,streamFile); vgmstream->sample_rate = read_32bitBE(0x04,streamFile); - /* always loop to the beginning */ - vgmstream->loop_start_sample=0; - vgmstream->loop_end_sample=vgmstream->num_samples; + /* always loop to the beginning */ + vgmstream->loop_start_sample=0; + vgmstream->loop_end_sample=vgmstream->num_samples; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; @@ -572,7 +644,6 @@ fail: /* a bunch of formats that are identical except for file extension, * but have different interleaves */ - VGMSTREAM * init_vgmstream_ngc_dsp_std_int(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -808,120 +879,60 @@ fail: return NULL; } - -/* sadb - .SAD files, two standard DSP headers */ +#define SADB_MAX_CHANNELS 2 +/* sadb - Procyon Studio header + interleaved dsp [Shiren the Wanderer 3 (Wii), Disaster: Day of Crisis (Wii)] */ VGMSTREAM * init_vgmstream_sadb(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t start_offset; - off_t interleave; - - struct dsp_header ch0_header,ch1_header; - int i; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; + struct dsp_header ch_header[SADB_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("sad",filename_extension(filename))) goto fail; - - /* check header magic */ - if (read_32bitBE(0x0,streamFile) != 0x73616462) goto fail; /* "sadb" */ + /* check extension */ + if (!check_extensions(streamFile, "sad")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x73616462) /* "sadb" */ + goto fail; channel_count = read_8bit(0x32, streamFile); - if (channel_count != 1 && channel_count != 2) goto fail; - - if (read_dsp_header(&ch0_header, 0x80, streamFile)) goto fail; - if (channel_count == 2 && read_dsp_header(&ch1_header, 0xe0, streamFile)) goto fail; + if (channel_count > SADB_MAX_CHANNELS) goto fail; + header_offset = 0x80; + header_spacing = 0x60; start_offset = read_32bitBE(0x48,streamFile); - interleave = 16; + interleave = 0x10; - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(start_offset,streamFile)) - goto fail; - if (channel_count == 2 && ch1_header.initial_ps != (uint8_t)read_8bit(start_offset+interleave,streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - (channel_count == 2 &&(ch1_header.format || ch1_header.gain))) - goto fail; - - /* check for agreement */ - if ( channel_count == 2 &&( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - )) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/8/channel_count*8; - loop_off = (loop_off/interleave*interleave*channel_count) + (loop_off%interleave); - if (ch0_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off,streamFile)) - goto fail; - if (channel_count == 2 && - ch1_header.loop_ps != (uint8_t)read_8bit(start_offset+loop_off+interleave,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + //todo: loop check fails unless adjusted: + // loop_offset = (loop_offset / spacing * spacing * channels) + (loop_offset % spacing); + //if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; - /* TODO: adjust for interleave? */ - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = channel_count == 2 ? layout_interleave : layout_none; - vgmstream->interleave_block_size = interleave; vgmstream->meta_type = meta_DSP_SADB; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - if (channel_count == 2) - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - - if (channel_count == 2) { - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - vgmstream->ch[1].streamfile = vgmstream->ch[0].streamfile; - } - - if (!vgmstream->ch[0].streamfile) goto fail; - /* open the file for reading */ - for (i=0;ich[i].channel_start_offset= - vgmstream->ch[i].offset=start_offset+i*interleave; - } - + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } @@ -1219,7 +1230,7 @@ fail: Lego Indiana Jones - The Original Adventures (Wii) Lego Indiana Jones 2 - The Adventure Continues (Wii) Lego Star Wars - The Complete Saga (Wii) - Lego The Lord of the Rings (Wii) + Lego The Lord of the Rings (Wii) The Chronicles of Narnia - Prince Caspian (Wii) */ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; @@ -1232,7 +1243,7 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if ((strcasecmp("gcm",filename_extension(filename))) && - (strcasecmp("idsp",filename_extension(filename)))) + (strcasecmp("idsp",filename_extension(filename)))) goto fail; /* check header magic */ @@ -1255,14 +1266,14 @@ VGMSTREAM * init_vgmstream_wii_idsp(STREAMFILE *streamFile) { start_offset = 0xe0; } - else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii) - read_32bitBE(0x8, streamFile) == 0x12c) - { - if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; + else if (read_32bitBE(0x4, streamFile) == 3 && //Lego The Lord of the Rings (Wii) + read_32bitBE(0x8, streamFile) == 0x12c) + { + if (read_dsp_header(&ch0_header, 0x20, streamFile)) goto fail; + if (read_dsp_header(&ch1_header, 0x80, streamFile)) goto fail; - start_offset = 0xe0; - } + start_offset = 0xe0; + } else goto fail; interleave = read_32bitBE(0xc, streamFile); @@ -1350,551 +1361,220 @@ fail: return NULL; } -/* .wsd files, two DSP files stuck together */ -/* found in Phantom Brave Wii */ +#define WSD_MAX_CHANNELS 2 +/* .wsd - Custom heade + full interleaved dsp [Phantom Brave (Wii)] */ VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size; - - struct dsp_header ch0_header,ch1_header; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("wsd",filename_extension(filename))) goto fail; - - /* read .wsd header */ - channel_1_start = read_32bitBE(0x0,streamFile); - channel_2_start = read_32bitBE(0x4,streamFile); - channel_1_size = read_32bitBE(0x8,streamFile); - channel_2_size = read_32bitBE(0xc,streamFile); - - /* check header */ - if (channel_1_size != channel_2_size) goto fail; - if (channel_1_start != 0x20) goto fail; - if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail; - if (channel_1_start + channel_1_size > channel_2_start) goto fail; - if (channel_2_start + channel_2_size > get_streamfile_size(streamFile)) - goto fail; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != - (uint8_t)read_8bit(channel_1_start + 0x60, streamFile)) - goto fail; - - if (ch1_header.initial_ps != - (uint8_t)read_8bit(channel_2_start + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != - (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != - (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_WII_WSD; - - /* coeffs */ - { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) goto fail; - - vgmstream->ch[0].channel_start_offset = - vgmstream->ch[0].offset=channel_1_start+0x60; - vgmstream->ch[1].channel_start_offset = - vgmstream->ch[1].offset=channel_2_start+0x60; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .ddsp files, two DSP files stuck together, without additional header */ -VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t channel_1_start, channel_2_start, channel_1_size, channel_2_size; - - struct dsp_header ch0_header,ch1_header; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ddsp",filename_extension(filename))) goto fail; - - /* read .wsd header */ - channel_1_start = 0; - channel_2_start = (get_streamfile_size(streamFile)/2); - channel_1_size = (get_streamfile_size(streamFile)/2)-0x60; - channel_2_size = (get_streamfile_size(streamFile)/2)-0x60; - - /* check header */ - if (channel_1_size != channel_2_size) goto fail; - if (channel_1_start != 0x0) goto fail; - if (channel_1_size < 0x20 || channel_2_size < 0x20) goto fail; - if (channel_1_start + channel_1_size > channel_2_start) goto fail; - if (channel_2_start + channel_2_size > get_streamfile_size(streamFile)) - goto fail; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != - (uint8_t)read_8bit(channel_1_start + 0x60, streamFile)) - goto fail; - - if (ch1_header.initial_ps != - (uint8_t)read_8bit(channel_2_start + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain || - ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != - (uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != - (uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_DSP_DDSP; - - /* coeffs */ - { - int i; - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) goto fail; - - vgmstream->ch[0].channel_start_offset = - vgmstream->ch[0].offset=channel_1_start+0x60; - vgmstream->ch[1].channel_start_offset = - vgmstream->ch[1].offset=channel_2_start+0x60; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .was files, DSP file(s), with additional iSWS header */ -VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; - int i; + struct dsp_header ch_header[WSD_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if ((strcasecmp("dsp",filename_extension(filename))) && - (strcasecmp("isws",filename_extension(filename))) && - (strcasecmp("was",filename_extension(filename)))) - goto fail; - - /* read iSWS header */ - if (read_32bitBE(0x0,streamFile) != 0x69535753) - goto fail; - - channel_count = read_32bitBE(0x08,streamFile); - - if (channel_count == 1) - { - - ch1_header_start = 0x20; - ch1_start = 0x80; - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(1,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - vgmstream->meta_type = meta_WII_WAS; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - } - else if (channel_count == 2) - { - - - ch1_header_start = 0x20; - ch2_header_start = 0x80; - ch1_start = 0xE0; - ch2_start = 0xE0 + (read_32bitBE(0x10,streamFile)); - - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } - - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(2,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = read_32bitBE(0x10,streamFile); - vgmstream->meta_type = meta_WII_WAS; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - - } - else - { - goto fail; - } - - return vgmstream; - - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .str found in Micro Machines, Superman: Shadow of Apokolips */ -VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; - int channel_count; - int i; - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("str",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "wsd")) + goto fail; + if (read_32bitBE(0x08,streamFile) != read_32bitBE(0x0c,streamFile)) /* channel sizes */ + goto fail; channel_count = 2; + if (channel_count > WSD_MAX_CHANNELS) goto fail; - ch1_header_start = 0x00; - ch2_header_start = 0x80; - ch1_start = 0x800; - ch2_start = 0x4800; + header_offset = read_32bitBE(0x00,streamFile); + header_spacing = read_32bitBE(0x04,streamFile) - header_offset; + start_offset = header_offset + 0x60; + interleave = header_spacing; - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count, ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + vgmstream->meta_type = meta_DSP_WII_WSD; vgmstream->coding_type = coding_NGC_DSP; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x4000; - vgmstream->meta_type = meta_DSP_STR_IG; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } -/* .dsp found in: Speed Challenge - Jacques Villeneuve's Racing Vision (NGC) - XIII (NGC) - always 2 channels, and an interleave of 0x8 */ +#define DDSP_MAX_CHANNELS 2 +/* .ddsp - full interleaved dsp [The Sims 2 - Pets (Wii)] */ +VGMSTREAM * init_vgmstream_dsp_ddsp(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[DDSP_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "ddsp")) + goto fail; + + channel_count = 2; + if (channel_count > DDSP_MAX_CHANNELS) goto fail; + + header_offset = 0x00; + header_spacing = (get_streamfile_size(streamFile) / channel_count); + start_offset = 0x60; + interleave = header_spacing; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_DDSP; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +#define ISWS_MAX_CHANNELS 2 +/* iSWS - Sumo Digital header + interleaved dsp [DiRT 2 (Wii), F1 2009 (Wii)] */ +VGMSTREAM * init_vgmstream_wii_was(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[ISWS_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "was,dsp,isws")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x69535753) /* "iSWS" */ + goto fail; + + channel_count = read_32bitBE(0x08,streamFile); + if (channel_count > ISWS_MAX_CHANNELS) goto fail; + + header_offset = 0x08 + read_32bitBE(0x04,streamFile); + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = read_32bitBE(0x10,streamFile); + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_WII_WAS; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +#define STR_IG_MAX_CHANNELS 2 +/* .str - Infogrames raw interleaved dsp [Micro Machines (GC), Superman: Shadow of Apokolips (GC)] */ +VGMSTREAM * init_vgmstream_dsp_str_ig(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[STR_IG_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "str")) + goto fail; + + channel_count = 2; + if (channel_count > STR_IG_MAX_CHANNELS) goto fail; + + header_offset = 0x00; + header_spacing = 0x80; + start_offset = 0x800; + interleave = 0x4000; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_STR_IG; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} + +/* .dsp - Ubisoft raw interleaved dsp [Speed Challenge: Jacques Villeneuve's Racing Vision (GC), XIII (GC)] */ +//todo unusual loop values VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; char filename[PATH_LIMIT]; @@ -1903,10 +1583,9 @@ VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { int channel_count; int i; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "dsp")) + goto fail; channel_count = 2; @@ -1987,12 +1666,12 @@ VGMSTREAM * init_vgmstream_dsp_xiii(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2005,105 +1684,56 @@ fail: } -/* .ndp found in Vertigo (WII) */ +#define NDP_MAX_CHANNELS 2 +/* NPD - Icon Games header + subinterleaved DSPs [Vertigo (Wii), Build n' Race (Wii)] */ VGMSTREAM * init_vgmstream_wii_ndp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; - int i; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[NDP_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("ndp",filename_extension(filename))) - goto fail; - - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x4E445000) /* NDP */ - goto fail; - - /* check size */ - if ((read_32bitLE(0x8,streamFile)+0x18 != get_streamfile_size(streamFile))) /* NDP */ - goto fail; - //channel_count = (read_16bitLE(0x10,streamFile) != 2); + /* check extension */ + if (!check_extensions(streamFile, "ndp")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x4E445000) /* "NDP\0" */ + goto fail; + if (read_32bitLE(0x08,streamFile) + 0x18 != get_streamfile_size(streamFile)) + goto fail; + /* 0x0c: sample rate */ - ch1_header_start = 0x18; - ch2_header_start = 0x78; - ch1_start = 0xD8; - ch2_start = 0xDC; + channel_count = read_32bitLE(0x10,streamFile); + if (channel_count > NDP_MAX_CHANNELS) goto fail; - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; + header_offset = 0x18; + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = 0x04; - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(2, ch0_header.loop_flag); + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + vgmstream->meta_type = meta_WII_NDP; vgmstream->coding_type = coding_NGC_DSP_subint; vgmstream->layout_type = layout_none; - vgmstream->interleave_block_size = 0x4; - vgmstream->meta_type = meta_WII_NDP; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - if (!vgmstream_open_stream(vgmstream,streamFile,ch1_start)) + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; return vgmstream; @@ -2124,7 +1754,7 @@ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + goto fail; channel_count = 2; @@ -2192,12 +1822,12 @@ VGMSTREAM * init_vgmstream_dsp_cabelas(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2210,248 +1840,133 @@ fail: } - -/* dual dsp header with additional "AAAp" header, found in Vexx (NGC) and Turok: Evolution (NGC) */ +#define AAAP_MAX_CHANNELS 2 +/* AAAp - Acclaim Austin Audio header + interleaved dsp [Vexx (GC), Turok: Evolution (GC)] */ VGMSTREAM * init_vgmstream_ngc_dsp_aaap(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - struct dsp_header ch0_header,ch1_header; - off_t ch1_header_start, ch2_header_start, ch1_start, ch2_start; + off_t start_offset, header_offset; + size_t header_spacing, interleave; int channel_count; - int i; + struct dsp_header ch_header[AAAP_MAX_CHANNELS]; - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dsp",filename_extension(filename))) - goto fail; + /* check extension */ + if (!check_extensions(streamFile, "dsp")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x41414170) /* "AAAp" */ + goto fail; - /* check header */ - if (read_32bitBE(0x0,streamFile) != 0x41414170) /* AAAp */ - goto fail; - - channel_count = (uint16_t)read_16bitBE(0x6,streamFile); + channel_count = read_16bitBE(0x06,streamFile); + if (channel_count > AAAP_MAX_CHANNELS) goto fail; - ch1_header_start = 0x08; - ch2_header_start = 0x68; - ch1_start = 0xC8; - ch2_start = ch1_start + (uint16_t)read_16bitBE(0x4,streamFile); + header_offset = 0x08; + header_spacing = 0x60; + start_offset = header_offset + channel_count*header_spacing; + interleave = (uint16_t)read_16bitBE(0x04,streamFile); - /* get DSP headers */ - if (read_dsp_header(&ch0_header, ch1_header_start, streamFile)) goto fail; - if (read_dsp_header(&ch1_header, ch2_header_start, streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch0_header.initial_ps != (uint8_t)read_8bit(ch1_start, streamFile)) - goto fail; - if (ch1_header.initial_ps != (uint8_t)read_8bit(ch2_start, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch0_header.format || ch0_header.gain) - goto fail; - if (ch1_header.format || ch1_header.gain) - goto fail; - - /* check for agreement */ - if ( - ch0_header.sample_count != ch1_header.sample_count || - ch0_header.nibble_count != ch1_header.nibble_count || - ch0_header.sample_rate != ch1_header.sample_rate || - ch0_header.loop_flag != ch1_header.loop_flag || - ch0_header.loop_start_offset != ch1_header.loop_start_offset || - ch0_header.loop_end_offset != ch1_header.loop_end_offset - ) goto fail; - - if (ch0_header.loop_flag) - { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch0_header.loop_start_offset/16*8; - - if (ch0_header.loop_ps != (uint8_t)read_8bit(ch1_start+loop_off,streamFile)) - goto fail; - if (ch1_header.loop_ps != (uint8_t)read_8bit(ch2_start+loop_off,streamFile)) - goto fail; - } + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,ch0_header.loop_flag); - if (!vgmstream) goto fail; - - /* fill in the vital statistics */ - vgmstream->num_samples = ch0_header.sample_count; - vgmstream->sample_rate = ch0_header.sample_rate; - - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; - - vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = ch2_start-ch1_start; - vgmstream->meta_type = meta_NGC_DSP_AAAP; - - /* coeffs */ - for (i=0;i<16;i++) { - vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i]; - vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i]; - } - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1; - vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2; - vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1; - vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2; - - /* open the file for reading */ - vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) - goto fail; - vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; - - vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[1].streamfile) - goto fail; - vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; - - return vgmstream; - -fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); - return NULL; -} - - -/* .dspw files, multiple DSP files stuck together */ -/* found in Sengoku Basara 3 Wii */ -VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { - VGMSTREAM * vgmstream = NULL; - char filename[PATH_LIMIT]; - - off_t streamSize, mrkrOffset, channelSpacing; - int channel_count, i, j; - int found_mrkr = 0; - VARDECL(struct dsp_header, ch_header); - VARDECL(off_t, channel_start); - - channel_count = (unsigned char)read_8bit(0x1B, streamFile); - - ALLOC(ch_header, channel_count, struct dsp_header); - ALLOC(channel_start, channel_count, off_t); - - /* check extension, case insensitive */ - streamFile->get_name(streamFile,filename,sizeof(filename)); - if (strcasecmp("dspw",filename_extension(filename))) goto fail; - - if (read_32bitBE(0x0,streamFile) != 0x44535057) // DSPW - goto fail; - - streamSize = read_32bitBE(0x8, streamFile); - - - if (read_32bitBE(streamSize - 0x10, streamFile) == 0x74494D45) // tIME - streamSize -= 0x10; - - mrkrOffset = streamSize - 4; - while ((mrkrOffset > streamSize - 0x1000) && !(found_mrkr)) { // some files have a mrkr section with multiple loop regions at the end - if (read_32bitBE(mrkrOffset, streamFile) != 0x6D726B72) // mrkr - mrkrOffset -= 4; - else { - streamSize = mrkrOffset; - found_mrkr++; - } - } - streamSize -= 0x20; // minus the main header - channelSpacing = streamSize / channel_count; - - /* read .dspw header */ - for (i = 0; i < channel_count; i++) { - channel_start[i] = 0x20 + i*channelSpacing; - - /* get DSP headers */ - if (read_dsp_header(&ch_header[i], channel_start[i], streamFile)) goto fail; - - /* check initial predictor/scale */ - if (ch_header[i].initial_ps != - (uint8_t)read_8bit(channel_start[i] + 0x60, streamFile)) - goto fail; - - /* check type==0 and gain==0 */ - if (ch_header[i].format || ch_header[i].gain) - goto fail; - - /* check for agreement */ - if (i > 0) { - if ( - ch_header[i].sample_count != ch_header[i-1].sample_count || - ch_header[i].nibble_count != ch_header[i-1].nibble_count || - ch_header[i].sample_rate != ch_header[i-1].sample_rate || - ch_header[i].loop_flag != ch_header[i-1].loop_flag || - ch_header[i].loop_start_offset != ch_header[i-1].loop_start_offset || - ch_header[i].loop_end_offset != ch_header[i-1].loop_end_offset - ) goto fail; - } - - if (ch_header[0].loop_flag) { - off_t loop_off; - /* check loop predictor/scale */ - loop_off = ch_header[0].loop_start_offset/16*8; - if (ch_header[i].loop_ps != - (uint8_t)read_8bit(channel_start[i]+0x60+loop_off,streamFile)) - goto fail; - } - } - /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); if (!vgmstream) goto fail; - /* fill in the vital statistics */ - vgmstream->num_samples = ch_header[0].sample_count; vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch_header[0].loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch_header[0].loop_end_offset)+1; - + vgmstream->meta_type = meta_NGC_DSP_AAAP; vgmstream->coding_type = coding_NGC_DSP; - vgmstream->layout_type = layout_none; - // vgmstream->layout_type = layout_interleave; - // vgmstream->interleave_block_size = channelSpacing; - vgmstream->meta_type = meta_DSP_DSPW; - - /* coeffs */ - for (i=0;ich[i].adpcm_coef[j] = ch_header[i].coef[j]; - } - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ - vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1; - vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2; - } - - - - /* open the file for reading */ - - for (i=0;ich[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[i].streamfile) goto fail; - - vgmstream->ch[i].channel_start_offset = - vgmstream->ch[i].offset=channel_start[i]+0x60; - } + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; return vgmstream; - /* clean up anything we may have opened */ fail: - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); + return NULL; +} + + +#define DSPW_MAX_CHANNELS 6 /* 6ch in Monster Hunter 3 Ultimate */ +/* DSPW - Capcom header + full interleaved DSP [Sengoku Basara 3 (Wii), Monster Hunter 3 Ultimate (WiiU)] */ +VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave, data_size; + int channel_count; + struct dsp_header ch_header[DSPW_MAX_CHANNELS]; + + /* check extension */ + if (!check_extensions(streamFile, "dspw")) + goto fail; + if (read_32bitBE(0x00,streamFile) != 0x44535057) /* "DSPW" */ + goto fail; + + + /* 0x10: loop start, 0x14: loop end, 0x1c: num_samples */ + channel_count = read_32bitBE(0x18, streamFile); + if (channel_count > DSPW_MAX_CHANNELS) goto fail; + + data_size = read_32bitBE(0x08, streamFile); + if (read_32bitBE(data_size - 0x10, streamFile) == 0x74494D45) /* "tIME" */ + data_size -= 0x10; /* (ignore, 2 ints in YYYYMMDD hhmmss00) */ + + /* some files have a mrkr section with multiple loop regions added at the end (variable size) */ + { + off_t mrkr_offset = data_size - 0x04; + off_t max_offset = data_size - 0x1000; + while (mrkr_offset > max_offset) { + if (read_32bitBE(mrkr_offset, streamFile) != 0x6D726B72) { /* "mrkr" */ + mrkr_offset -= 0x04; + } else { + data_size = mrkr_offset; + break; + } + } + } + data_size -= 0x20; /* header size */ + + header_offset = 0x20; + header_spacing = data_size / channel_count; + start_offset = header_offset + 0x60; + interleave = data_size / channel_count; + + /* read dsp */ + if (!dsp_load_header(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; + if (!check_dsp_format(ch_header, channel_count)) goto fail; + if (!check_dsp_samples(ch_header, channel_count)) goto fail; + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag); + if (!vgmstream) goto fail; + + vgmstream->sample_rate = ch_header[0].sample_rate; + vgmstream->num_samples = ch_header[0].sample_count; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch_header[0].loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch_header[0].loop_end_offset)+1; + + vgmstream->meta_type = meta_DSP_DSPW; + vgmstream->coding_type = coding_NGC_DSP; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = interleave; + setup_vgmstream_dsp(vgmstream, ch_header); + + if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); return NULL; } @@ -2468,11 +1983,11 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("iadp",filename_extension(filename))) - goto fail; + goto fail; /* check header */ if (read_32bitBE(0x0,streamFile) != 0x69616470) /* iadp */ - goto fail; + goto fail; channel_count = read_32bitBE(0x4,streamFile); @@ -2531,10 +2046,8 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { vgmstream->num_samples = ch0_header.sample_count; vgmstream->sample_rate = ch0_header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - ch0_header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - ch0_header.loop_end_offset)+1; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(ch0_header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(ch0_header.loop_end_offset)+1; vgmstream->coding_type = coding_NGC_DSP; vgmstream->interleave_block_size = read_32bitBE(0x8,streamFile); @@ -2557,12 +2070,12 @@ VGMSTREAM * init_vgmstream_ngc_dsp_iadp(STREAMFILE *streamFile) { /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[0].streamfile) - goto fail; + goto fail; vgmstream->ch[0].channel_start_offset = vgmstream->ch[0].offset=ch1_start; vgmstream->ch[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); if (!vgmstream->ch[1].streamfile) - goto fail; + goto fail; vgmstream->ch[1].channel_start_offset = vgmstream->ch[1].offset=ch2_start; return vgmstream; @@ -2573,58 +2086,42 @@ fail: return NULL; } -/* the csmp format from Metroid Prime 3 and DKCR */ - -#define CSMP_MAGIC 0x43534D50 -#define CSMP_DATA 0x44415441 - -struct csmp_chunk { - uint32_t id; - uint32_t length; -}; - +//todo might be only part of a full header? +/* CSMP - Retro Studios header + interleaved DSPs [Metroid Prime 3 (Wii), Donkey Kong Country Returns (Wii)] */ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; + off_t start_offset; char filename[PATH_LIMIT]; long current_offset; int tries; - struct dsp_header header; - const off_t start_offset = 0x60; - int i; - int csmp_magic; - int csmp_version; + int chanel_count, i; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("csmp",filename_extension(filename))) goto fail; - current_offset = 0; + if (read_32bitBE(0x00, streamFile) != 0x43534D50) /* "CSMP" */ + goto fail; + if (read_32bitBE(0x04, streamFile) != 1) /* version? */ + goto fail; - csmp_magic = read_32bitBE(current_offset, streamFile); - if (csmp_magic != CSMP_MAGIC) goto fail; + chanel_count = 1; + start_offset = 0x60; - current_offset += 4; - - csmp_version = read_32bitBE(current_offset, streamFile); - if (csmp_version != 1) goto fail; - - current_offset += 4; - - tries =0; - while (1) - { - struct csmp_chunk chunk; + current_offset = 0x08; + tries = 0; + while (1) { + uint32_t chunk_id, chunk_size; if (tries > 4) goto fail; - - chunk.id = read_32bitBE(current_offset, streamFile); - chunk.length = read_32bitBE(current_offset + 4, streamFile); - current_offset += 8; - if (chunk.id != CSMP_DATA) - { - current_offset += chunk.length; + + chunk_id = read_32bitBE(current_offset + 0x00, streamFile); + chunk_size = read_32bitBE(current_offset + 0x04, streamFile); + current_offset += 0x08; + if (chunk_id != 0x44415441) { /* "DATA" */ + current_offset += chunk_size; tries++; continue; } @@ -2632,10 +2129,12 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { break; } - if (read_dsp_header(&header, current_offset, streamFile)) goto fail; + if (read_dsp_header(&header, current_offset, streamFile)) goto fail; + + /* check initial predictor/scale */ - /* Retro doesn't seem to abide by this */ + /* Retro doesn't seem to abide by this */ //if (header.initial_ps != (uint8_t)read_8bit(current_offset + start_offset,streamFile)) // goto fail; @@ -2647,7 +2146,7 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { // off_t loop_off; /* check loop predictor/scale */ // loop_off = header.loop_start_offset/16*8; - /* Retro doesn't seem to abide by this */ + /* Retro doesn't seem to abide by this */ // if (header.loop_ps != (uint8_t)read_8bit(current_offset + start_offset+loop_off,streamFile)) // goto fail; } @@ -2659,19 +2158,15 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { */ /* build the VGMSTREAM */ - - - vgmstream = allocate_vgmstream(1,header.loop_flag); + vgmstream = allocate_vgmstream(chanel_count,header.loop_flag); if (!vgmstream) goto fail; /* fill in the vital statistics */ vgmstream->num_samples = header.sample_count; vgmstream->sample_rate = header.sample_rate; - vgmstream->loop_start_sample = dsp_nibbles_to_samples( - header.loop_start_offset); - vgmstream->loop_end_sample = dsp_nibbles_to_samples( - header.loop_end_offset)+1; + vgmstream->loop_start_sample = dsp_nibbles_to_samples(header.loop_start_offset); + vgmstream->loop_end_sample = dsp_nibbles_to_samples(header.loop_end_offset)+1; /* don't know why, but it does happen*/ if (vgmstream->loop_end_sample > vgmstream->num_samples) @@ -2684,25 +2179,18 @@ VGMSTREAM * init_vgmstream_ngc_dsp_csmp(STREAMFILE *streamFile) { /* coeffs */ for (i=0;i<16;i++) vgmstream->ch[0].adpcm_coef[i] = header.coef[i]; - - /* initial history */ - /* always 0 that I've ever seen, but for completeness... */ vgmstream->ch[0].adpcm_history1_16 = header.initial_hist1; vgmstream->ch[0].adpcm_history2_16 = header.initial_hist2; /* open the file for reading */ vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); - if (!vgmstream->ch[0].streamfile) goto fail; - vgmstream->ch[0].channel_start_offset= - vgmstream->ch[0].offset=current_offset + start_offset; + vgmstream->ch[0].offset=current_offset + start_offset; return vgmstream; fail: - /* clean up anything we may have opened */ - if (vgmstream) close_vgmstream(vgmstream); + close_vgmstream(vgmstream); return NULL; } -