vgmstream/src/layout/blocked_ubi_sce.c

58 lines
2.2 KiB
C

#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;
}
}
}
}