If you have an issue with any of our projects. feel free to register.

Commit 38b5dd6e authored by Christopher Snowhill's avatar Christopher Snowhill

Updated VGMStream to r1050-2895-g772fe03e

parent 5fbf722f
......@@ -54,3 +54,8 @@ void decode_asf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing,
stream->adpcm_history1_32 = hist1;
stream->adpcm_history2_32 = hist2;
}
int32_t asf_bytes_to_samples(size_t bytes, int channels) {
if (channels <= 0) return 0;
return bytes / channels / 0x11 * 32;
}
#include "coding.h"
/* Circus XPCM mode 2 decoding, verified vs EF.exe (info from foo_adpcm/libpcm and https://github.com/lioncash/ExtractData) */
void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_pos = 0;
int32_t hist = stream->adpcm_history1_32;
int scale = stream->adpcm_scale;
off_t frame_offset = stream->offset; /* frame size is 1 */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int8_t code = read_8bit(frame_offset+i,stream->streamfile);
hist += code << scale;
if (code == 0) {
if (scale > 0)
scale--;
}
else if (code == 127 || code == -128) {
if (scale < 8)
scale++;
}
outbuf[sample_pos] = hist;
}
stream->adpcm_history1_32 = hist;
stream->adpcm_scale = scale;
}
#include "coding.h"
#include "circus_decoder_lib.h"
struct circus_codec_data {
STREAMFILE* sf;
int16_t* buf;
int buf_samples_all;
circus_handle_t* handle;
};
circus_codec_data* init_circus_vq(STREAMFILE* sf, off_t start, uint8_t codec, uint8_t flags) {
circus_codec_data* data = NULL;
data = calloc(1, sizeof(circus_codec_data));
if (!data) goto fail;
data->sf = reopen_streamfile(sf, 0);
data->handle = circus_init(start, codec, flags);
if (!data->handle) goto fail;
return data;
fail:
free_circus_vq(data);
return NULL;
}
void decode_circus_vq(circus_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels) {
int ok, i, samples_to_get;
while (samples_to_do > 0) {
if (data->buf_samples_all == 0) {
ok = circus_decode_frame(data->handle, data->sf, &data->buf, &data->buf_samples_all);
if (!ok) goto decode_fail;
}
samples_to_get = data->buf_samples_all / channels;
if (samples_to_get > samples_to_do)
samples_to_get = samples_to_do;
for (i = 0; i < samples_to_get * channels; i++) {
outbuf[i] = data->buf[i];
}
data->buf += samples_to_get * channels;
data->buf_samples_all -= samples_to_get * channels;
outbuf += samples_to_get * channels;
samples_to_do -= samples_to_get;
}
return;
decode_fail:
VGM_LOG("CIRCUS: decode error\n");
memset(outbuf, 0, samples_to_do * channels * sizeof(sample_t));
}
void reset_circus_vq(circus_codec_data* data) {
if (!data) return;
circus_reset(data->handle);
data->buf_samples_all = 0;
}
void seek_circus_vq(circus_codec_data* data, int32_t num_sample) {
if (!data) return;
reset_circus_vq(data);
//data->samples_discard = num_sample; //todo (xpcm don't have loop points tho)
}
void free_circus_vq(circus_codec_data* data) {
if (!data) return;
close_streamfile(data->sf);
circus_free(data->handle);
free(data);
}
/* ************************************************************************* */
/* Circus XPCM mode 2 decoding, verified vs EF.exe (info from foo_adpcm/libpcm and https://github.com/lioncash/ExtractData) */
void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
int i, sample_pos = 0;
int32_t hist = stream->adpcm_history1_32;
int scale = stream->adpcm_scale;
off_t frame_offset = stream->offset; /* frame size is 1 */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int8_t code = read_8bit(frame_offset+i,stream->streamfile);
hist += code << scale;
if (code == 0) {
if (scale > 0)
scale--;
}
else if (code == 127 || code == -128) {
if (scale < 8)
scale++;
}
outbuf[sample_pos] = hist;
}
stream->adpcm_history1_32 = hist;
stream->adpcm_scale = scale;
}
This diff is collapsed.
#ifndef _CIRCUS_DECODER_LIB_H_
#define _CIRCUS_DECODER_LIB_H_
#include "../streamfile.h"
typedef struct circus_handle_t circus_handle_t;
circus_handle_t* circus_init(off_t start, uint8_t codec, uint8_t flags);
void circus_free(circus_handle_t* handle);
void circus_reset(circus_handle_t* handle);
int circus_decode_frame(circus_handle_t* handle, STREAMFILE* sf, int16_t** p_buf, int* p_buf_samples_all);
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
/* Decompresses Circus's custom LZ used in XPCM as a machine state for streaming,
* that may break during any step. Original code decompress at once the full thing
* into memory so it's simpler. */
#define LZXPCM_OK 0
#define LZXPCM_ERROR -1
#define LZXPCM_WINDOW_SIZE (1 << 16)
typedef enum {
READ_FLAGS,
COPY_LITERAL,
READ_TOKEN,
PARSE_TOKEN,
SET_MATCH,
COPY_MATCH
} lzxpcm_state_t;
typedef struct {
lzxpcm_state_t state;
uint32_t flags;
uint8_t token;
int values_pos;
int offset_pos;
int match_len;
int match_pos;
int window_pos;
uint8_t window[LZXPCM_WINDOW_SIZE];
} lzxpcm_context_t;
typedef struct {
lzxpcm_context_t ctx;
uint8_t *next_out; /* next bytes to write (reassign when avail is 0) */
int avail_out; /* bytes available at next_out */
int total_out; /* written bytes, for reference (set to 0 per call if needed) */
const uint8_t *next_in; /* next bytes to read (reassign when avail is 0) */
int avail_in; /* bytes available at next_in */
int total_in; /* read bytes, for reference (set to 0 per call if needed) */
} lzxpcm_stream_t;
static void lzxpcm_reset(lzxpcm_stream_t* strm) {
memset(strm, 0, sizeof(lzxpcm_stream_t));
}
/* Decompress src into dst, returning a code and number of bytes used. Caller must handle
* stop (when no more input data or all data has been decompressed) as LZXPCM has no end marker. */
static int lzxpcm_decompress(lzxpcm_stream_t* strm) {
lzxpcm_context_t* ctx = &strm->ctx;
uint8_t* dst = strm->next_out;
const uint8_t* src = strm->next_in;
int dst_size = strm->avail_out;
int src_size = strm->avail_in;
int dst_pos = 0;
int src_pos = 0;
uint8_t next_val;
while (1) {
/* mostly linear state machine, but it may break anytime when reaching dst or src
* end, and resume from same state in next call */
switch(ctx->state) {
case READ_FLAGS:
if (src_pos >= src_size)
goto buffer_end;
ctx->flags >>= 1;
if ((ctx->flags & 0x0100) == 0) {
ctx->flags = 0xFF00 | src[src_pos++];
}
if (ctx->flags & 1)
ctx->state = COPY_LITERAL;
else
ctx->state = READ_TOKEN;
break;
case COPY_LITERAL:
if (src_pos >= src_size || dst_pos >= dst_size)
goto buffer_end;
next_val = src[src_pos++];
dst[dst_pos++] = next_val;
ctx->window[ctx->window_pos++] = next_val;
if (ctx->window_pos == LZXPCM_WINDOW_SIZE)
ctx->window_pos = 0;
ctx->state = READ_FLAGS;
break;
case READ_TOKEN:
if (src_pos >= src_size)
goto buffer_end;
ctx->token = src[src_pos++];
ctx->values_pos = 0;
ctx->state = PARSE_TOKEN;
break;
case PARSE_TOKEN:
if (ctx->token >= 0xC0) {
ctx->match_len = ((ctx->token >> 2) & 0x0F) + 4; /* 6b */
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos = src[src_pos++]; /* upper 2b + lower 8b */
ctx->offset_pos |= ((ctx->token & 3) << 8);
}
else if (ctx->token >= 0x80) {
ctx->match_len = ((ctx->token >> 5) & 3) + 2; /* 2b */
ctx->offset_pos = ctx->token & 0x1F; /* 5b */
if (ctx->offset_pos == 0) {
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos = src[src_pos++];
}
}
else if (ctx->token == 0x7F) {
if (ctx->values_pos == 0) {
if (src_pos >= src_size)
goto buffer_end;
ctx->match_len = (src[src_pos++] << 0u);
ctx->values_pos++;
}
if (ctx->values_pos == 1) {
if (src_pos >= src_size)
goto buffer_end;
ctx->match_len |= (src[src_pos++] << 8u);
ctx->match_len += 2;
ctx->values_pos++;
}
if (ctx->values_pos == 2) {
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos = (src[src_pos++] << 0u);
ctx->values_pos++;
}
if (ctx->values_pos == 3) {
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos |= (src[src_pos++] << 8u);
ctx->values_pos++;
}
}
else {
ctx->match_len = ctx->token + 4;
if (ctx->values_pos == 0) {
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos = (src[src_pos++] << 0u);
ctx->values_pos++;
}
if (ctx->values_pos == 1) {
if (src_pos >= src_size)
goto buffer_end;
ctx->offset_pos |= (src[src_pos++] << 8u);
ctx->values_pos++;
}
}
ctx->state = SET_MATCH;
break;
case SET_MATCH:
ctx->match_pos = ctx->window_pos - ctx->offset_pos;
if (ctx->match_pos < 0) /* circular buffer so negative is from window end */
ctx->match_pos = LZXPCM_WINDOW_SIZE + ctx->match_pos;
ctx->state = COPY_MATCH;
break;
case COPY_MATCH:
while (ctx->match_len > 0) {
if (dst_pos >= dst_size)
goto buffer_end;
next_val = ctx->window[ctx->match_pos++];
if (ctx->match_pos == LZXPCM_WINDOW_SIZE)
ctx->match_pos = 0;
dst[dst_pos++] = next_val;
ctx->window[ctx->window_pos++] = next_val;
if (ctx->window_pos == LZXPCM_WINDOW_SIZE)
ctx->window_pos = 0;
ctx->match_len--;
};
ctx->state = READ_FLAGS;
break;
default:
goto fail;
}
}
buffer_end:
strm->next_out += dst_pos;
strm->next_in += src_pos;
strm->avail_out -= dst_pos;
strm->avail_in -= src_pos;
strm->total_out += dst_pos;
strm->total_in += src_pos;
return LZXPCM_OK;
fail:
return LZXPCM_ERROR;
}
#if 0
/* non-streamed form that XPCM originally uses, assumes buffers are big enough */
static int lzxpcm_decompress_full(uint8_t* dst, size_t dst_size, const uint8_t* src, size_t src_size) {
int src_pos = 0;
int dst_pos = 0;
uint32_t flags = 0;
while (src_pos < src_size && dst_pos < dst_size) {
flags >>= 1;
if ((flags & 0x0100) == 0) {
flags = 0xFF00 | src[src_pos++];
}
if (flags & 1) {
/* uncompressed byte per bit */
dst[dst_pos++] = src[src_pos++];
}
else {
/* compressed data */
uint32_t length;
uint32_t offset;
const uint32_t token = src[src_pos++];
if (token >= 0xC0) {
length = ((token >> 2) & 0x0F) + 4; /* 6b */
offset = ((token & 3) << 8) | src[src_pos++]; /* upper 2b + lower 8b */
}
else if (token >= 0x80) {
length = ((token >> 5) & 3) + 2; /* 2b */
offset = token & 0x1F; /* 5b */
if (offset == 0) {
offset = src[src_pos++];
}
}
else if (token == 0x7F) {
length = (uint16_t)(src[src_pos] | src[src_pos+1] << 8u) + 2;
src_pos += 2;
offset = (uint16_t)(src[src_pos] | src[src_pos+1] << 8u);
src_pos += 2;
}
else {
length = token + 4;
offset = (uint16_t)(src[src_pos] | src[src_pos+1] << 8u);
src_pos += 2;
}
if (dst_pos + length > dst_size) {
length = dst_size - dst_pos;
}
for (int i = 0; i < length; i++) {
dst[dst_pos] = dst[dst_pos - offset];
dst_pos++;
}
}
}
return 0;
}
#endif
......@@ -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);
......@@ -167,6 +167,7 @@ void decode_fadpcm(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacin
/* asf_decoder */
void decode_asf(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
int32_t asf_bytes_to_samples(size_t bytes, int channels);
/* dsa_decoder */
void decode_dsa(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
......@@ -178,7 +179,13 @@ void decode_xmd(VGMSTREAMCHANNEL *stream, sample_t *outbuf, int channelspacing,
void decode_derf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* circus_decoder */
void decode_circus_adpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
typedef struct circus_codec_data circus_codec_data;
circus_codec_data* init_circus_vq(STREAMFILE* sf, off_t start, uint8_t codec, uint8_t flags);
void decode_circus_vq(circus_codec_data* data, sample_t* outbuf, int32_t samples_to_do, int channels);
void reset_circus_vq(circus_codec_data* data);
void seek_circus_vq(circus_codec_data* data, int32_t num_sample);
void free_circus_vq(circus_codec_data* data);
void decode_circus_adpcm(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* oki_decoder */
void decode_pcfx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int mode);
......
......@@ -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 ?
......
......@@ -173,25 +173,25 @@ void decode_hevag(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspaci
if (shift_factor > 12)
shift_factor = 9; /* ? */
shift_factor = 20 - shift_factor;
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t sample = 0, scale = 0;
int32_t sample = 0;
if (flag < 0x07) { /* with flag 0x07 decoded sample must be 0 */
uint8_t nibbles = frame[0x02 + i/2];
scale = i&1 ? /* low nibble first */
sample = (i&1 ? /* low nibble first */
get_high_nibble_signed(nibbles):
get_low_nibble_signed(nibbles);
sample = (hist1 * hevag_coefs[coef_index][0] +
hist2 * hevag_coefs[coef_index][1] +
hist3 * hevag_coefs[coef_index][2] +
hist4 * hevag_coefs[coef_index][3] ) / 32;
sample = (sample + (scale << (20 - shift_factor)) + 128) >> 8;
sample = clamp16(sample);
get_low_nibble_signed(nibbles)) << shift_factor; /*scale*/
sample = ((hist1 * hevag_coefs[coef_index][0] +
hist2 * hevag_coefs[coef_index][1] +
hist3 * hevag_coefs[coef_index][2] +
hist4 * hevag_coefs[coef_index][3]) >> 5) + sample;
sample >>= 8;
}
outbuf[sample_count] = sample;
outbuf[sample_count] = clamp16(sample); /*clamping*/
sample_count += channelspacing;
hist4 = hist3;
......
......@@ -93,22 +93,22 @@ void decode_psx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing,
VGM_ASSERT_ONCE(flag > 7,"PS-ADPCM: unknown flag at %x\n", (uint32_t)frame_offset); /* meta should use PSX-badflags */
shift_factor = 20 - shift_factor;
/* decode nibbles */
for (i = first_sample; i < first_sample + samples_to_do; i++) {
int32_t sample = 0;
if (flag < 0x07) { /* with flag 0x07 decoded sample must be 0 */
uint8_t nibbles = frame[0x02 + i/2];