mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Add FSB FADPCM decoding [Dead Rising 4 (PC), Sine Mora EX (Switch)]
This commit is contained in:
parent
3a11728846
commit
5e50819778
@ -136,6 +136,9 @@ void decode_mta2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
/* mc3_decoder */
|
||||
void decode_mc3(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
||||
/* fadpcm_decoder */
|
||||
void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
|
||||
/* ea_mt_decoder*/
|
||||
ea_mt_codec_data *init_ea_mt(int channel_count, int type);
|
||||
void decode_ea_mt(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
|
85
src/coding/fadpcm_decoder.c
Normal file
85
src/coding/fadpcm_decoder.c
Normal file
@ -0,0 +1,85 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* FADPCM table */
|
||||
static const int8_t fadpcm_coefs[8][2] = {
|
||||
{ 0 , 0 },
|
||||
{ 60 , 0 },
|
||||
{ 122 , 60 },
|
||||
{ 115 , 52 },
|
||||
{ 98 , 55 },
|
||||
{ 0 , 0 },
|
||||
{ 0 , 0 },
|
||||
{ 0 , 0 },
|
||||
};
|
||||
|
||||
/* FMOD's FADPCM, basically XA/PSX ADPCM with a fancy header layout.
|
||||
* Code/layout could be simplified but tries to emulate FMOD's code.
|
||||
* Algorithm and tables debugged from their PC DLLs. */
|
||||
void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
off_t frame_offset;
|
||||
int i, j, k;
|
||||
int block_samples, num_frame, samples_done = 0, sample_count = 0;
|
||||
int coef_index[8], shift_factor[8];
|
||||
int32_t hist1; //= stream->adpcm_history1_32;
|
||||
int32_t hist2; //= stream->adpcm_history2_32;
|
||||
|
||||
/* external interleave (fixed size), mono */
|
||||
block_samples = (0x8c - 0xc) * 2;
|
||||
num_frame = first_sample / block_samples;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
frame_offset = stream->offset + 0x8c*num_frame;
|
||||
|
||||
|
||||
/* parse 0xc header */
|
||||
{
|
||||
uint32_t coefs, shifts;
|
||||
coefs = read_32bitLE(frame_offset + 0x00, stream->streamfile);
|
||||
shifts = read_32bitLE(frame_offset + 0x04, stream->streamfile);
|
||||
hist1 = read_16bitLE(frame_offset + 0x08, stream->streamfile);
|
||||
hist2 = read_16bitLE(frame_offset + 0x0a, stream->streamfile);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
coef_index[i] = (coefs >> i*4) & 0x0f;
|
||||
shift_factor[i] = (shifts >> i*4) & 0x0f;
|
||||
}
|
||||
|
||||
/* header samples are not written to outbuf */
|
||||
}
|
||||
|
||||
|
||||
/* decode nibbles, grouped in 0x10 * 0x04 * 2 */
|
||||
for (i = 0; i < 8; i++) {
|
||||
off_t group_offset = frame_offset + 0x0c + 0x10*i;
|
||||
int32_t coef1 = fadpcm_coefs[(coef_index[i] % 0x07)][0]; /* indexes > 7 are repeats (ex. 0x9 is 0x2) */
|
||||
int32_t coef2 = fadpcm_coefs[(coef_index[i] % 0x07)][1];
|
||||
int32_t shift = 0x16 - shift_factor[i];
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
uint32_t nibbles = read_32bitLE(group_offset + 0x04*j, stream->streamfile);
|
||||
|
||||
for (k = 0; k < 8; k++) {
|
||||
int32_t new_sample;
|
||||
|
||||
new_sample = (nibbles >> k*4) & 0x0f;
|
||||
new_sample = (new_sample << 28) >> shift; /* sign extend + scale */
|
||||
new_sample = (new_sample - hist2*coef2 + hist1*coef1);
|
||||
new_sample = new_sample >> 6; /* (new_sample / 64) has minor rounding differences */
|
||||
new_sample = clamp16(new_sample);
|
||||
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = new_sample;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
hist2 = hist1;
|
||||
hist1 = new_sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//stream->adpcm_history1_32 = hist1;
|
||||
//stream->adpcm_history2_32 = hist2;
|
||||
}
|
@ -495,6 +495,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
|
||||
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
|
||||
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
|
||||
{coding_FADPCM, "FMOD FADPCM 4-bit ADCPM"},
|
||||
|
||||
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
|
||||
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
|
||||
|
@ -1478,6 +1478,10 @@
|
||||
RelativePath=".\coding\ea_xas_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\fadpcm_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\ffmpeg_decoder.c"
|
||||
>
|
||||
|
@ -429,6 +429,7 @@
|
||||
<ClCompile Include="coding\ea_mt_decoder.c" />
|
||||
<ClCompile Include="coding\ea_xa_decoder.c" />
|
||||
<ClCompile Include="coding\ea_xas_decoder.c" />
|
||||
<ClCompile Include="coding\fadpcm_decoder.c" />
|
||||
<ClCompile Include="coding\g719_decoder.c" />
|
||||
<ClCompile Include="coding\g721_decoder.c" />
|
||||
<ClCompile Include="coding\g7221_decoder.c" />
|
||||
|
@ -871,6 +871,9 @@
|
||||
<ClCompile Include="coding\ea_xas_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\fadpcm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\g721_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -110,7 +110,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
break;
|
||||
case 0x03: /* Loop Info */
|
||||
LoopStart = read_32bitLE(ExtraFlagStart+0x04,streamFile);
|
||||
if (ExtraFlagSize > 0x04) /* probably no needed */
|
||||
if (ExtraFlagSize > 0x04) /* probably not needed */
|
||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||
|
||||
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
||||
@ -118,9 +118,9 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
break;
|
||||
case 0x04: /* free comment, or maybe SFX info */
|
||||
break;
|
||||
//case 0x05: /* Unknown (32b) */
|
||||
// /* found in Tearaway Vita, value 0, first stream only */
|
||||
// break;
|
||||
//case 0x05: /* Unknown (32b) */
|
||||
// /* found in Tearaway Vita, value 0, first stream only */
|
||||
// break;
|
||||
case 0x06: /* XMA seek table */
|
||||
/* no need for it */
|
||||
break;
|
||||
@ -142,11 +142,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
* (xN entries)
|
||||
*/
|
||||
break;
|
||||
//case 0x0d: /* Unknown (32b) */
|
||||
// /* found in some XMA2 and Vorbis */
|
||||
// break;
|
||||
//case 0x0d: /* Unknown (32b) */
|
||||
// /* found in some XMA2/Vorbis/FADPCM */
|
||||
// break;
|
||||
default:
|
||||
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
||||
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x + 0x04 (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -336,7 +336,10 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||
#endif
|
||||
|
||||
case 0x10: /* FMOD_SOUND_FORMAT_FADPCM */
|
||||
goto fail;
|
||||
vgmstream->coding_type = coding_FADPCM;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x8c;
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
|
@ -1145,6 +1145,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
return 128*2;
|
||||
case coding_MC3:
|
||||
return 10;
|
||||
case coding_FADPCM:
|
||||
return 256; /* (0x8c - 0xc) * 2 */
|
||||
case coding_EA_MT:
|
||||
return 432;
|
||||
case coding_CRI_HCA:
|
||||
@ -1300,6 +1302,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 0x90;
|
||||
case coding_MC3:
|
||||
return 0x04;
|
||||
case coding_FADPCM:
|
||||
return 0x8c;
|
||||
case coding_EA_MT:
|
||||
return 0; /* variable (frames of bit counts or PCM frames) */
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
@ -1917,6 +1921,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
chan);
|
||||
}
|
||||
break;
|
||||
case coding_FADPCM:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_fadpcm(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_EA_MT:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_ea_mt(vgmstream, buffer+samples_written*vgmstream->channels+chan,
|
||||
|
@ -152,6 +152,7 @@ typedef enum {
|
||||
coding_MTAF, /* Konami MTAF ADPCM */
|
||||
coding_MTA2, /* Konami MTA2 ADPCM */
|
||||
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
|
||||
coding_FADPCM, /* FMOD FADPCM 4-bit ADCPM */
|
||||
|
||||
/* others */
|
||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
|
||||
|
Loading…
x
Reference in New Issue
Block a user