mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-23 22:41:05 +01:00
Fix interleaved MS_IMA [Manhunt (PC)]
This commit is contained in:
parent
cc73ebd1bc
commit
97b1aa23e0
@ -773,6 +773,36 @@ int decode_get_shortframe_size(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
}
|
||||
|
||||
/* ugly kludge due to vgmstream's finicky internals, to be improved some day:
|
||||
* - some codecs have frame sizes AND may also have interleave
|
||||
* - meaning, ch0 could read 0x100 (frame_size) N times until 0x1000 (interleave)
|
||||
* then skip 0x1000 per other channels and keep reading 0x100
|
||||
* (basically: ch0=0x0000..0x1000, ch1=0x1000..0x2000, ch0=0x2000..0x3000, etc)
|
||||
* - interleave layout assumes by default codecs DON'T update offsets and only interleave does
|
||||
* - interleave calculates how many frames/samples will read before moving offsets,
|
||||
* then once 1 channel is done skips original channel data + other channel's data
|
||||
* - decoders need to calculate current frame offset on every frame since
|
||||
* offsets only move when interleave moves offsets (ugly)
|
||||
* - other codecs move offsets internally instead (also ugly)
|
||||
* - but interleave doesn't know this and will skip too much data
|
||||
*
|
||||
* To handle the last case, return a flag here that interleave layout can use to
|
||||
* separate between both cases when the interleave data is done
|
||||
* - codec doesn't advance offsets: will skip interleave for all channels including current
|
||||
* - ex. 2ch, 0x100, 0x1000: after reading 0x100*10 frames offset is still 0x0000 > skips 0x1000*2 (ch0+ch1)
|
||||
* - codec does advance offsets: will skip interleave for all channels except current
|
||||
* - ex. 2ch, 0x100, 0x1000: after reading 0x100*10 frames offset is at 0x1000 > skips 0x1000*1 (ch1)
|
||||
*
|
||||
* Ideally frame reading + skipping would be moved to some kind of consumer functions
|
||||
* separate from frame decoding which would simplify all this but meanwhile...
|
||||
*
|
||||
* Instead of this flag, codecs could be converted to avoid moving offsets (like most codecs) but it's
|
||||
* getting hard to understand the root issue so have some wall of text as a reminder.
|
||||
*/
|
||||
bool decode_uses_internal_offset_updates(VGMSTREAM* vgmstream) {
|
||||
return vgmstream->coding_type == coding_MS_IMA || vgmstream->coding_type == coding_MS_IMA_mono;
|
||||
}
|
||||
|
||||
/* Decode samples into the buffer. Assume that we have written samples_written into the
|
||||
* buffer already, and we have samples_to_do consecutive samples ahead of us (won't call
|
||||
* more than one frame if configured above to do so).
|
||||
|
@ -29,4 +29,6 @@ int decode_get_samples_per_shortframe(VGMSTREAM* vgmstream);
|
||||
int decode_get_shortframe_size(VGMSTREAM* vgmstream);
|
||||
|
||||
|
||||
bool decode_uses_internal_offset_updates(VGMSTREAM* vgmstream);
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
|
||||
int samples_per_frame_l = 0, samples_this_block_l = 0; /* last */
|
||||
int has_interleave_first = vgmstream->interleave_first_block_size && vgmstream->channels > 1;
|
||||
int has_interleave_last = vgmstream->interleave_last_block_size && vgmstream->channels > 1;
|
||||
int has_interleave_internal_updates = vgmstream->codec_internal_updates;
|
||||
|
||||
|
||||
/* setup */
|
||||
@ -133,9 +134,15 @@ void render_vgmstream_interleave(sample_t * buffer, int32_t sample_count, VGMSTR
|
||||
vgmstream->ch[ch].offset += skip;
|
||||
}
|
||||
}
|
||||
else if (has_interleave_internal_updates) {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
off_t skip = vgmstream->interleave_block_size * (vgmstream->channels - 1);
|
||||
vgmstream->ch[ch].offset += skip;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
off_t skip = vgmstream->interleave_block_size*vgmstream->channels;
|
||||
off_t skip = vgmstream->interleave_block_size * vgmstream->channels;
|
||||
vgmstream->ch[ch].offset += skip;
|
||||
}
|
||||
}
|
||||
|
@ -1234,6 +1234,8 @@ int vgmstream_open_stream_bf(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t start_o
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->codec_internal_updates = decode_uses_internal_offset_updates(vgmstream);
|
||||
|
||||
/* big interleaved values for non-interleaved data may result in incorrect behavior,
|
||||
* quick fix for now since layouts are finicky, with 'interleave' left for meta info
|
||||
* (certain layouts+codecs combos results in funny output too, should rework the whole thing) */
|
||||
|
@ -222,6 +222,7 @@ typedef struct {
|
||||
/* decoder config/state */
|
||||
int codec_endian; /* little/big endian marker; name is left vague but usually means big endian */
|
||||
int codec_config; /* flags for codecs or layouts with minor variations; meaning is up to them */
|
||||
bool codec_internal_updates; /* temp(?) kludge (see vgmstream_open_stream/decode) */
|
||||
int32_t ws_output_size; /* WS ADPCM: output bytes for this block */
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user