diff --git a/src/formats.c b/src/formats.c index d446b535..f2252cc3 100644 --- a/src/formats.c +++ b/src/formats.c @@ -425,6 +425,7 @@ static const char* extension_list[] = { "sb5", "sb6", "sb7", + "sbk", "sbr", "sbv", "sm0", @@ -1319,6 +1320,7 @@ static const meta_info meta_info_list[] = { {meta_WADY, "Marble WADY header"}, {meta_DSP_SQEX, "Square Enix DSP header"}, {meta_DSP_WIIVOICE, "Koei Tecmo WiiVoice header"}, + {meta_SBK, "Team17 SBK header"}, }; void get_vgmstream_coding_description(VGMSTREAM* vgmstream, char* out, size_t out_size) { diff --git a/src/libvgmstream.vcxproj b/src/libvgmstream.vcxproj index a63a593d..892c94f3 100644 --- a/src/libvgmstream.vcxproj +++ b/src/libvgmstream.vcxproj @@ -227,6 +227,7 @@ + diff --git a/src/libvgmstream.vcxproj.filters b/src/libvgmstream.vcxproj.filters index 9d76bc4a..8dda843c 100644 --- a/src/libvgmstream.vcxproj.filters +++ b/src/libvgmstream.vcxproj.filters @@ -1834,5 +1834,8 @@ meta\Source Files + + meta\Source Files + \ No newline at end of file diff --git a/src/meta/meta.h b/src/meta/meta.h index c19b9c13..31ee4039 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -928,4 +928,6 @@ VGMSTREAM* init_vgmstream_wady(STREAMFILE* sf); VGMSTREAM* init_vgmstream_cpk(STREAMFILE* sf); VGMSTREAM* init_vgmstream_cpk_memory(STREAMFILE* sf, STREAMFILE* sf_acb); +VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf); + #endif /*_META_H*/ diff --git a/src/meta/sbk.c b/src/meta/sbk.c new file mode 100644 index 00000000..b6dc82e6 --- /dev/null +++ b/src/meta/sbk.c @@ -0,0 +1,95 @@ +#include "meta.h" +#include "../coding/coding.h" + +/* .SBK - from Addiction Pinball (PC) */ +VGMSTREAM *init_vgmstream_sbk(STREAMFILE *sf) { + VGMSTREAM *vgmstream = NULL; + uint32_t sound_offset, sound_size, padding_size, sample_rate; + uint16_t format, channels, block_size, bps; + off_t table_offset, data_offset, entry_offset, start_offset; + size_t table_size, data_size; + int target_subsong = sf->stream_index, total_subsongs, loop_flag; + + /* checks */ + if (!check_extensions(sf, "sbk")) + goto fail; + + /* check header */ + if (read_u32be(0x00, sf) != 0x52494646) /* "RIFF" */ + goto fail; + if (read_u32be(0x08, sf) != 0x53424E4B) /* "SBNK" */ + goto fail; + + if (!find_chunk_le(sf, 0x57415649, 0x0c, 0, &table_offset, &table_size)) /* "WAVI" */ + goto fail; + + total_subsongs = table_size / 0x38; + + if (target_subsong == 0) target_subsong = 1; + if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) + goto fail; + + entry_offset = table_offset + 0x38 * (target_subsong - 1); + sound_offset = read_u32le(entry_offset + 0x04, sf); + sound_size = read_u32le(entry_offset + 0x00, sf); + padding_size = read_u32le(entry_offset + 0x10, sf); + sound_offset += padding_size; + sound_size -= padding_size; + + /* read fmt chunk */ + format = read_u16le(entry_offset + 0x1c, sf); + channels = read_u16le(entry_offset + 0x1e, sf); + sample_rate = read_u32le(entry_offset + 0x20, sf); + block_size = read_u16le(entry_offset + 0x28, sf); + bps = read_u16le(entry_offset + 0x2a, sf); + + loop_flag = 0; + + /* build the VGMSTREAM */ + vgmstream = allocate_vgmstream(channels, loop_flag); + if (!vgmstream) goto fail; + + /* fill in the vital statistics */ + vgmstream->meta_type = meta_SBK; + vgmstream->sample_rate = sample_rate; + vgmstream->stream_size = sound_size; + vgmstream->num_streams = total_subsongs; + + switch (format) { + case 0x01: /* PCM */ + if (bps != 8 && bps != 16) + goto fail; + + vgmstream->coding_type = (bps == 8) ? coding_PCM8_U : coding_PCM16LE; + vgmstream->layout_type = layout_interleave; + vgmstream->interleave_block_size = (bps == 8) ? 0x01 : 0x02; + vgmstream->num_samples = pcm_bytes_to_samples(sound_size, channels, bps); + + if (!find_chunk_le(sf, 0x57415644, 0x0c, 0, &data_offset, &data_size)) /* "WAVD" */ + goto fail; + + start_offset = data_offset + sound_offset; + break; + case 0x11: /* Microsoft IMA */ + vgmstream->coding_type = coding_MS_IMA; + vgmstream->layout_type = layout_none; + vgmstream->interleave_block_size = block_size; + vgmstream->num_samples = ms_ima_bytes_to_samples(sound_size, block_size, channels); + + if (!find_chunk_le(sf, 0x53574156, 0x0c, 0, &data_offset, &data_size)) /* "SWAV" */ + goto fail; + + start_offset = data_offset + sound_offset; + break; + default: + goto fail; + } + + if (!vgmstream_open_stream(vgmstream, sf, start_offset)) + goto fail; + return vgmstream; + +fail: + close_vgmstream(vgmstream); + return NULL; +} diff --git a/src/meta/ubi_sb.c b/src/meta/ubi_sb.c index 93a73fc1..a6afc335 100644 --- a/src/meta/ubi_sb.c +++ b/src/meta/ubi_sb.c @@ -1868,7 +1868,7 @@ static int parse_type_audio(ubi_sb_header* sb, off_t offset, STREAMFILE* sf) { /* apparently, there may also be other subblocks based on various flags but they were not seen so far */ if (sb->cfg.audio_subblock_flag && sb->cfg.audio_subblock_and) { - /* flag probably means "hardware decoded" */ + /* flag probably means "software decoded" */ int subblock_flag = read_32bit(offset + sb->cfg.audio_subblock_flag, sf) & sb->cfg.audio_subblock_and; sb->subblock_id = (!subblock_flag) ? 0 : 1; @@ -3039,7 +3039,6 @@ static int config_sb_version(ubi_sb_header* sb, STREAMFILE* sf) { config_sb_sequence(sb, 0x2c, 0x1c); /* no layers */ - return 1; } diff --git a/src/vgmstream.c b/src/vgmstream.c index ad6cf472..b86ffe9c 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -512,6 +512,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_xws, init_vgmstream_cpk, init_vgmstream_opus_nsopus, + init_vgmstream_sbk, /* 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 */ diff --git a/src/vgmstream.h b/src/vgmstream.h index 915b30e4..f4f5783b 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -741,6 +741,7 @@ typedef enum { meta_WADY, meta_DSP_SQEX, meta_DSP_WIIVOICE, + meta_SBK, } meta_t; /* standard WAVEFORMATEXTENSIBLE speaker positions */