mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Merge pull request #90 from Thealexbarney/mdsp
Add support for multi-channel Nintendo dsp files
This commit is contained in:
commit
187c161409
@ -539,6 +539,7 @@ DECLARE_MULTIPLE_FILE_TYPE("MC3 Audio File (*.MC3)", mc3);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("MCA Audio File (*.MCA)", mca);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("MCG Audio File (*.MCG)", mcg);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("MDS Audio File (*.MDS)", mds);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("MDSP Audio File (*.MDSP)", dsp);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("PS2 MI4 Audio File (*.MI4)", mi4);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIB Audio File (*.MIB)", mib);
|
||||
DECLARE_MULTIPLE_FILE_TYPE("PS2 MIC Audio File (*.MIC)", mic);
|
||||
|
@ -27,6 +27,8 @@ VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_std(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_dsp_stm(STREAMFILE *streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_mpdsp(STREAMFILE *streamFile);
|
||||
|
@ -24,13 +24,15 @@ struct dsp_header {
|
||||
uint16_t loop_ps;
|
||||
int16_t loop_hist1;
|
||||
int16_t loop_hist2;
|
||||
int16_t channel_count;
|
||||
int16_t block_size;
|
||||
};
|
||||
|
||||
/* nonzero on failure */
|
||||
static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *file) {
|
||||
int i;
|
||||
uint8_t buf[0x4a]; /* usually padded out to 0x60 */
|
||||
if (read_streamfile(buf, offset, 0x4a, file) != 0x4a) return 1;
|
||||
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);
|
||||
@ -65,6 +67,10 @@ static int read_dsp_header(struct dsp_header *header, off_t offset, STREAMFILE *
|
||||
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;
|
||||
}
|
||||
@ -175,6 +181,81 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* the standard multi-channel .dsp, as generated by DSPADPCM.exe */
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_mdsp_std(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
struct dsp_header header;
|
||||
const off_t header_size = 0x60;
|
||||
off_t start_offset;
|
||||
int i, c, channel_count;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
||||
if (strcasecmp("dsp", filename_extension(filename)) &&
|
||||
strcasecmp("mdsp", filename_extension(filename))) goto fail;
|
||||
|
||||
if (read_dsp_header(&header, 0, streamFile)) goto fail;
|
||||
|
||||
channel_count = header.channel_count==0 ? 1 : header.channel_count;
|
||||
start_offset = header_size * channel_count;
|
||||
|
||||
/* check initial predictor/scale */
|
||||
if (header.initial_ps != (uint8_t)read_8bit(start_offset, streamFile))
|
||||
goto fail;
|
||||
|
||||
/* check type==0 and gain==0 */
|
||||
if (header.format || header.gain)
|
||||
goto fail;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
|
||||
vgmstream = allocate_vgmstream(channel_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;
|
||||
|
||||
/* don't know why, but it does happen*/
|
||||
if (vgmstream->loop_end_sample > vgmstream->num_samples)
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave;
|
||||
vgmstream->meta_type = meta_DSP_STD;
|
||||
vgmstream->interleave_block_size = header.block_size * 8;
|
||||
|
||||
for (i = 0; i < channel_count; i++) {
|
||||
if (read_dsp_header(&header, header_size * i, streamFile)) goto fail;
|
||||
|
||||
/* coeffs */
|
||||
for (c = 0; c < 16; c++)
|
||||
vgmstream->ch[i].adpcm_coef[c] = header.coef[c];
|
||||
|
||||
/* initial history */
|
||||
/* always 0 that I've ever seen, but for completeness... */
|
||||
vgmstream->ch[i].adpcm_history1_16 = header.initial_hist1;
|
||||
vgmstream->ch[i].adpcm_history2_16 = header.initial_hist2;
|
||||
}
|
||||
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Some very simple stereo variants of standard dsp just use the standard header
|
||||
* twice and add interleave, or just concatenate the channels. We'll support
|
||||
* them all here.
|
||||
|
@ -36,6 +36,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_halpst,
|
||||
init_vgmstream_rs03,
|
||||
init_vgmstream_ngc_dsp_std,
|
||||
init_vgmstream_ngc_mdsp_std,
|
||||
init_vgmstream_ngc_dsp_csmp,
|
||||
init_vgmstream_Cstr,
|
||||
init_vgmstream_gcsw,
|
||||
|
Loading…
x
Reference in New Issue
Block a user