diff --git a/src/formats.c b/src/formats.c index 6a6352d0..22c5bfe6 100644 --- a/src/formats.c +++ b/src/formats.c @@ -183,6 +183,7 @@ static const char* extension_list[] = { "matx", "mc3", "mca", + "mcadpcm", "mcg", "mds", "mdsp", @@ -982,6 +983,7 @@ static const meta_info meta_info_list[] = { {meta_STHD, "Dream Factory STHD header"}, {meta_MP4, "MP4/AAC header"}, {meta_PCM_SRE, "Capcom .PCM+SRE header"}, + {meta_DSP_MCADPCM, "Bethesda .mcadpcm header"}, #ifdef VGM_USE_FFMPEG {meta_FFmpeg, "FFmpeg supported file format"}, diff --git a/src/meta/meta.h b/src/meta/meta.h index d8ea7abe..945f2a5e 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -727,4 +727,6 @@ VGMSTREAM * init_vgmstream_ngc_dsp_std_le(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_pcm_sre(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile); + #endif /*_META_H*/ diff --git a/src/meta/ngc_dsp_std.c b/src/meta/ngc_dsp_std.c index f38e7b99..0eeed7c5 100644 --- a/src/meta/ngc_dsp_std.c +++ b/src/meta/ngc_dsp_std.c @@ -80,12 +80,12 @@ static void setup_vgmstream_dsp(VGMSTREAM* vgmstream, struct dsp_header* ch_head } } -static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { +static int dsp_load_header_endian(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing, int big_endian) { 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)) + if (read_dsp_header_endian(&ch_header[i], offset + i*spacing, streamFile, big_endian)) goto fail; } @@ -93,6 +93,12 @@ static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFIL fail: return 0; } +static int dsp_load_header(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 1); +} +static int dsp_load_header_le(struct dsp_header* ch_header, int channels, STREAMFILE *streamFile, off_t offset, size_t spacing) { + return dsp_load_header_endian(ch_header, channels, streamFile, offset, spacing, 0); +} static int check_dsp_format(struct dsp_header* ch_header, int channels) { int i; @@ -1283,7 +1289,7 @@ fail: } #define WSD_MAX_CHANNELS 2 -/* .wsd - Custom heade + full interleaved dsp [Phantom Brave (Wii)] */ +/* .wsd - Custom header + full interleaved dsp [Phantom Brave (Wii)] */ VGMSTREAM * init_vgmstream_wii_wsd(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset, header_offset; @@ -2056,3 +2062,63 @@ fail: close_vgmstream(vgmstream); return NULL; } + +#define MCADPCM_MAX_CHANNELS 2 +/* .mcadpcm - Custom header + full interleaved dsp [Skyrim (Switch)] */ +VGMSTREAM * init_vgmstream_dsp_mcadpcm(STREAMFILE *streamFile) { + VGMSTREAM * vgmstream = NULL; + off_t start_offset, header_offset; + size_t header_spacing, interleave; + int channel_count; + struct dsp_header ch_header[MCADPCM_MAX_CHANNELS]; + + /* checks */ + if (!check_extensions(streamFile, "mcadpcm")) + goto fail; +VGM_LOG("1\n"); + if (read_32bitLE(0x08,streamFile) != read_32bitLE(0x10,streamFile)) /* dsp sizes */ + goto fail; +VGM_LOG("2\n"); + channel_count = read_32bitLE(0x00,streamFile); + if (channel_count > MCADPCM_MAX_CHANNELS) goto fail; + + header_offset = read_32bitLE(0x04,streamFile); + header_spacing = read_32bitLE(0x08,streamFile); /* technically dsp size but eh */ + start_offset = header_offset + 0x60; + interleave = header_spacing; +VGM_LOG("3\n"); + /* read dsp */ + if (!dsp_load_header_le(ch_header, channel_count, streamFile,header_offset,header_spacing)) goto fail; +VGM_LOG("4\n"); + if (!check_dsp_format(ch_header, channel_count)) goto fail; +VGM_LOG("5\n"); + if (!check_dsp_samples(ch_header, channel_count)) goto fail; +VGM_LOG("6\n"); + if (!check_dsp_initial_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; +VGM_LOG("7\n"); + if (!check_dsp_loop_ps(ch_header, channel_count, streamFile,start_offset,interleave)) goto fail; +VGM_LOG("8\n"); + + /* 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_MCADPCM; + 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; +} diff --git a/src/vgmstream.c b/src/vgmstream.c index b462feb1..ad11378f 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -392,6 +392,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = { init_vgmstream_ea_wve_ad10, init_vgmstream_sthd, init_vgmstream_pcm_sre, + init_vgmstream_dsp_mcadpcm, init_vgmstream_txth, /* should go at the end (lower priority) */ #ifdef VGM_USE_FFMPEG diff --git a/src/vgmstream.h b/src/vgmstream.h index 7b128258..b73a692b 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -667,6 +667,7 @@ typedef enum { meta_STHD, /* STHD .stx [Kakuto Chojin (Xbox)] */ meta_MP4, /* MP4/AAC */ meta_PCM_SRE, /* .PCM+SRE [Viewtiful Joe (PS2)] */ + meta_DSP_MCADPCM, /* Skyrim (Switch) */ #ifdef VGM_USE_FFMPEG meta_FFmpeg,