diff --git a/src/meta/ea_schl.c b/src/meta/ea_schl.c index 7c90848f..378795b6 100644 --- a/src/meta/ea_schl.c +++ b/src/meta/ea_schl.c @@ -454,18 +454,9 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE* sf) { goto fail; /* build the VGMSTREAM */ - vgmstream = allocate_vgmstream(data_s->segments[0]->channels, 1); - if (!vgmstream) goto fail; - - vgmstream->sample_rate = data_s->segments[0]->sample_rate; - vgmstream->num_samples = data_s->segments[0]->num_samples + data_s->segments[1]->num_samples; - vgmstream->loop_start_sample = data_s->segments[0]->num_samples; - vgmstream->loop_end_sample = vgmstream->num_samples; - - vgmstream->meta_type = meta_EA_SCHL; - vgmstream->coding_type = data_s->segments[0]->coding_type; - vgmstream->layout_type = layout_segmented; - vgmstream->layout_data = data_s; + vgmstream = allocate_segmented_vgmstream(data_s, 1, 1, 1); + if (!vgmstream) + goto fail; break; default: @@ -810,12 +801,12 @@ fail: VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_mus = NULL; - off_t tracks_table, samples_table, section_offset, entry_offset, eof_offset, off_mult, sound_offset; - uint32_t track_start, track_hash = 0; + segmented_layout_data *data_s = NULL; + uint32_t track_start, track_end, track_hash, tracks_table, samples_table, section_offset, entry_offset, eof_offset, off_mult, sound_offset; uint16_t num_nodes; uint8_t version, sub_version, num_tracks, num_sections, num_events, num_routers, num_vars, subentry_num; - int32_t(*read_32bit)(off_t, STREAMFILE*); - int16_t(*read_16bit)(off_t, STREAMFILE*); + int32_t(*read_u32)(off_t, STREAMFILE*); + int16_t(*read_u16)(off_t, STREAMFILE*); int i; int target_stream = sf->stream_index, total_streams, big_endian, is_bnk = 0; @@ -825,29 +816,29 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { /* detect endianness */ if (read_32bitBE(0x00, sf) == 0x50464478) { /* "PFDx" */ - read_32bit = read_32bitBE; - read_16bit = read_16bitBE; + read_u32 = read_u32be; + read_u16 = read_u16be; big_endian = 1; } else if (read_32bitLE(0x00, sf) == 0x50464478) { /* "xDFP" */ - read_32bit = read_32bitLE; - read_16bit = read_16bitLE; + read_u32 = read_u32le; + read_u16 = read_u16le; big_endian = 0; } else { goto fail; } - version = read_8bit(0x04, sf); - sub_version = read_8bit(0x05, sf); + version = read_u8(0x04, sf); + sub_version = read_u8(0x05, sf); if (version < 3 || version > 5) goto fail; if (version == 5 && sub_version > 2) goto fail; /* newer version using SNR/SNS */ - num_tracks = read_8bit(0x0d, sf); - num_sections = read_8bit(0x0e, sf); - num_events = read_8bit(0x0f, sf); - num_routers = read_8bit(0x10, sf); - num_vars = read_8bit(0x11, sf); - num_nodes = read_16bit(0x12, sf); + num_tracks = read_u8(0x0d, sf); + num_sections = read_u8(0x0e, sf); + num_events = read_u8(0x0f, sf); + num_routers = read_u8(0x10, sf); + num_vars = read_u8(0x11, sf); + num_nodes = read_u16(0x12, sf); /* HACK: number of sub-entries for nodes and events is stored in bitstreams that are different in LE and BE */ /* I can't figure it out, so let's just use a workaround for now */ @@ -857,19 +848,19 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { if (version == 3) /* SSX Tricky (v3.1), Harry Potter and the Chamber of Secrets (v3.4) */ { /* we need to go through all the sections to get to the samples table */ - if (sub_version != 1 && sub_version != 4) + if (sub_version != 1 && sub_version != 2 && sub_version != 4) goto fail; /* get the last entry offset */ section_offset = 0x24; - entry_offset = (uint16_t)read_16bit(section_offset + (num_nodes - 1) * 0x02, sf) * 0x04; - if (sub_version == 1) { - subentry_num = read_8bit(entry_offset + 0x0b, sf); + entry_offset = read_u16(section_offset + (num_nodes - 1) * 0x02, sf) * 0x04; + if (sub_version == 1 || sub_version == 2) { + subentry_num = read_u8(entry_offset + 0x0b, sf); } else if (sub_version == 4) { if (big_endian) { - subentry_num = (read_32bitBE(entry_offset + 0x04, sf) >> 19) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x04, sf) >> 19) & 0xFF; } else { - subentry_num = (read_32bitBE(entry_offset + 0x04, sf) >> 16) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x04, sf) >> 16) & 0xFF; } } section_offset = entry_offset + 0x0c + subentry_num * 0x04; @@ -877,97 +868,104 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { section_offset += align_size_to_block(num_events * num_tracks * num_sections, 0x04); section_offset += num_routers * 0x04; section_offset += num_vars * 0x04; - tracks_table = read_32bit(section_offset, sf) * 0x04; - if (sub_version == 1) + + tracks_table = read_u32(section_offset, sf) * 0x04; + if (sub_version == 1 || sub_version == 2) samples_table = tracks_table + num_tracks * 0x04; else if (sub_version == 4) samples_table = tracks_table + (num_tracks + 1) * 0x04; + if (sub_version == 1 || sub_version == 2) + eof_offset = get_streamfile_size(sf); + else if (sub_version == 4) + eof_offset = read_u32(tracks_table + num_tracks * 0x04, sf) * 0x04; + total_streams = (eof_offset - samples_table) / 0x08; + off_mult = 0x04; + + track_start = total_streams; for (i = num_tracks - 1; i >= 0; i--) { - track_start = read_32bit(tracks_table + i * 0x04, sf) * 0x04; + track_end = track_start; + track_start = read_u32(tracks_table + i * 0x04, sf) * 0x04; track_start = (track_start - samples_table) / 0x08; if (track_start <= target_stream - 1) break; } - - - if (sub_version == 1) - eof_offset = get_streamfile_size(sf); - else if (sub_version == 4) - eof_offset = read_32bit(tracks_table + num_tracks * 0x04, sf) * 0x04; - total_streams = (eof_offset - samples_table) / 0x08; - off_mult = 0x04; } else if (version == 4) { /* Need for Speed: Underground 2, SSX 3, Harry Potter and the Prisoner of Azkaban */ /* we need to go through all the sections to get to the samples table */ /* get the last entry offset */ section_offset = 0x20; - entry_offset = (uint16_t)read_16bit(section_offset + (num_nodes - 1) * 0x02, sf) * 0x04; + entry_offset = read_u16(section_offset + (num_nodes - 1) * 0x02, sf) * 0x04; if (big_endian) { - subentry_num = (read_32bitBE(entry_offset + 0x04, sf) >> 15) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x04, sf) >> 15) & 0xFF; } else { - subentry_num = (read_32bitBE(entry_offset + 0x04, sf) >> 20) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x04, sf) >> 20) & 0xFF; } section_offset = entry_offset + 0x10 + subentry_num * 0x04; /* get the last entry offset */ - entry_offset = (uint16_t)read_16bit(section_offset + (num_events - 1) * 0x02, sf) * 0x04; + entry_offset = read_u16(section_offset + (num_events - 1) * 0x02, sf) * 0x04; if (big_endian) { - subentry_num = (read_32bitBE(entry_offset + 0x0c, sf) >> 10) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x0c, sf) >> 10) & 0xFF; } else { - subentry_num = (read_32bitBE(entry_offset + 0x0c, sf) >> 8) & 0xFF; + subentry_num = (read_u32be(entry_offset + 0x0c, sf) >> 8) & 0xFF; } section_offset = entry_offset + 0x10 + subentry_num * 0x10; /* TODO: verify this */ - section_offset = read_32bit(section_offset, sf) * 0x04; + section_offset = read_u32(section_offset, sf) * 0x04; section_offset += num_routers * 0x04; section_offset += num_vars * 0x04; + tracks_table = section_offset; samples_table = tracks_table + (num_tracks + 1) * 0x04; + eof_offset = read_u32(tracks_table + num_tracks * 0x04, sf) * 0x04; + total_streams = (eof_offset - samples_table) / 0x08; + off_mult = 0x80; + + track_start = total_streams; for (i = num_tracks - 1; i >= 0; i--) { - track_start = read_32bit(tracks_table + i * 0x04, sf) * 0x04; + track_end = track_start; + track_start = read_u32(tracks_table + i * 0x04, sf) * 0x04; track_start = (track_start - samples_table) / 0x08; if (track_start <= target_stream - 1) break; } - - eof_offset = read_32bit(tracks_table + num_tracks * 0x04, sf) * 0x04; - total_streams = (eof_offset - samples_table) / 0x08; - off_mult = 0x80; } else if (version == 5) { /* Need for Speed: Most Wanted, Need for Speed: Carbon */ - tracks_table = read_32bit(0x2c, sf); - samples_table = read_32bit(0x34, sf); + tracks_table = read_u32(0x2c, sf); + samples_table = read_u32(0x34, sf); + eof_offset = read_u32(0x38, sf); + total_streams = (eof_offset - samples_table) / 0x08; + off_mult = 0x80; + + track_start = total_streams; for (i = num_tracks - 1; i >= 0; i--) { - entry_offset = read_32bit(tracks_table + i * 0x04, sf) * 0x04; - track_start = read_32bit(entry_offset + 0x00, sf); + track_end = track_start; + entry_offset = read_u32(tracks_table + i * 0x04, sf) * 0x04; + track_start = read_u32(entry_offset + 0x00, sf); if (track_start <= target_stream - 1) { - track_hash = read_32bitBE(entry_offset + 0x08, sf); + track_hash = read_u32be(entry_offset + 0x08, sf); is_bnk = (track_hash == 0xF1F1F1F1); /* checks to distinguish it from SNR/SNS version */ if (is_bnk) { - if (read_32bitBE(entry_offset + 0x0c, sf) == 0x00) + if (read_u32be(entry_offset + 0x0c, sf) == 0x00) goto fail; - track_hash = read_32bitBE(entry_offset + 0x14, sf); + track_hash = read_u32be(entry_offset + 0x14, sf); if (track_hash == 0xF1F1F1F1) continue; /* empty track */ } else { - if (read_32bitBE(entry_offset + 0x0c, sf) != 0x00) + if (read_u32be(entry_offset + 0x0c, sf) != 0x00) goto fail; } break; } } - - eof_offset = read_32bit(0x38, sf); - total_streams = (eof_offset - samples_table) / 0x08; - off_mult = 0x80; } else { goto fail; } @@ -981,21 +979,43 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { goto fail; if (version == 5) { - if (read_32bitBE(0x00, sf_mus) != track_hash) + if (read_u32be(0x00, sf_mus) != track_hash) goto fail; } else { - is_bnk = (read_32bitBE(0x00, sf_mus) == (big_endian ? EA_BNK_HEADER_BE : EA_BNK_HEADER_LE)); + is_bnk = (read_u32be(0x00, sf_mus) == (big_endian ? EA_BNK_HEADER_BE : EA_BNK_HEADER_LE)); } /* 0x00 - offset/BNK index, 0x04 - duration (in milliseconds) */ + sound_offset = read_u32(samples_table + (target_stream - 1) * 0x08 + 0x00, sf); + if (is_bnk) { - /* TODO: Harry Potter COS appears to reference only the first segments of multi-segment BNK sounds? */ - sound_offset = read_32bit(samples_table + (target_stream - 1) * 0x08 + 0x00, sf); - vgmstream = parse_bnk_header(sf_mus, version < 5 ? 0x00 : 0x100, sound_offset, 1); + /* for some reason, RAM segments are almost always split into multiple sounds (usually 4) */ + off_t bnk_offset = version < 5 ? 0x00 : 0x100; + int bnk_total_sounds = read_u16(0x06, sf_mus); + int bnk_segments; + + /* play until the next entry in MPF track or the end of BNK */ + if (target_stream < track_end) { + bnk_segments = read_u32(samples_table + (target_stream - 0) * 0x08 + 0x00, sf) - sound_offset; + } else { + bnk_segments = bnk_total_sounds - sound_offset; + } + + /* init layout */ + data_s = init_layout_segmented(bnk_segments); + if (!data_s) goto fail; + + for (i = 0; i < bnk_segments; i++) + data_s->segments[i] = parse_bnk_header(sf_mus, bnk_offset, sound_offset + i, 1); + + /* setup segmented VGMSTREAMs */ + if (!setup_layout_segmented(data_s)) goto fail; + + vgmstream = allocate_segmented_vgmstream(data_s, 0, 0, 0); if (!vgmstream) goto fail; } else { - sound_offset = read_32bit(samples_table + (target_stream - 1) * 0x08 + 0x00, sf) * off_mult; + sound_offset *= off_mult;; if (read_32bitBE(sound_offset, sf_mus) != EA_BLOCKID_HEADER) goto fail; @@ -1011,6 +1031,8 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE* sf) { fail: close_streamfile(sf_mus); + free_layout_segmented(data_s); + return NULL; }