mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Add Ubi SB alt IMA [Splinter Cell: Essentials (PSP)]
This commit is contained in:
parent
9a09d2cf11
commit
6ec4f0d008
@ -35,7 +35,7 @@ void decode_apple_ima4(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channel
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int codec_config);
|
||||
void decode_h4m_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, uint16_t frame_format);
|
||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
||||
|
@ -1009,8 +1009,9 @@ void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||
|
||||
|
||||
/* DVI stereo/mono with some mini header and sample output */
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int codec_config) {
|
||||
int i, sample_count = 0;
|
||||
int has_header = (codec_config & 0x80) == 0;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
@ -1018,7 +1019,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||
//internal interleave
|
||||
|
||||
//header in the beginning of the stream
|
||||
if (stream->channel_start_offset == stream->offset) {
|
||||
if (has_header && stream->channel_start_offset == stream->offset) {
|
||||
int version, big_endian, header_samples, max_samples_to_do;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
off_t offset = stream->offset;
|
||||
@ -1051,8 +1052,12 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||
}
|
||||
}
|
||||
|
||||
if (has_header) {
|
||||
first_sample -= 10; //todo fix hack (needed to adjust nibble offset below)
|
||||
}
|
||||
|
||||
first_sample -= 10; //todo fix hack (needed to adjust nibble offset below)
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||
off_t byte_offset = channelspacing == 1 ?
|
||||
|
@ -727,7 +727,6 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
||||
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
|
||||
{coding_UBI_IMA, "Ubisoft 4-bit IMA ADPCM"},
|
||||
|
||||
{coding_H4M_IMA, "Hudson HVQM4 4-bit IMA ADPCM"},
|
||||
|
||||
{coding_MSADPCM, "Microsoft 4-bit ADPCM"},
|
||||
@ -850,6 +849,7 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_blocked_xa_aiff, "blocked (XA AIFF)"},
|
||||
{layout_blocked_vs_square, "blocked (Square VS)"},
|
||||
{layout_blocked_vid1, "blocked (VID1)"},
|
||||
{layout_blocked_ubi_sce, "blocked (Ubi SCE)"},
|
||||
};
|
||||
|
||||
static const meta_info meta_info_list[] = {
|
||||
|
@ -208,6 +208,9 @@ void block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
case layout_blocked_vid1:
|
||||
block_update_vid1(block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_ubi_sce:
|
||||
block_update_ubi_sce(block_offset,vgmstream);
|
||||
break;
|
||||
default: /* not a blocked layout */
|
||||
break;
|
||||
}
|
||||
|
57
src/layout/blocked_ubi_sce.c
Normal file
57
src/layout/blocked_ubi_sce.c
Normal file
@ -0,0 +1,57 @@
|
||||
#include "layout.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* weird mix of Ubi ADPCM format with Ubi IMA, found in Splinter Cell Essentials (PSP) */
|
||||
void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
STREAMFILE* sf = vgmstream->ch[0].streamfile;
|
||||
int i, channels;
|
||||
size_t header_size, frame_size, subframe_size, padding_size;
|
||||
|
||||
/* format mimics Ubi ADPCM's:
|
||||
* - 0x34/38 header with frame size (ex. 0x600), pre-read in meta
|
||||
* xN frames:
|
||||
* - 0x34 channel header per channel, with ADPCM config
|
||||
* - subframe (ex. 0x300) + padding byte
|
||||
* - subframe (ex. 0x300) + padding byte
|
||||
*
|
||||
* to skip the padding byte we'll detect subframes using codec_config as a counter
|
||||
* (higher bit has a special meaning)
|
||||
*/
|
||||
|
||||
vgmstream->codec_config |= 0x80; /* flag for decoder, ugly I know */
|
||||
|
||||
if ((vgmstream->codec_config & 1) == 0) {
|
||||
header_size = 0x34; /* read header in first subframe */
|
||||
}
|
||||
else {
|
||||
header_size = 0x00;
|
||||
}
|
||||
vgmstream->codec_config ^= 1; /* swap counter bit */
|
||||
|
||||
channels = vgmstream->channels;
|
||||
frame_size = vgmstream->full_block_size;
|
||||
subframe_size = frame_size / 2;
|
||||
padding_size = 0x01;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->current_block_size = subframe_size;
|
||||
vgmstream->next_block_offset = block_offset + header_size * vgmstream->channels + subframe_size + padding_size;
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + header_size * channels;
|
||||
|
||||
if (header_size > 0) {
|
||||
vgmstream->ch[i].adpcm_step_index = read_32bitLE(block_offset + header_size * i + 0x04, sf);
|
||||
vgmstream->ch[i].adpcm_history1_32 = read_32bitLE(block_offset + header_size * i + 0x08, sf);
|
||||
|
||||
/* TODO figure out
|
||||
* First step seems to always be a special value for the decoder, unsure of meaning.
|
||||
* 0 = too quiet and max = 88 = waveform starts a bit off and clicky. First hist is usually +-1,
|
||||
* other frames look, fine not sure what are they aiming for.
|
||||
*/
|
||||
if (vgmstream->ch[i].adpcm_step_index == 0x500) {
|
||||
vgmstream->ch[i].adpcm_step_index = 88;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -47,6 +47,7 @@ void block_update_h4m(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_xa_aiff(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_vs_square(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
void block_update_vid1(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
@ -2390,10 +2390,14 @@
|
||||
RelativePath=".\layout\blocked_thp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_tra.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_tra.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_ubi_sce.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_vs.c"
|
||||
>
|
||||
|
@ -173,6 +173,7 @@
|
||||
<ClCompile Include="layout\blocked_vs_str.c" />
|
||||
<ClCompile Include="layout\layered.c" />
|
||||
<ClCompile Include="layout\blocked_tra.c" />
|
||||
<ClCompile Include="layout\blocked_ubi_sce.c" />
|
||||
<ClCompile Include="meta\akb.c" />
|
||||
<ClCompile Include="meta\awb.c" />
|
||||
<ClCompile Include="meta\awc.c" />
|
||||
|
@ -1492,6 +1492,9 @@
|
||||
<ClCompile Include="layout\blocked_tra.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_ubi_sce.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\lsf_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define SB_MAX_LAYER_COUNT 16 /* arbitrary max */
|
||||
#define SB_MAX_CHAIN_COUNT 256 /* +150 exist in Tonic Trouble */
|
||||
|
||||
typedef enum { UBI_IMA, UBI_ADPCM, RAW_PCM, RAW_PSX, RAW_DSP, RAW_XBOX, FMT_VAG, FMT_AT3, RAW_AT3, FMT_XMA1, RAW_XMA1, FMT_OGG, FMT_CWAV, FMT_APM, FMT_MPDX } ubi_sb_codec;
|
||||
typedef enum { UBI_IMA, UBI_ADPCM, RAW_PCM, RAW_PSX, RAW_DSP, RAW_XBOX, FMT_VAG, FMT_AT3, RAW_AT3, FMT_XMA1, RAW_XMA1, FMT_OGG, FMT_CWAV, FMT_APM, FMT_MPDX, UBI_IMA_SCE } ubi_sb_codec;
|
||||
typedef enum { UBI_PC, UBI_PS2, UBI_XBOX, UBI_GC, UBI_X360, UBI_PSP, UBI_PS3, UBI_WII, UBI_3DS } ubi_sb_platform;
|
||||
typedef enum { UBI_NONE = 0, UBI_AUDIO, UBI_LAYER, UBI_SEQUENCE, UBI_SILENCE } ubi_sb_type;
|
||||
|
||||
@ -496,6 +496,16 @@ static VGMSTREAM * init_vgmstream_ubi_sb_base(ubi_sb_header *sb, STREAMFILE *str
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
||||
case UBI_IMA_SCE:
|
||||
vgmstream->coding_type = coding_UBI_IMA;
|
||||
vgmstream->layout_type = layout_blocked_ubi_sce;
|
||||
vgmstream->full_block_size = read_32bitLE(0x18, streamData);
|
||||
|
||||
/* this "codec" is an ugly hack of IMA w/ Ubi ADPCM's frame format, surely to
|
||||
* shoehorn a simpler codec into the existing code when porting the game */
|
||||
start_offset += 0x08 + 0x30; /* skip Ubi ADPCM header */
|
||||
break;
|
||||
|
||||
case UBI_ADPCM:
|
||||
/* custom Ubi 4/6-bit ADPCM used in early games:
|
||||
* - Splinter Cell (PC): 4-bit w/ 2ch (music), 6-bit w/ 1ch (sfx)
|
||||
@ -1553,10 +1563,9 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
||||
case UBI_PS3:
|
||||
sb->codec = RAW_PSX; /* PS3 */
|
||||
break;
|
||||
case UBI_PSP:
|
||||
/* TODO: IMA using Ubisoft ADPCM frame layout [Splinter Cell: Essentials (PSP)] */
|
||||
VGM_LOG("UBI SB: Unimplemented custom IMA codec.\n");
|
||||
goto fail;
|
||||
case UBI_PSP: /* Splinter Cell: Essentials (PSP) */
|
||||
sb->codec = UBI_IMA_SCE;
|
||||
break;
|
||||
default:
|
||||
sb->codec = UBI_ADPCM;
|
||||
break;
|
||||
|
@ -1109,6 +1109,7 @@ void render_vgmstream(sample_t * buffer, int32_t sample_count, VGMSTREAM * vgmst
|
||||
case layout_blocked_xa_aiff:
|
||||
case layout_blocked_vs_square:
|
||||
case layout_blocked_vid1:
|
||||
case layout_blocked_ubi_sce:
|
||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||
break;
|
||||
case layout_segmented:
|
||||
@ -1947,7 +1948,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
case coding_UBI_IMA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ubi_ima(&vgmstream->ch[ch],buffer+samples_written*vgmstream->channels+ch,
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch);
|
||||
vgmstream->channels,vgmstream->samples_into_block,samples_to_do, ch, vgmstream->codec_config);
|
||||
}
|
||||
break;
|
||||
case coding_H4M_IMA:
|
||||
|
Loading…
x
Reference in New Issue
Block a user