mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 15:54:05 +01:00
Split Ubi IMA and Ubi SCE IMA into different codecs
This commit is contained in:
parent
9d65efabc5
commit
d4754b00b0
@ -37,7 +37,8 @@ void decode_apple_ima4(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelsp
|
||||
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, int codec_config);
|
||||
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_sce_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
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);
|
||||
void decode_cd_ima(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||
|
@ -1065,9 +1065,8 @@ 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, int codec_config) {
|
||||
void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
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;
|
||||
@ -1075,7 +1074,7 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||
//internal interleave
|
||||
|
||||
//header in the beginning of the stream
|
||||
if (has_header && stream->channel_start_offset == stream->offset) {
|
||||
if (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;
|
||||
@ -1108,16 +1107,10 @@ 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;
|
||||
} else {
|
||||
if (step_index < 0) step_index = 0;
|
||||
if (step_index > 89) step_index = 89;
|
||||
}
|
||||
|
||||
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 ?
|
||||
@ -1131,12 +1124,39 @@ void decode_ubi_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspa
|
||||
outbuf[sample_count] = (short)(hist1); /* all samples are written */
|
||||
}
|
||||
|
||||
//external interleave
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
/* standard IMA but with a tweak for Ubi's encoder bug with step index (see blocked_ubi_sce.c) */
|
||||
void decode_ubi_sce_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
//internal interleave
|
||||
|
||||
if (step_index < 0) step_index = 0;
|
||||
if (step_index > 89) step_index = 89;
|
||||
|
||||
for (i = first_sample; i < first_sample + samples_to_do; i++, sample_count += channelspacing) {
|
||||
off_t byte_offset = channelspacing == 1 ?
|
||||
stream->offset + i/2 : /* mono mode */
|
||||
stream->offset + i; /* stereo mode */
|
||||
int nibble_shift = channelspacing == 1 ?
|
||||
(!(i%2) ? 4:0) : /* mono mode (high first) */
|
||||
(channel==0 ? 4:0); /* stereo mode (high=L,low=R) */
|
||||
|
||||
std_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||
outbuf[sample_count] = (short)(hist1); /* all samples are written */
|
||||
}
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
|
||||
/* IMA with variable frame formats controlled by the block layout. The original code uses
|
||||
* tables mapping all standard IMA combinations (to optimize calculations), but decodes the same.
|
||||
* Based on HCS's and Nisto's reverse engineering in h4m_audio_decode. */
|
||||
|
12
src/decode.c
12
src/decode.c
@ -355,6 +355,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM* vgmstream) {
|
||||
case coding_SNDS_IMA:
|
||||
case coding_OTNS_IMA:
|
||||
case coding_UBI_IMA:
|
||||
case coding_UBI_SCE_IMA:
|
||||
case coding_OKI16:
|
||||
case coding_OKI4S:
|
||||
case coding_MTF_IMA:
|
||||
@ -580,6 +581,8 @@ int get_vgmstream_frame_size(VGMSTREAM* vgmstream) {
|
||||
return 0; //todo: 0x01?
|
||||
case coding_UBI_IMA: /* variable (PCM then IMA) */
|
||||
return 0;
|
||||
case coding_UBI_SCE_IMA:
|
||||
return 0;
|
||||
case coding_XBOX_IMA:
|
||||
//todo should be 0x48 when stereo, but blocked/interleave layout don't understand stereo codecs
|
||||
return 0x24; //vgmstream->channels==1 ? 0x24 : 0x48;
|
||||
@ -1145,8 +1148,13 @@ 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+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch,
|
||||
vgmstream->codec_config);
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_UBI_SCE_IMA:
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
decode_ubi_sce_ima(&vgmstream->ch[ch], buffer+ch,
|
||||
vgmstream->channels, vgmstream->samples_into_block, samples_to_do, ch);
|
||||
}
|
||||
break;
|
||||
case coding_H4M_IMA:
|
||||
|
@ -749,6 +749,7 @@ 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_UBI_SCE_IMA, "Ubisoft 4-bit SCE IMA ADPCM"},
|
||||
{coding_H4M_IMA, "Hudson HVQM4 4-bit IMA ADPCM"},
|
||||
{coding_CD_IMA, "Crystal Dynamics 4-bit IMA ADPCM"},
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
/* weird mix of Ubi ADPCM format with Ubi IMA, found in Splinter Cell Essentials (PSP) */
|
||||
@ -18,8 +19,6 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
* (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 */
|
||||
}
|
||||
@ -34,8 +33,8 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
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;
|
||||
vgmstream->current_block_samples = ima_bytes_to_samples(subframe_size, channels);
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + header_size * channels;
|
||||
@ -44,11 +43,11 @@ void block_update_ubi_sce(off_t block_offset, VGMSTREAM* vgmstream) {
|
||||
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);
|
||||
|
||||
/* First step is always 0x500, not sure if it's a bug or a feature but the game just takes it as is and
|
||||
* ends up reading 0 from out-of-bounds memory area which causes a pop at the start. Yikes.
|
||||
* It gets clampled later so the rest of the sound plays ok.
|
||||
* We put 89 here as our special index which contains 0 to simulate this.
|
||||
*/
|
||||
/* First step is always 0x500, not sure if it's a bug or a feature but the game just takes it as is and
|
||||
* ends up reading 0 from out-of-bounds memory area which causes a pop at the start. Yikes.
|
||||
* It gets clampled later so the rest of the sound plays ok.
|
||||
* We put 89 here as our special index which contains 0 to simulate this.
|
||||
*/
|
||||
if (vgmstream->ch[i].adpcm_step_index == 0x500) {
|
||||
vgmstream->ch[i].adpcm_step_index = 89;
|
||||
}
|
||||
|
@ -984,7 +984,7 @@ static VGMSTREAM* init_vgmstream_ubi_sb_base(ubi_sb_header* sb, STREAMFILE* sf_h
|
||||
break;
|
||||
|
||||
case UBI_IMA_SCE:
|
||||
vgmstream->coding_type = coding_UBI_IMA;
|
||||
vgmstream->coding_type = coding_UBI_SCE_IMA;
|
||||
vgmstream->layout_type = layout_blocked_ubi_sce;
|
||||
vgmstream->full_block_size = read_32bitLE(0x18, sf_data);
|
||||
|
||||
|
@ -141,6 +141,7 @@ typedef enum {
|
||||
coding_REF_IMA, /* Reflections IMA ADPCM */
|
||||
coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */
|
||||
coding_UBI_IMA, /* Ubisoft IMA ADPCM */
|
||||
coding_UBI_SCE_IMA, /* Ubisoft SCE IMA ADPCM */
|
||||
coding_H4M_IMA, /* H4M IMA ADPCM (stereo or mono, high nibble first) */
|
||||
coding_MTF_IMA, /* Capcom MT Framework IMA ADPCM */
|
||||
coding_CD_IMA, /* Crystal Dynamics IMA ADPCM */
|
||||
|
Loading…
x
Reference in New Issue
Block a user