mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Add Platinum ADPCM for .wem [Bayonetta 2 (Switch)]
This commit is contained in:
parent
60b4cb8310
commit
057d66cf99
@ -339,6 +339,7 @@ are used in few games.
|
||||
- Paradigm MC3 ADPCM
|
||||
- FMOD FADPCM 4-bit ADPCM
|
||||
- Konami XMD 4-bit ADPCM
|
||||
- Platinum 4-bit ADPCM
|
||||
- Argonaut ASF 4-bit ADPCM
|
||||
- Ocean DSA 4-bit ADPCM
|
||||
- Circus XPCM ADPCM
|
||||
|
@ -183,6 +183,10 @@ void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacin
|
||||
void decode_oki16(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
size_t oki_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
/* ptadpcm_decoder */
|
||||
void decode_ptadpcm(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size);
|
||||
size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size);
|
||||
|
||||
/* ea_mt_decoder*/
|
||||
ea_mt_codec_data *init_ea_mt(int channels, int type);
|
||||
ea_mt_codec_data *init_ea_mt_loops(int channels, int pcm_blocks, int loop_sample, off_t *loop_offsets);
|
||||
|
98
src/coding/ptadpcm_decoder.c
Normal file
98
src/coding/ptadpcm_decoder.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include "coding.h"
|
||||
|
||||
|
||||
/* a somewhat IMA-like mix of step+step index all in one */
|
||||
static const int32_t ptadpcm_table[(16+16)*16] = { /* 16 of (step+index) + 16 values in a nibble */
|
||||
-14, 2, -10, 2, -7, 1, -5, 1, -3, 0, -2, 0, -1, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 3, 0, 5, 1, 7, 1, 10, 2, 14, 2,
|
||||
-28, 3, -20, 3, -14, 2, -10, 2, -7, 1, -5, 1, -3, 1, -1, 0,
|
||||
1, 0, 3, 1, 5, 1, 7, 1, 10, 2, 14, 2, 20, 3, 28, 3,
|
||||
-56, 4, -40, 4, -28, 3, -20, 3, -14, 2, -10, 2, -6, 2, -2, 1,
|
||||
2, 1, 6, 2, 10, 2, 14, 2, 20, 3, 28, 3, 40, 4, 56, 4,
|
||||
-112, 5, -80, 5, -56, 4, -40, 4, -28, 3, -20, 3, -12, 3, -4, 2,
|
||||
4, 2, 12, 3, 20, 3, 28, 3, 40, 4, 56, 4, 80, 5, 112, 5,
|
||||
-224, 6, -160, 6, -112, 5, -80, 5, -56, 4, -40, 4, -24, 4, -8, 3,
|
||||
8, 3, 24, 4, 40, 4, 56, 4, 80, 5, 112, 5, 160, 6, 224, 6,
|
||||
-448, 7, -320, 7, -224, 6, -160, 6, -112, 5, -80, 5, -48, 5, -16, 4,
|
||||
16, 4, 48, 5, 80, 5, 112, 5, 160, 6, 224, 6, 320, 7, 448, 7,
|
||||
-896, 8, -640, 8, -448, 7, -320, 7, -224, 6, -160, 6, -96, 6, -32, 5,
|
||||
32, 5, 96, 6, 160, 6, 224, 6, 320, 7, 448, 7, 640, 8, 896, 8,
|
||||
-1792, 9, -1280, 9, -896, 8, -640, 8, -448, 7, -320, 7, -192, 7, -64, 6,
|
||||
64, 6, 192, 7, 320, 7, 448, 7, 640, 8, 896, 8, 1280, 9, 1792, 9,
|
||||
-3584, 10, -2560, 10, -1792, 9, -1280, 9, -896, 8, -640, 8, -384, 8, -128, 7,
|
||||
128, 7, 384, 8, 640, 8, 896, 8, 1280, 9, 1792, 9, 2560, 10, 3584, 10,
|
||||
-7168, 11, -5120, 11, -3584, 10, -2560, 10, -1792, 9, -1280, 9, -768, 9, -256, 8,
|
||||
256, 8, 768, 9, 1280, 9, 1792, 9, 2560, 10, 3584, 10, 5120, 11, 7168, 11,
|
||||
-14336, 11, -10240, 11, -7168, 11, -5120, 11, -3584, 10, -2560, 10, -1536, 10, -512, 9,
|
||||
512, 9, 1536, 10, 2560, 10, 3584, 10, 5120, 11, 7168, 11, 10240, 11, 14336, 11,
|
||||
-28672, 11, -20480, 11, -14336, 11, -10240, 11, -7168, 11, -5120, 11, -3072, 11, -1024, 10,
|
||||
1024, 10, 3072, 11, 5120, 11, 7168, 11, 10240, 11, 14336, 11, 20480, 11, 28672, 11,
|
||||
/* rest is 0s */
|
||||
};
|
||||
|
||||
/* Platinum "PtADPCM" custom ADPCM for Wwise (reverse engineered from .exes). */
|
||||
void decode_ptadpcm(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, size_t frame_size) {
|
||||
off_t frame_offset;
|
||||
int i, frames_in, sample_count = 0, samples_done = 0;
|
||||
size_t bytes_per_frame, samples_per_frame;
|
||||
int16_t hist1, hist2;
|
||||
int index, step;
|
||||
|
||||
/* external interleave (variable size), mono */
|
||||
bytes_per_frame = frame_size;
|
||||
samples_per_frame = 2 + (frame_size - 0x05) * 2;
|
||||
frames_in = first_sample / samples_per_frame;
|
||||
first_sample = first_sample % samples_per_frame;
|
||||
|
||||
/* parse frame header */
|
||||
frame_offset = stream->offset + bytes_per_frame*frames_in;
|
||||
hist2 = read_16bitLE(frame_offset+0x00,stream->streamfile);
|
||||
hist1 = read_16bitLE(frame_offset+0x02,stream->streamfile);
|
||||
index = (uint8_t)read_8bit(frame_offset+0x04,stream->streamfile);
|
||||
|
||||
VGM_ASSERT_ONCE(index > 12, "PTADPCM: incorrect index at %x\n", (uint32_t)frame_offset);
|
||||
|
||||
/* write header samples (needed) */
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist2;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
if (sample_count >= first_sample && samples_done < samples_to_do) {
|
||||
outbuf[samples_done * channelspacing] = hist1;
|
||||
samples_done++;
|
||||
}
|
||||
sample_count++;
|
||||
|
||||
/* decode nibbles */
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++) {
|
||||
int32_t new_sample;
|
||||
uint8_t nibbles = (uint8_t)read_8bit(frame_offset+0x05 + i/2,stream->streamfile);
|
||||
uint8_t nibble;
|
||||
|
||||
nibble = !(i&1) ? /* low nibble first */
|
||||
(nibbles >> 0) & 0xF :
|
||||
(nibbles >> 4) & 0xF;
|
||||
|
||||
step = ptadpcm_table[2*(nibble + 16*index) + 0];
|
||||
index = ptadpcm_table[2*(nibble + 16*index) + 1];
|
||||
new_sample = clamp16(step + 2*hist1 - hist2);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t ptadpcm_bytes_to_samples(size_t bytes, int channels, size_t frame_size) {
|
||||
if (channels <= 0 || frame_size < 0x06) return 0;
|
||||
return (bytes / channels / frame_size) * ((frame_size-0x05) * 2);
|
||||
}
|
@ -682,6 +682,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_XMD, "Konami XMD 4-bit ADPCM"},
|
||||
{coding_PCFX, "PC-FX 4-bit ADPCM"},
|
||||
{coding_OKI16, "OKI 4-bit ADPCM (16-bit output)"},
|
||||
{coding_PTADPCM, "Platinum 4-bit ADPCM"},
|
||||
|
||||
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
|
||||
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
|
||||
|
@ -2022,10 +2022,14 @@
|
||||
RelativePath=".\coding\psv_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\psx_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\psx_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\ptadpcm_decoder.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\sassc_decoder.c"
|
||||
>
|
||||
|
@ -564,6 +564,7 @@
|
||||
<ClCompile Include="coding\pcm_decoder.c" />
|
||||
<ClCompile Include="coding\psv_decoder.c" />
|
||||
<ClCompile Include="coding\psx_decoder.c" />
|
||||
<ClCompile Include="coding\ptadpcm_decoder.c" />
|
||||
<ClCompile Include="coding\sassc_decoder.c" />
|
||||
<ClCompile Include="coding\sdx2_decoder.c" />
|
||||
<ClCompile Include="coding\vorbis_custom_decoder.c" />
|
||||
|
@ -1210,6 +1210,9 @@
|
||||
<ClCompile Include="coding\psx_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\ptadpcm_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\sassc_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
* Some info: https://www.audiokinetic.com/en/library/edge/
|
||||
*/
|
||||
typedef enum { PCM, IMA, VORBIS, DSP, XMA2, XWMA, AAC, HEVAG, ATRAC9, OPUS } wwise_codec;
|
||||
typedef enum { PCM, IMA, VORBIS, DSP, XMA2, XWMA, AAC, HEVAG, ATRAC9, OPUSNX, OPUS, PTADPCM } wwise_codec;
|
||||
typedef struct {
|
||||
int big_endian;
|
||||
size_t file_size;
|
||||
@ -73,7 +73,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
|
||||
#if 0
|
||||
/* Wwise's RIFF size is often wonky, seemingly depending on codec:
|
||||
* - PCM, IMA, VORBIS, AAC, OPUS: correct
|
||||
* - PCM, IMA/PTADPCM, VORBIS, AAC, OPUSNX/OPUS: correct
|
||||
* - DSP, XWMA, ATRAC9: almost always slightly smaller (around 0x50)
|
||||
* - HEVAG: very off
|
||||
* - XMA2: exact file size
|
||||
@ -172,14 +172,17 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
case 0x0162: ww.codec = XWMA; break; /* WMAPro */
|
||||
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
|
||||
case 0x0166: ww.codec = XMA2; break;
|
||||
case 0x3039: ww.codec = OPUS; break; /* later renamed to "OPUSNX" */
|
||||
//case 0x3040: ww.codec = OPUS; break; /* same for other platforms, supposedly */
|
||||
case 0xAAC0: ww.codec = AAC; break;
|
||||
case 0xFFF0: ww.codec = DSP; break;
|
||||
case 0xFFFB: ww.codec = HEVAG; break;
|
||||
case 0xFFFC: ww.codec = ATRAC9; break;
|
||||
case 0xFFFE: ww.codec = PCM; break; /* "PCM for Wwise Authoring" */
|
||||
case 0xFFFF: ww.codec = VORBIS; break;
|
||||
case 0x3039: ww.codec = OPUSNX; break; /* later renamed from "OPUS" */
|
||||
#if 0
|
||||
case 0x3040: ww.codec = OPUS; break;
|
||||
case 0x8311: ww.codec = PTADPCM; break;
|
||||
#endif
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
@ -193,12 +196,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
|
||||
ww.codec = DSP;
|
||||
} else if (ww.block_align == 0x104 * ww.channels) {
|
||||
//ww.codec = SWITCH_ADPCM;
|
||||
/* unknown codec, found in Bayonetta 2 (Switch)
|
||||
* frames of 0x104 per ch, possibly frame header is hist1(2)/hist2(2)/index(1)
|
||||
* (may write 2 header samples + FF*2 nibbles = 0x200 samples per block?)
|
||||
* index only goes up to ~0xb, may be a shift/scale value */
|
||||
goto fail;
|
||||
ww.codec = PTADPCM; /* Bayonetta 2 (Switch) */
|
||||
}
|
||||
}
|
||||
|
||||
@ -561,7 +559,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
|
||||
case OPUS: { /* Switch */
|
||||
case OPUSNX: { /* Switch */
|
||||
size_t skip;
|
||||
|
||||
/* values up to 0x14 seem fixed and similar to HEVAG's (block_align 0x02/04, bits_per_sample 0x10) */
|
||||
@ -587,6 +585,25 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
case OPUS: { /* PC/etc */
|
||||
ffmpeg_codec_data * ffmpeg_data = NULL;
|
||||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
||||
|
||||
/* extra: size 0x12, unknown values, maybe num_samples/etc */
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = (int32_t)ffmpeg_data->totalSamples;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
case HEVAG: /* PSV */
|
||||
/* changed values, another bizarre Wwise quirk */
|
||||
@ -626,12 +643,24 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case PTADPCM: /* substitutes IMA as default ADPCM codec */
|
||||
if (ww.bits_per_sample != 4) goto fail;
|
||||
if (ww.block_align != 0x24 * ww.channels && ww.block_align != 0x104 * ww.channels) goto fail;
|
||||
|
||||
vgmstream->coding_type = coding_PTADPCM;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = ww.block_align / ww.channels;
|
||||
//vgmstream->codec_endian = ww.big_endian; //?
|
||||
|
||||
vgmstream->num_samples = ptadpcm_bytes_to_samples(ww.data_size, ww.channels, vgmstream->interleave_block_size);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
@ -1249,6 +1249,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
return 14; /* (0x08 - 0x1) * 2 */
|
||||
case coding_XMD:
|
||||
return (vgmstream->interleave_block_size - 0x06)*2 + 2;
|
||||
case coding_PTADPCM:
|
||||
return (vgmstream->interleave_block_size - 0x05)*2 + 2;
|
||||
case coding_EA_MT:
|
||||
return 0; /* 432, but variable in looped files */
|
||||
case coding_CRI_HCA:
|
||||
@ -1431,6 +1433,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
return 0x08;
|
||||
case coding_XMD:
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_PTADPCM:
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_EA_MT:
|
||||
return 0; /* variable (frames of bit counts or PCM frames) */
|
||||
#ifdef VGM_USE_ATRAC9
|
||||
@ -2078,6 +2082,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
vgmstream->interleave_block_size);
|
||||
}
|
||||
break;
|
||||
case coding_PTADPCM:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ptadpcm(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do,
|
||||
vgmstream->interleave_block_size);
|
||||
}
|
||||
break;
|
||||
case coding_PCFX:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_pcfx(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
|
@ -165,6 +165,7 @@ typedef enum {
|
||||
coding_XMD, /* Konami XMD 4-bit ADPCM */
|
||||
coding_PCFX, /* PC-FX 4-bit ADPCM */
|
||||
coding_OKI16, /* OKI 4-bit ADPCM with 16-bit output */
|
||||
coding_PTADPCM, /* Platinum 4-bit ADPCM */
|
||||
|
||||
/* others */
|
||||
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
|
||||
|
Loading…
x
Reference in New Issue
Block a user