mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Add AWC PCM/IMA (non-encrypted only) [GTA5 (PC)]
This commit is contained in:
parent
953022b983
commit
41b22c2699
@ -30,7 +30,8 @@ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * out
|
||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||
|
||||
|
@ -678,6 +678,43 @@ void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i, sample_count;
|
||||
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
int step_index = stream->adpcm_step_index;
|
||||
|
||||
//internal interleave, mono
|
||||
int block_samples = (0x800 - 4) * 2;
|
||||
first_sample = first_sample % block_samples;
|
||||
|
||||
//inverted header
|
||||
if (first_sample == 0) {
|
||||
off_t header_offset = stream->offset;
|
||||
|
||||
step_index = read_16bitLE(header_offset,stream->streamfile);
|
||||
hist1 = read_16bitLE(header_offset+2,stream->streamfile);
|
||||
if (step_index < 0) step_index=0;
|
||||
if (step_index > 88) step_index=88;
|
||||
}
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
off_t byte_offset = stream->offset + 4 + i/2;
|
||||
int nibble_shift = (i&1?4:0); //low nibble first
|
||||
|
||||
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||
outbuf[sample_count] = (short)(hist1);
|
||||
}
|
||||
|
||||
//internal interleave: increment offset on complete frame
|
||||
if (i == block_samples) stream->offset += 0x800;
|
||||
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
|
||||
/* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
||||
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels;
|
||||
|
@ -449,6 +449,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"},
|
||||
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
|
||||
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
||||
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
|
||||
{coding_WS, "Westwood Studios VBR ADPCM"},
|
||||
{coding_ACM, "InterPlay ACM"},
|
||||
{coding_NWA0, "NWA DPCM Level 0"},
|
||||
@ -533,6 +534,7 @@ static const layout_info layout_info_list[] = {
|
||||
{layout_aax, "AAX blocked, 18-byte interleaved"},
|
||||
{layout_scd_int, "SCD multistream interleave"},
|
||||
{layout_ea_sns_blocked, "Electronic Arts SNS blocked"},
|
||||
{layout_blocked_awc, "blocked (AWC)"},
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{layout_ogg_vorbis, "Ogg"},
|
||||
#endif
|
||||
|
@ -143,6 +143,9 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
||||
break;
|
||||
case layout_ea_sns_blocked:
|
||||
ea_sns_block_update(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
case layout_blocked_awc:
|
||||
block_update_awc(vgmstream->next_block_offset,vgmstream);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
58
src/layout/blocked_awc.c
Normal file
58
src/layout/blocked_awc.c
Normal file
@ -0,0 +1,58 @@
|
||||
#include "layout.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian);
|
||||
|
||||
/* AWC music chunks */
|
||||
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
|
||||
size_t header_size, entries, block_size, block_samples;
|
||||
int i;
|
||||
|
||||
/* assumed only AWC_IMA enters here, MPEG/XMA2 need special parsing as blocked layout is too limited */
|
||||
|
||||
entries = read_32bit(block_offset + 0x18*0 + 0x04, streamFile); /* assumed same for all channels */
|
||||
block_samples = entries * (0x800-4)*2;
|
||||
block_size = vgmstream->full_block_size;
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
vgmstream->current_block_samples = block_samples;
|
||||
|
||||
/* starts with a header block */
|
||||
/* for each channel
|
||||
* 0x00: start entry within channel (ie. entries * ch)
|
||||
* 0x04: entries
|
||||
* 0x08: samples to discard in the beginning of this block (MPEG only?)
|
||||
* 0x0c: samples in channel (for MPEG/XMA2 can vary between channels)
|
||||
* 0x10: MPEG only: close to number of frames but varies a bit?
|
||||
* 0x14: MPEG only: channel usable data size (not counting padding)
|
||||
* for each channel
|
||||
* 32b * entries = global samples per frame in each block (for MPEG probably per full frame)
|
||||
*/
|
||||
|
||||
header_size = get_block_header_size(streamFile, block_offset, vgmstream->channels, vgmstream->codec_endian);
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian) {
|
||||
size_t header_size = 0;
|
||||
int i;
|
||||
int entries = channels;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
||||
for (i = 0; i < entries; i++) {
|
||||
header_size += 0x18;
|
||||
header_size += read_32bit(offset + 0x18*i + 0x04, streamFile) * 0x04; /* entries in the table */
|
||||
}
|
||||
|
||||
if (header_size % 0x800) /* padded */
|
||||
header_size += 0x800 - (header_size % 0x800);
|
||||
|
||||
return header_size;
|
||||
}
|
@ -65,6 +65,8 @@ void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||
|
||||
void block_update_awc(off_t block_ofset, VGMSTREAM * vgmstream);
|
||||
|
||||
/* other layouts */
|
||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||
|
||||
|
@ -1534,6 +1534,10 @@
|
||||
RelativePath=".\layout\blocked.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\blocked_awc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\layout\caf_blocked.c"
|
||||
>
|
||||
|
@ -454,6 +454,7 @@
|
||||
<ClCompile Include="layout\ast_blocked.c" />
|
||||
<ClCompile Include="layout\bdsp_blocked.c" />
|
||||
<ClCompile Include="layout\blocked.c" />
|
||||
<ClCompile Include="layout\blocked_awc.c" />
|
||||
<ClCompile Include="layout\caf_blocked.c" />
|
||||
<ClCompile Include="layout\de2_blocked.c" />
|
||||
<ClCompile Include="layout\ea_block.c" />
|
||||
|
@ -898,6 +898,9 @@
|
||||
<ClCompile Include="layout\blocked.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\blocked_awc.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout\caf_blocked.c">
|
||||
<Filter>layout\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
typedef struct {
|
||||
int big_endian;
|
||||
@ -51,16 +52,19 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
switch(awc.codec) {
|
||||
//case 0x01: /* PCM (PC/PS3) */
|
||||
// vgmstream->coding_type = coding_PCM!6;
|
||||
// vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
|
||||
// break;
|
||||
|
||||
//case 0x04: /* IMA (PC) */
|
||||
// vgmstream->coding_type = coding_AWC_IMA;
|
||||
// vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
|
||||
// break;
|
||||
case 0x01: /* PCM (PC/PS3) [sfx, rarely] */
|
||||
if (awc.is_music) goto fail; /* blocked_awc needs to be prepared */
|
||||
vgmstream->coding_type = awc.big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
break;
|
||||
|
||||
case 0x04: /* IMA (PC) */
|
||||
vgmstream->coding_type = coding_AWC_IMA;
|
||||
vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
|
||||
vgmstream->full_block_size = awc.block_chunk;
|
||||
vgmstream->codec_endian = awc.big_endian;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_MPEG
|
||||
case 0x07: { /* MPEG (PS3) */
|
||||
@ -89,8 +93,8 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,awc.stream_offset))
|
||||
goto fail;
|
||||
|
||||
//if (vgmstream->layout_type == layout_blocked_awc)
|
||||
// update_
|
||||
if (vgmstream->layout_type == layout_blocked_awc)
|
||||
block_update_awc(awc.stream_offset, vgmstream);
|
||||
|
||||
return vgmstream;
|
||||
|
||||
|
@ -934,6 +934,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
||||
case layout_rws_blocked:
|
||||
case layout_hwas_blocked:
|
||||
case layout_ea_sns_blocked:
|
||||
case layout_blocked_awc:
|
||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||
break;
|
||||
case layout_interleave_byte:
|
||||
@ -1053,6 +1054,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_WWISE_IMA:
|
||||
case coding_REF_IMA:
|
||||
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
|
||||
case coding_AWC_IMA:
|
||||
return (0x800-4)*2;
|
||||
case coding_RAD_IMA_mono:
|
||||
return 32;
|
||||
case coding_NDS_PROCYON:
|
||||
@ -1156,6 +1159,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
case coding_WWISE_IMA:
|
||||
case coding_REF_IMA:
|
||||
return vgmstream->interleave_block_size;
|
||||
case coding_AWC_IMA:
|
||||
return 0x800;
|
||||
case coding_RAD_IMA_mono:
|
||||
return 0x14;
|
||||
case coding_NGC_DTK:
|
||||
@ -1653,6 +1658,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do,chan);
|
||||
}
|
||||
break;
|
||||
case coding_AWC_IMA:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_awc_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
|
||||
case coding_WS:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
|
@ -132,6 +132,7 @@ typedef enum {
|
||||
coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */
|
||||
coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */
|
||||
coding_REF_IMA, /* Reflections IMA ADPCM */
|
||||
coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */
|
||||
|
||||
coding_MSADPCM, /* Microsoft ADPCM */
|
||||
coding_WS, /* Westwood Studios VBR ADPCM */
|
||||
@ -236,6 +237,7 @@ typedef enum {
|
||||
layout_rws_blocked,
|
||||
layout_hwas_blocked,
|
||||
layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
||||
layout_blocked_awc, /* Rockstar AWC */
|
||||
|
||||
/* otherwise odd */
|
||||
layout_acm, /* libacm layout */
|
||||
|
Loading…
x
Reference in New Issue
Block a user