mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-22 05:10:02 +01:00
commit
dbbdc2c8d0
@ -1,7 +1,7 @@
|
||||
#include "coding.h"
|
||||
#include "../util.h"
|
||||
|
||||
void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type) {
|
||||
void decode_adx(VGMSTREAMCHANNEL* stream, sample_t* outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int32_t frame_size, coding_t coding_type) {
|
||||
uint8_t frame[0x12] = {0};
|
||||
off_t frame_offset;
|
||||
int i, frames_in, sample_count = 0;
|
||||
@ -21,12 +21,22 @@ void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
|
||||
frame_offset = stream->offset + bytes_per_frame * frames_in;
|
||||
read_streamfile(frame, frame_offset, bytes_per_frame, stream->streamfile); /* ignore EOF errors */
|
||||
|
||||
scale = get_16bitBE(frame+0x00);
|
||||
|
||||
scale = get_s16be(frame+0x00);
|
||||
switch(coding_type) {
|
||||
case coding_CRI_ADX:
|
||||
scale = scale + 1;
|
||||
coef1 = stream->adpcm_coef[0];
|
||||
coef2 = stream->adpcm_coef[1];
|
||||
|
||||
/* Detect EOF scale (0x8001) found in some ADX of any type, signals "stop decoding" (without this frame?).
|
||||
* Normally num_samples stops right before it, but ADXPLAY will honor it even in the middle on a file
|
||||
* (may repeat last sample buffer). Some Baroque (SAT) videos set it on file end, but num_samples goes beyond.
|
||||
* Just the upper bit triggers it even in encrypted ADX (max is 0x7FFF), but the check only here just in case. */
|
||||
if (frame[0] == 0x80 && frame[1] == 0x01) {
|
||||
scale = 0; /* fix scaled click, maybe should just exit */
|
||||
VGM_LOG("ADX: reached EOF scale\n");
|
||||
}
|
||||
break;
|
||||
case coding_CRI_ADX_exp:
|
||||
scale = 1 << (12 - scale);
|
||||
@ -79,6 +89,6 @@ void decode_adx(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing
|
||||
}
|
||||
}
|
||||
|
||||
void adx_next_key(VGMSTREAMCHANNEL * stream) {
|
||||
void adx_next_key(VGMSTREAMCHANNEL* stream) {
|
||||
stream->adx_xor = (stream->adx_xor * stream->adx_mult + stream->adx_add) & 0x7fff;
|
||||
}
|
||||
|
@ -950,11 +950,11 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_EA_1SNH, "Electronic Arts 1SNh header"},
|
||||
{meta_EA_EACS, "Electronic Arts EACS header"},
|
||||
{meta_SL3, "Atari Melbourne House SL3 header"},
|
||||
{meta_FSB1, "FMOD Sample Bank (FSB1) Header"},
|
||||
{meta_FSB2, "FMOD Sample Bank (FSB2) Header"},
|
||||
{meta_FSB3, "FMOD Sample Bank (FSB3) Header"},
|
||||
{meta_FSB4, "FMOD Sample Bank (FSB4) Header"},
|
||||
{meta_FSB5, "FMOD Sample Bank (FSB5) Header"},
|
||||
{meta_FSB1, "FMOD FSB1 header"},
|
||||
{meta_FSB2, "FMOD FSB2 header"},
|
||||
{meta_FSB3, "FMOD FSB3 header"},
|
||||
{meta_FSB4, "FMOD FSB4 header"},
|
||||
{meta_FSB5, "FMOD FSB5 header"},
|
||||
{meta_RWX, "RWX Header"},
|
||||
{meta_XWB, "Microsoft XWB header"},
|
||||
{meta_PS2_XA30, "Reflections XA30 PS2 header"},
|
||||
|
@ -28,7 +28,6 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
|
||||
samples_this_block = vgmstream_get_samples(data->segments[data->current_segment]);
|
||||
|
||||
//VGM_LOG("segment decode start: cur=%i, this=%i, into=%i\n", data->current_segment, samples_this_block, vgmstream->samples_into_block);
|
||||
while (samples_written < sample_count) {
|
||||
int samples_to_do;
|
||||
|
||||
@ -39,7 +38,7 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
}
|
||||
|
||||
/* detect segment change and restart (after loop, but before decode, to allow looping to kick in) */
|
||||
if (vgmstream->samples_into_block == samples_this_block) {
|
||||
if (vgmstream->samples_into_block >= samples_this_block) {
|
||||
data->current_segment++;
|
||||
|
||||
/* could happen on last segment trying to decode more samples */
|
||||
@ -63,6 +62,11 @@ void render_vgmstream_segmented(sample_t* outbuf, int32_t sample_count, VGMSTREA
|
||||
if (samples_to_do > VGMSTREAM_SEGMENT_SAMPLE_BUFFER /*&& use_internal_buffer*/) /* always for fade/etc mixes */
|
||||
samples_to_do = VGMSTREAM_SEGMENT_SAMPLE_BUFFER;
|
||||
|
||||
if (samples_to_do < 0) { /* ? */
|
||||
VGM_LOG("SEGMENTED: wrong samples_to_do %i found\n", samples_to_do);
|
||||
break;
|
||||
}
|
||||
|
||||
render_vgmstream(
|
||||
use_internal_buffer ?
|
||||
data->buffer : &outbuf[samples_written * data->output_channels],
|
||||
|
@ -36,7 +36,7 @@ typedef struct {
|
||||
static layered_layout_data* build_layered_fsb5_celt(STREAMFILE* sf, fsb5_header* fsb5);
|
||||
static layered_layout_data* build_layered_fsb5_atrac9(STREAMFILE* sf, fsb5_header* fsb5, off_t configs_offset, size_t configs_size);
|
||||
|
||||
/* FSB5 - FMOD Studio multiplatform format */
|
||||
/* FSB5 - Firelight's FMOD Studio SoundBank format */
|
||||
VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
fsb5_header fsb5 = {0};
|
||||
@ -211,6 +211,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
|
||||
/* found in some XMA2/Vorbis/FADPCM */
|
||||
VGM_LOG("FSB5: stream %i flag %x with value %08x\n", i, extraflag_type, read_32bitLE(extraflag_offset+0x04,sf));
|
||||
break;
|
||||
case 0x0e: /* number of layered Vorbis channels [Invisible, Inc. (Switch)] */
|
||||
default:
|
||||
VGM_LOG("FSB5: stream %i unknown flag 0x%x at %x + 0x04 (size 0x%x)\n", i, extraflag_type, (uint32_t)extraflag_offset, extraflag_size);
|
||||
break;
|
||||
|
47
src/render.c
47
src/render.c
@ -243,9 +243,8 @@ static int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstre
|
||||
|
||||
if (vgmstream->current_sample > vgmstream->num_samples) {
|
||||
int channels = vgmstream->channels;
|
||||
int to_do = sample_count;
|
||||
int done = 0;
|
||||
memset(buf + done * channels, 0, to_do * sizeof(sample_t) * channels);
|
||||
|
||||
memset(buf, 0, sample_count * sizeof(sample_t) * channels);
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
@ -310,27 +309,33 @@ static int render_layout(sample_t* buf, int32_t sample_count, VGMSTREAM* vgmstre
|
||||
|
||||
if (vgmstream->current_sample > vgmstream->num_samples) {
|
||||
int channels = vgmstream->channels;
|
||||
int to_do = (vgmstream->current_sample - vgmstream->num_samples);
|
||||
int done = sample_count - to_do;
|
||||
memset(buf + done * channels, 0, to_do * sizeof(sample_t) * channels);
|
||||
int32_t excess, decoded;
|
||||
|
||||
excess = (vgmstream->current_sample - vgmstream->num_samples);
|
||||
if (excess > sample_count)
|
||||
excess = sample_count;
|
||||
decoded = sample_count - excess;
|
||||
|
||||
memset(buf + decoded * channels, 0, excess * sizeof(sample_t) * channels);
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
|
||||
static void render_trim(VGMSTREAM* vgmstream) {
|
||||
/* big-ish buffer since the average trim would be a few seconds for >=2ch at 48000, and less calls = better */
|
||||
sample_t tmpbuf[0x40000];
|
||||
int max_samples = 0x40000 / vgmstream->pstate.input_channels;
|
||||
sample_t* tmpbuf = vgmstream->tmpbuf;
|
||||
size_t tmpbuf_size = vgmstream->tmpbuf_size;
|
||||
int32_t buf_samples = tmpbuf_size / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
|
||||
while (vgmstream->pstate.trim_begin_left) {
|
||||
int to_do = vgmstream->pstate.trim_begin_left;
|
||||
if (to_do > max_samples)
|
||||
to_do = max_samples;
|
||||
if (to_do > buf_samples)
|
||||
to_do = buf_samples;
|
||||
|
||||
render_layout(tmpbuf, to_do, vgmstream);
|
||||
/* just consume samples so no need to apply mixing */
|
||||
/* no mixing */
|
||||
vgmstream->pstate.trim_begin_left -= to_do;
|
||||
}
|
||||
}
|
||||
@ -489,18 +494,18 @@ static void seek_force_loop(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
static void seek_force_decode(VGMSTREAM* vgmstream, int samples) {
|
||||
sample_t tmpbuf[0x40000]; /* big-ish buffer as less calls = better */
|
||||
int32_t buf_samples = 0x40000 / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
sample_t* tmpbuf = vgmstream->tmpbuf;
|
||||
size_t tmpbuf_size = vgmstream->tmpbuf_size;
|
||||
int32_t buf_samples = tmpbuf_size / vgmstream->channels; /* base channels, no need to apply mixing */
|
||||
|
||||
int i;
|
||||
while (samples) {
|
||||
int to_do = samples;
|
||||
if (to_do > buf_samples)
|
||||
to_do = buf_samples;
|
||||
|
||||
for (i = 0; i < samples; i += buf_samples) {
|
||||
int to_get = buf_samples;
|
||||
if (i + buf_samples > samples)
|
||||
to_get = samples - i;
|
||||
|
||||
render_layout(tmpbuf, to_get, vgmstream);
|
||||
render_layout(tmpbuf, to_do, vgmstream);
|
||||
/* no mixing */
|
||||
samples -= to_do;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,6 +726,12 @@ VGMSTREAM* allocate_vgmstream(int channel_count, int loop_flag) {
|
||||
if (!vgmstream->loop_ch) goto fail;
|
||||
}
|
||||
|
||||
/* garbage buffer for decode discarding (local bufs may cause stack overflows with segments/layers)
|
||||
* in theory the bigger the better but in practice there isn't much difference */
|
||||
vgmstream->tmpbuf_size = 0x10000; /* for all channels */
|
||||
vgmstream->tmpbuf = malloc(sizeof(sample_t) * vgmstream->tmpbuf_size);
|
||||
|
||||
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->loop_flag = loop_flag;
|
||||
|
||||
@ -736,6 +742,7 @@ VGMSTREAM* allocate_vgmstream(int channel_count, int loop_flag) {
|
||||
fail:
|
||||
if (vgmstream) {
|
||||
mixing_close(vgmstream);
|
||||
free(vgmstream->tmpbuf);
|
||||
free(vgmstream->ch);
|
||||
free(vgmstream->start_ch);
|
||||
free(vgmstream->loop_ch);
|
||||
@ -776,6 +783,7 @@ void close_vgmstream(VGMSTREAM* vgmstream) {
|
||||
}
|
||||
|
||||
mixing_close(vgmstream);
|
||||
free(vgmstream->tmpbuf);
|
||||
free(vgmstream->ch);
|
||||
free(vgmstream->start_ch);
|
||||
free(vgmstream->loop_ch);
|
||||
|
@ -975,6 +975,8 @@ typedef struct {
|
||||
play_state_t pstate; /* player state (applied over decoding) */
|
||||
int loop_count; /* counter of complete loops (1=looped once) */
|
||||
int loop_target; /* max loops before continuing with the stream end (loops forever if not set) */
|
||||
sample_t* tmpbuf; /* garbage buffer used for seeking/trimming */
|
||||
size_t tmpbuf_size; /* for all channels (samples = tmpbuf_size / channels) */
|
||||
|
||||
} VGMSTREAM;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user