Updated VGMStream to r1050-359-g00523fb.
parent
786868d191
commit
f6cf915fc2
|
@ -5,37 +5,30 @@
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
#define AHX_EXPECTED_FRAME_SIZE 0x414
|
#define AHX_EXPECTED_FRAME_SIZE 0x414
|
||||||
#define MPEG_DEFAULT_BUFFER_SIZE 0x1000 /* should be >= AHX_EXPECTED_FRAME_SIZE */
|
#define MPEG_DEFAULT_BUFFER_SIZE 0x1000 /* should be >= AHX_EXPECTED_FRAME_SIZE */
|
||||||
#define MPEG_SYNC_BITS 0xFFE00000
|
|
||||||
#define MPEG_PADDING_BIT 0x200
|
|
||||||
|
|
||||||
static mpeg_codec_data *init_mpeg_codec_data_internal(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int interleaved, int fixed_frame_size, int fsb_padding);
|
typedef struct {
|
||||||
|
int version;
|
||||||
|
int layer;
|
||||||
|
int bit_rate;
|
||||||
|
int sample_rate;
|
||||||
|
int frame_samples;
|
||||||
|
int frame_size; /* bytes */
|
||||||
|
int channels;
|
||||||
|
coding_t coding_type;
|
||||||
|
} mpeg_frame_info;
|
||||||
|
|
||||||
static mpg123_handle * init_mpg123_handle();
|
static mpg123_handle * init_mpg123_handle();
|
||||||
|
|
||||||
static void decode_mpeg_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
static void decode_mpeg_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||||
static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||||
static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, mpg123_handle *m, int channels, int num_stream, size_t block_size);
|
static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, mpg123_handle *m, int channels, int num_stream, size_t block_size);
|
||||||
|
static int update_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamfile, off_t offset);
|
||||||
static void update_frame_sizes(mpeg_codec_data * data, VGMSTREAMCHANNEL *stream);
|
static int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info * info);
|
||||||
static void update_base_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamFile, off_t start_offset, int fixed_frame_size, int current_frame_size, int fsb_padding);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits regular MPEG.
|
* Inits regular MPEG.
|
||||||
*/
|
*/
|
||||||
mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels) {
|
mpeg_codec_data *init_mpeg_codec_data(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels) {
|
||||||
return init_mpeg_codec_data_internal(streamfile, start_offset, coding_type, channels, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Init interleaved MPEG.
|
|
||||||
*/
|
|
||||||
mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding) {
|
|
||||||
return init_mpeg_codec_data_internal(streamfile, start_offset, coding_type, channels, 1, fixed_frame_size, fsb_padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
static mpeg_codec_data *init_mpeg_codec_data_internal(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int interleaved, int fixed_frame_size, int fsb_padding) {
|
|
||||||
mpeg_codec_data *data = NULL;
|
mpeg_codec_data *data = NULL;
|
||||||
int current_frame_size = 0;
|
|
||||||
|
|
||||||
/* init codec */
|
/* init codec */
|
||||||
data = calloc(1,sizeof(mpeg_codec_data));
|
data = calloc(1,sizeof(mpeg_codec_data));
|
||||||
|
@ -67,7 +60,15 @@ static mpeg_codec_data *init_mpeg_codec_data_internal(STREAMFILE *streamfile, of
|
||||||
read_offset+=1;
|
read_offset+=1;
|
||||||
|
|
||||||
rc = mpg123_decode(main_m, data->buffer,data->buffer_size, NULL,0, &bytes_done);
|
rc = mpg123_decode(main_m, data->buffer,data->buffer_size, NULL,0, &bytes_done);
|
||||||
if (rc != MPG123_OK && rc != MPG123_NEW_FORMAT && rc != MPG123_NEED_MORE) goto fail; //todo handle MPG123_DONE
|
if (rc != MPG123_OK && rc != MPG123_NEW_FORMAT && rc != MPG123_NEED_MORE) {
|
||||||
|
VGM_LOG("MPEG: unable to set up mpp123 @ 0x%08lx to 0x%08lx\n", start_offset, read_offset);
|
||||||
|
goto fail; //todo handle MPG123_DONE?
|
||||||
|
}
|
||||||
|
if (read_offset > 0x5000) { /* don't hang in some incorrectly detected formats */
|
||||||
|
VGM_LOG("MPEG: unable to find mpeg data @ 0x%08lx to 0x%08lx\n", start_offset, read_offset);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
} while (rc != MPG123_NEW_FORMAT);
|
} while (rc != MPG123_NEW_FORMAT);
|
||||||
|
|
||||||
/* check first frame header and validate */
|
/* check first frame header and validate */
|
||||||
|
@ -80,7 +81,7 @@ static mpeg_codec_data *init_mpeg_codec_data_internal(STREAMFILE *streamfile, of
|
||||||
goto fail;
|
goto fail;
|
||||||
if (sample_rate_per_frame != mi.rate)
|
if (sample_rate_per_frame != mi.rate)
|
||||||
goto fail;
|
goto fail;
|
||||||
if ((channels != -1 && channels_per_frame != channels && !interleaved))
|
if ((channels != -1 && channels_per_frame != channels))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (mi.version == MPG123_1_0 && mi.layer == 1)
|
if (mi.version == MPG123_1_0 && mi.layer == 1)
|
||||||
|
@ -117,28 +118,69 @@ static mpeg_codec_data *init_mpeg_codec_data_internal(STREAMFILE *streamfile, of
|
||||||
data->channels_per_frame = channels_per_frame;
|
data->channels_per_frame = channels_per_frame;
|
||||||
data->samples_per_frame = samples_per_frame;
|
data->samples_per_frame = samples_per_frame;
|
||||||
|
|
||||||
/* unlikely (can fixed with bigger buffer or a feed loop) */
|
|
||||||
if (mi.framesize > data->buffer_size)
|
|
||||||
goto fail;
|
|
||||||
current_frame_size = mi.framesize;
|
|
||||||
|
|
||||||
/* reinit, to ignore the reading we've done so far */
|
/* reinit, to ignore the reading we've done so far */
|
||||||
mpg123_open_feed(main_m);
|
mpg123_open_feed(main_m);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init interleaved audio, which needs separate decoders per stream and frame size stuff.
|
return data;
|
||||||
* We still leave data->m as a "base" info/format to simplify some stuff (could be improved) */
|
|
||||||
if (interleaved) {
|
fail:
|
||||||
|
free_mpeg(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init interleaved MPEG (also accepts normal MPEGs, but it's less error tolerant than normal MPEG init).
|
||||||
|
*/
|
||||||
|
mpeg_codec_data *init_mpeg_codec_data_interleaved(STREAMFILE *streamfile, off_t start_offset, coding_t *coding_type, int channels, int fixed_frame_size, int fsb_padding) {
|
||||||
|
mpeg_codec_data *data = NULL;
|
||||||
|
|
||||||
|
/* init codec */
|
||||||
|
data = calloc(1,sizeof(mpeg_codec_data));
|
||||||
|
if (!data) goto fail;
|
||||||
|
|
||||||
|
data->buffer_size = MPEG_DEFAULT_BUFFER_SIZE;
|
||||||
|
data->buffer = calloc(sizeof(uint8_t), data->buffer_size);
|
||||||
|
if (!data->buffer) goto fail;
|
||||||
|
|
||||||
|
data->m = init_mpg123_handle();
|
||||||
|
if (!data->m) goto fail;
|
||||||
|
|
||||||
|
/* interleaved setup */
|
||||||
|
{
|
||||||
|
mpeg_frame_info info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
data->interleaved = interleaved;
|
|
||||||
|
data->interleaved = 1;
|
||||||
|
|
||||||
|
/* get frame info at offset */
|
||||||
|
if ( !mpeg_get_frame_info(streamfile, start_offset, &info) )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
*coding_type = info.coding_type;
|
||||||
|
data->channels_per_frame = info.channels;
|
||||||
|
data->sample_rate_per_frame = info.sample_rate;
|
||||||
|
data->samples_per_frame = info.frame_samples;
|
||||||
|
|
||||||
|
data->fixed_frame_size = fixed_frame_size;
|
||||||
|
data->current_frame_size = fixed_frame_size;
|
||||||
|
data->fsb_padding = fsb_padding;
|
||||||
|
|
||||||
|
/* get frame size from the first frame as it can be used externally to calc interleave */
|
||||||
|
if ( !update_frame_sizes(data, streamfile, start_offset) )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* unlikely, can fixed with bigger buffer or a feed loop */
|
||||||
|
if (info.frame_size > data->buffer_size)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
if (channels < 1 || channels > 32) goto fail; /* arbitrary max */
|
if (channels < 1 || channels > 32) goto fail; /* arbitrary max */
|
||||||
if (channels < data->channels_per_frame) goto fail;
|
if (channels < data->channels_per_frame) goto fail;
|
||||||
|
|
||||||
update_base_frame_sizes(data, streamfile, start_offset, fixed_frame_size, current_frame_size, fsb_padding);
|
//todo improve (less buffers / simplify data->ms)
|
||||||
if (!data->base_frame_size) goto fail;
|
/* Init interleaved audio, which needs separate decoders per stream and frame size stuff.
|
||||||
|
* We still leave data->m as a "base" info/format to simplify some stuff */
|
||||||
data->ms_size = channels / data->channels_per_frame;
|
data->ms_size = channels / data->channels_per_frame;
|
||||||
data->ms = calloc(sizeof(mpg123_handle *), data->ms_size);
|
data->ms = calloc(sizeof(mpg123_handle *), data->ms_size);
|
||||||
for (i=0; i < data->ms_size; i++) {
|
for (i=0; i < data->ms_size; i++) {
|
||||||
|
@ -163,6 +205,7 @@ fail:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inits MPEG for AHX, which ignores frame headers.
|
* Inits MPEG for AHX, which ignores frame headers.
|
||||||
*/
|
*/
|
||||||
|
@ -292,7 +335,7 @@ static void decode_mpeg_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode interleaved (multichannel) MPEG. Works with mono/stereo too.
|
* Decode interleaved (multichannel) MPEG. Works with mono/stereo too.
|
||||||
* Channels (1 or 2), samples and frame size per stream should be constant. //todo extra validations
|
* Channels (1 or 2), samples and frame size per stream should be constant.
|
||||||
*
|
*
|
||||||
* Reads frame 'streams' (ex. 4ch = 1+1+1+1 = 4 streams or 2+2 = 2 streams), decodes
|
* Reads frame 'streams' (ex. 4ch = 1+1+1+1 = 4 streams or 2+2 = 2 streams), decodes
|
||||||
* samples per stream and muxes them into a single internal buffer before copying to outbuf
|
* samples per stream and muxes them into a single internal buffer before copying to outbuf
|
||||||
|
@ -330,6 +373,21 @@ static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data
|
||||||
for (i=0; i < data->ms_size; i++) {
|
for (i=0; i < data->ms_size; i++) {
|
||||||
decode_mpeg_interleave_samples(&vgmstream->ch[i], data, data->ms[i], channels, i, vgmstream->interleave_block_size);
|
decode_mpeg_interleave_samples(&vgmstream->ch[i], data, data->ms[i], channels, i, vgmstream->interleave_block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* discard (for looping): 'remove' decoded samples from the buffer */
|
||||||
|
if (data->samples_to_discard) {
|
||||||
|
size_t bytes_to_discard = data->samples_to_discard * sizeof(sample) * channels;
|
||||||
|
|
||||||
|
/* 'remove' all buffer at most */
|
||||||
|
if (bytes_to_discard > data->bytes_in_interleave_buffer)
|
||||||
|
bytes_to_discard = data->bytes_in_interleave_buffer;
|
||||||
|
|
||||||
|
/* pretend the samples were used up */
|
||||||
|
data->bytes_used_in_interleave_buffer = bytes_to_discard;
|
||||||
|
|
||||||
|
/* and readjust discard */
|
||||||
|
data->samples_to_discard -= bytes_to_discard / sizeof(sample) / channels;;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,13 +399,24 @@ static void decode_mpeg_interleave(VGMSTREAM * vgmstream, mpeg_codec_data * data
|
||||||
*/
|
*/
|
||||||
static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, mpg123_handle *m, int channels, int num_stream, size_t block_size) {
|
static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_data * data, mpg123_handle *m, int channels, int num_stream, size_t block_size) {
|
||||||
size_t bytes_done;
|
size_t bytes_done;
|
||||||
|
size_t stream_size = get_streamfile_size(stream->streamfile);
|
||||||
|
|
||||||
/* decode samples from 1 full frame */
|
/* decode samples from 1 full frame */
|
||||||
do {
|
do {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* padded frame stuff */
|
/* padded frame stuff */
|
||||||
update_frame_sizes(data, stream);
|
rc = update_frame_sizes(data, stream->streamfile, stream->offset);
|
||||||
|
/* ignore any errors and continue; mpg123 will probably sync */
|
||||||
|
VGM_ASSERT(rc==0, "MPEG: frame error @ 0x%08lx (prev size=0x%x / padding=0x%x)\n", stream->offset, data->current_frame_size, data->current_padding);
|
||||||
|
|
||||||
|
/* extra EOF check for edge cases when the caller tries to read more samples than possible */
|
||||||
|
if (stream->offset > stream_size) {
|
||||||
|
memset(data->frame_buffer, 0, data->frame_buffer_size);
|
||||||
|
bytes_done = data->frame_buffer_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* read more raw data (only 1 frame, to check interleave block end) */
|
/* read more raw data (only 1 frame, to check interleave block end) */
|
||||||
if (!data->buffer_full) {
|
if (!data->buffer_full) {
|
||||||
|
@ -385,7 +454,7 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_
|
||||||
|
|
||||||
/* samples per frame should be constant... */
|
/* samples per frame should be constant... */
|
||||||
if (bytes_done > 0 && bytes_done < data->frame_buffer_size) {
|
if (bytes_done > 0 && bytes_done < data->frame_buffer_size) {
|
||||||
VGM_LOG("borked frame: %i bytes done, expected %i, rc=%i\n", bytes_done, data->frame_buffer_size, rc);
|
VGM_LOG("MPEG: borked frame @ 0x%08lx (%i bytes done, expected %i, rc=%i)\n", stream->offset, bytes_done, data->frame_buffer_size, rc);
|
||||||
memset(data->frame_buffer + bytes_done, 0, data->frame_buffer_size - bytes_done);
|
memset(data->frame_buffer + bytes_done, 0, data->frame_buffer_size - bytes_done);
|
||||||
bytes_done = data->frame_buffer_size;
|
bytes_done = data->frame_buffer_size;
|
||||||
}
|
}
|
||||||
|
@ -422,44 +491,36 @@ static void decode_mpeg_interleave_samples(VGMSTREAMCHANNEL *stream, mpeg_codec_
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Very Clunky Stuff for FSBs of varying padding sizes per frame.
|
* Get frame size info for the current frame, needed by FSBs of varying padding.
|
||||||
* Padding sometimes contains next frame header so we can't feed it to mpg123 or it gets confused.
|
* Padding sometimes contains next frame header so we can't feed it to mpg123 or it gets confused.
|
||||||
* Expected to be called at the beginning of a new frame.
|
* Expected to be called at the beginning of a new frame.
|
||||||
*/
|
*/
|
||||||
static void update_frame_sizes(mpeg_codec_data * data, VGMSTREAMCHANNEL *stream) {
|
static int update_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamfile, off_t offset) {
|
||||||
if (!data->fixed_frame_size) {
|
if (!data->fixed_frame_size) {
|
||||||
/* Manually fix frame size. Not ideal but mpg123_info.framesize is weird. */
|
mpeg_frame_info info;
|
||||||
uint32_t header = (uint32_t)read_32bitBE(stream->offset, stream->streamfile);
|
|
||||||
if (header & MPEG_SYNC_BITS)
|
|
||||||
data->current_frame_size = data->base_frame_size + (header & MPEG_PADDING_BIT ? 1 : 0);
|
|
||||||
else
|
|
||||||
data->current_frame_size = 0; /* todo skip invalid frame? */
|
|
||||||
|
|
||||||
if (data->fsb_padding) //todo not always ok
|
/* Manually find new frame size. Not ideal but mpg123_info.framesize is wrong sometimes */
|
||||||
|
if ( !mpeg_get_frame_info(streamfile, offset, &info) )
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* could mess some calcs */
|
||||||
|
VGM_ASSERT(data->sample_rate_per_frame != info.sample_rate || data->samples_per_frame != info.frame_samples,
|
||||||
|
"MPEG: variable frame info found @ 0x%08lx", offset);
|
||||||
|
|
||||||
|
/* new frame */
|
||||||
|
data->current_frame_size = info.frame_size;
|
||||||
|
|
||||||
|
/* get FSB padding for MPEG1/2 Layer III (MPEG1 Layer II doesn't use it, and Layer I doesn't seem to be supported) */
|
||||||
|
if (data->fsb_padding && info.layer == 3) {
|
||||||
data->current_padding = (data->current_frame_size % data->fsb_padding) ?
|
data->current_padding = (data->current_frame_size % data->fsb_padding) ?
|
||||||
data->fsb_padding - (data->current_frame_size % data->fsb_padding) : 0;
|
data->fsb_padding - (data->current_frame_size % data->fsb_padding) : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
static void update_base_frame_sizes(mpeg_codec_data * data, STREAMFILE *streamFile, off_t start_offset, int fixed_frame_size, int current_frame_size, int fsb_padding) {
|
|
||||||
if (fixed_frame_size) {
|
|
||||||
data->fixed_frame_size = fixed_frame_size;
|
|
||||||
data->base_frame_size = data->fixed_frame_size;
|
|
||||||
data->current_frame_size = data->fixed_frame_size;
|
|
||||||
} else {
|
|
||||||
/* adjust sizes in the first frame */
|
|
||||||
//todo: sometimes mpg123_info.framesize is not correct, manually calculate? (Xing headers?)
|
|
||||||
uint32_t header = (uint32_t)read_32bitBE(start_offset, streamFile);
|
|
||||||
if (header & MPEG_SYNC_BITS)
|
|
||||||
data->base_frame_size = current_frame_size - (header & MPEG_PADDING_BIT ? 1 : 0);
|
|
||||||
else
|
|
||||||
data->base_frame_size = 0; /* todo skip invalid frame? */
|
|
||||||
|
|
||||||
data->current_frame_size = current_frame_size;
|
return 1;
|
||||||
data->fsb_padding = fsb_padding;
|
|
||||||
if (data->fsb_padding) //todo not always ok
|
fail:
|
||||||
data->current_padding = (data->current_frame_size % data->fsb_padding) ?
|
return 0;
|
||||||
data->fsb_padding - (data->current_frame_size % data->fsb_padding) : 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -597,7 +658,7 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
|
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
|
||||||
/* won't work for fake or multistream MPEG */
|
/* won't work for fake AHX MPEG */
|
||||||
off_t input_offset;
|
off_t input_offset;
|
||||||
mpeg_codec_data *data = vgmstream->codec_data;
|
mpeg_codec_data *data = vgmstream->codec_data;
|
||||||
|
|
||||||
|
@ -613,7 +674,7 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
|
||||||
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
|
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
|
||||||
}
|
}
|
||||||
/* manually add skip samples, since we don't really know the correct offset */
|
/* manually add skip samples, since we don't really know the correct offset */
|
||||||
//todo call decode with samples_to_do and fake header
|
data->samples_to_discard = num_sample;
|
||||||
|
|
||||||
data->bytes_in_interleave_buffer = 0;
|
data->bytes_in_interleave_buffer = 0;
|
||||||
data->bytes_used_in_interleave_buffer = 0;
|
data->bytes_used_in_interleave_buffer = 0;
|
||||||
|
@ -651,4 +712,94 @@ void mpeg_set_error_logging(mpeg_codec_data * data, int enable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************/
|
||||||
|
/* FRAME HELPERS */
|
||||||
|
/*****************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets info from a MPEG frame header at offset. Normally you would use mpg123_info but somehow
|
||||||
|
* it's wrong at times (maybe because we use an ancient version) so here we do our thing.
|
||||||
|
*/
|
||||||
|
static int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info * info) {
|
||||||
|
/* index tables */
|
||||||
|
static const int versions[4] = { /* MPEG 2.5 */ 3, /* reserved */ -1, /* MPEG 2 */ 2, /* MPEG 1 */ 1 };
|
||||||
|
static const int layers[4] = { -1,3,2,1 };
|
||||||
|
static const int bit_rates[5][16] = { /* [version index ][bit rate index] (0=free, -1=bad) */
|
||||||
|
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 Layer I */
|
||||||
|
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 Layer II */
|
||||||
|
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 Layer III */
|
||||||
|
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2/2.5 Layer I */
|
||||||
|
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 }, /* MPEG2/2.5 Layer II/III */
|
||||||
|
};
|
||||||
|
static const int sample_rates[4][4] = { /* [version][sample rate index] */
|
||||||
|
{ 44100, 48000, 32000, -1}, /* MPEG1 */
|
||||||
|
{ 22050, 24000, 16000, -1}, /* MPEG2 */
|
||||||
|
{ 11025, 12000, 8000, -1}, /* MPEG2.5 */
|
||||||
|
};
|
||||||
|
static const int channels[4] = { 2,2,2, 1 }; /* [channel] */
|
||||||
|
static const int frame_samples[3][3] = { /* [version][layer] */
|
||||||
|
{ 384, 1152, 1152 }, /* MPEG1 */
|
||||||
|
{ 384, 1152, 576 }, /* MPEG2 */
|
||||||
|
{ 384, 1152, 576 } /* MPEG2.5 */
|
||||||
|
};
|
||||||
|
static const coding_t coding_types[3][3] = { /* [version][layer] */
|
||||||
|
{ coding_MPEG1_L1, coding_MPEG1_L2, coding_MPEG1_L3 },
|
||||||
|
{ coding_MPEG2_L1, coding_MPEG2_L2, coding_MPEG2_L3 },
|
||||||
|
{ coding_MPEG25_L1, coding_MPEG25_L2, coding_MPEG25_L3 },
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t header;
|
||||||
|
int idx, padding;
|
||||||
|
|
||||||
|
|
||||||
|
memset(info, 0, sizeof(*info));
|
||||||
|
|
||||||
|
header = read_32bitBE(offset, streamfile);
|
||||||
|
|
||||||
|
if ((header >> 21) != 0x7FF) /* 31-21: sync */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
info->version = versions[(header >> 19) & 0x3]; /* 20,19: version */
|
||||||
|
if (info->version <= 0) goto fail;
|
||||||
|
|
||||||
|
info->layer = layers[(header >> 17) & 0x3]; /* 18,17: layer */
|
||||||
|
if (info->layer <= 0) goto fail;
|
||||||
|
|
||||||
|
//crc = (header >> 16) & 0x1; /* 16: protected by crc? */
|
||||||
|
|
||||||
|
idx = (info->version==1 ? info->layer-1 : (3 + (info->layer==1 ? 0 : 1)));
|
||||||
|
info->bit_rate = bit_rates[idx][(header >> 12) & 0xf]; /* 15-12: bit rate */
|
||||||
|
if (info->bit_rate <= 0) goto fail;
|
||||||
|
|
||||||
|
info->sample_rate = sample_rates[info->version-1][(header >> 10) & 0x3]; /* 11-10: sampling rate */
|
||||||
|
if (info->sample_rate <= 0) goto fail;
|
||||||
|
|
||||||
|
padding = (header >> 9) & 0x1; /* 9: padding? */
|
||||||
|
//private = (header >> 8) & 0x1; /* 8: private bit */
|
||||||
|
|
||||||
|
info->channels = channels[(header >> 6) & 0x3]; /* 7,6: channel mode */
|
||||||
|
|
||||||
|
//js_mode = (header >> 4) & 0x3; /* 5,4: mode extension for joint stereo */
|
||||||
|
//copyright = (header >> 3) & 0x1; /* 3: copyrighted */
|
||||||
|
//original = (header >> 2) & 0x1; /* 2: original */
|
||||||
|
//emphasis = (header >> 0) & 0x3; /* 1,0: emphasis */
|
||||||
|
|
||||||
|
info->frame_samples = frame_samples[info->version-1][info->layer-1];
|
||||||
|
|
||||||
|
/* calculate frame length (from hcs's fsb_mpeg) */
|
||||||
|
switch (info->frame_samples) {
|
||||||
|
case 384: info->frame_size = (12l * info->bit_rate * 1000l / info->sample_rate + padding) * 4; break;
|
||||||
|
case 576: info->frame_size = (72l * info->bit_rate * 1000l / info->sample_rate + padding); break;
|
||||||
|
case 1152: info->frame_size = (144l * info->bit_rate * 1000l / info->sample_rate + padding); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->coding_type = coding_types[info->version-1][info->layer-1];
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,30 +1,27 @@
|
||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
|
/* BCSTM - Nintendo 3DS format */
|
||||||
VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
|
|
||||||
coding_t coding_type;
|
coding_t coding_type;
|
||||||
|
|
||||||
off_t info_offset = 0, seek_offset = 0, data_offset = 0;
|
off_t info_offset = 0, seek_offset = 0, data_offset = 0;
|
||||||
uint16_t temp_id;
|
uint16_t temp_id;
|
||||||
int codec_number;
|
int codec_number;
|
||||||
int channel_count;
|
int channel_count, loop_flag;
|
||||||
int loop_flag;
|
|
||||||
int i, ima = 0;
|
int i, ima = 0;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
int section_count;
|
int section_count;
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
if ( !check_extensions(streamFile,"bcstm") )
|
||||||
if (strcasecmp("bcstm", filename_extension(filename)))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4353544D) /* "CSTM" */
|
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4353544D) /* "CSTM" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if ((uint16_t)read_16bitLE(4, streamFile) != 0xFEFF)
|
if ((uint16_t)read_16bitLE(4, streamFile) != 0xFEFF)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -57,11 +54,12 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info_offset == 0) goto fail;
|
||||||
|
if ((uint32_t)read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* check type details */
|
/* check type details */
|
||||||
if (info_offset == 0) goto fail;
|
|
||||||
codec_number = read_8bit(info_offset + 0x20, streamFile);
|
codec_number = read_8bit(info_offset + 0x20, streamFile);
|
||||||
loop_flag = read_8bit(info_offset + 0x21, streamFile);
|
loop_flag = read_8bit(info_offset + 0x21, streamFile);
|
||||||
channel_count = read_8bit(info_offset + 0x22, streamFile);
|
channel_count = read_8bit(info_offset + 0x22, streamFile);
|
||||||
|
@ -89,13 +87,12 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
||||||
if (channel_count < 1) goto fail;
|
if (channel_count < 1) goto fail;
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
/* fill in the vital statistics */
|
||||||
vgmstream->num_samples = read_32bitLE(info_offset + 0x2c, streamFile);
|
vgmstream->num_samples = read_32bitLE(info_offset + 0x2c, streamFile);
|
||||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(info_offset + 0x24, streamFile);
|
vgmstream->sample_rate = read_32bitLE(info_offset + 0x24, streamFile);
|
||||||
/* channels and loop flag are set by allocate_vgmstream */
|
/* channels and loop flag are set by allocate_vgmstream */
|
||||||
if (ima) //Shift the loop points back slightly to avoid stupid pops in some IMA streams due to DC offsetting
|
if (ima) //Shift the loop points back slightly to avoid stupid pops in some IMA streams due to DC offsetting
|
||||||
{
|
{
|
||||||
|
@ -166,34 +163,14 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE *streamFile) {
|
||||||
start_offset = data_offset + 0x20;
|
start_offset = data_offset + 0x20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
/* open the file for reading by each channel */
|
||||||
{
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
int i;
|
goto fail;
|
||||||
for (i = 0; i<channel_count; i++) {
|
|
||||||
if (vgmstream->layout_type == layout_interleave_shortblock)
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
vgmstream->interleave_block_size);
|
|
||||||
else if (vgmstream->layout_type == layout_interleave)
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
||||||
else
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
0x1000);
|
|
||||||
|
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
return vgmstream;
|
||||||
|
|
||||||
vgmstream->ch[i].channel_start_offset =
|
|
||||||
vgmstream->ch[i].offset =
|
|
||||||
start_offset + i*vgmstream->interleave_block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vgmstream;
|
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,17 @@
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
#include "../stack_alloc.h"
|
#include "../stack_alloc.h"
|
||||||
|
|
||||||
|
/* BFSTM - Nintendo Wii U format */
|
||||||
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
|
|
||||||
coding_t coding_type;
|
coding_t coding_type;
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
|
||||||
off_t info_offset = 0, seek_offset = 0, data_offset = 0;
|
off_t info_offset = 0, seek_offset = 0, data_offset = 0;
|
||||||
uint16_t temp_id;
|
uint16_t temp_id;
|
||||||
int codec_number;
|
int codec_number;
|
||||||
int channel_count;
|
int channel_count, loop_flag;
|
||||||
int loop_flag;
|
|
||||||
int i, j;
|
int i, j;
|
||||||
int ima = 0;
|
int ima = 0;
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
@ -20,47 +20,52 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
int section_count;
|
int section_count;
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile, filename, sizeof(filename));
|
if ( !check_extensions(streamFile,"bfstm") )
|
||||||
if (strcasecmp("bfstm", filename_extension(filename)))
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4653544D) /* "FSTM" */
|
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4653544D) /* "FSTM" */
|
||||||
goto fail;
|
goto fail;
|
||||||
if ((uint16_t)read_16bitBE(4, streamFile) != 0xFEFF)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
section_count = read_16bitBE(0x10, streamFile);
|
if ((uint16_t)read_16bitBE(4, streamFile) == 0xFEFF) { /* endian marker (BE most common) */
|
||||||
|
read_32bit = read_32bitBE;
|
||||||
|
read_16bit = read_16bitBE;
|
||||||
|
} else if ((uint16_t)read_16bitBE(4, streamFile) == 0xFFFE) { /* Blaster Master Zero 3DS */
|
||||||
|
read_32bit = read_32bitLE;
|
||||||
|
read_16bit = read_16bitLE;
|
||||||
|
} else {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
section_count = read_16bit(0x10, streamFile);
|
||||||
for (i = 0; i < section_count; i++) {
|
for (i = 0; i < section_count; i++) {
|
||||||
temp_id = read_16bitBE(0x14 + i * 0xc, streamFile);
|
temp_id = read_16bit(0x14 + i * 0xc, streamFile);
|
||||||
switch(temp_id) {
|
switch(temp_id) {
|
||||||
case 0x4000:
|
case 0x4000:
|
||||||
info_offset = read_32bitBE(0x18 + i * 0xc, streamFile);
|
info_offset = read_32bit(0x18 + i * 0xc, streamFile);
|
||||||
/* size_t info_size = read_32bitBE(0x1c + i * 0xc, streamFile); */
|
/* size_t info_size = read_32bit(0x1c + i * 0xc, streamFile); */
|
||||||
break;
|
break;
|
||||||
case 0x4001:
|
case 0x4001:
|
||||||
seek_offset = read_32bitBE(0x18 + i * 0xc, streamFile);
|
seek_offset = read_32bit(0x18 + i * 0xc, streamFile);
|
||||||
/* size_t seek_size = read_32bitBE(0x1c + i * 0xc, streamFile); */
|
/* size_t seek_size = read_32bit(0x1c + i * 0xc, streamFile); */
|
||||||
break;
|
break;
|
||||||
case 0x4002:
|
case 0x4002:
|
||||||
data_offset = read_32bitBE(0x18 + i * 0xc, streamFile);
|
data_offset = read_32bit(0x18 + i * 0xc, streamFile);
|
||||||
/* size_t data_size = read_32bitBE(0x1c + i * 0xc, streamFile); */
|
/* size_t data_size = read_32bit(0x1c + i * 0xc, streamFile); */
|
||||||
break;
|
break;
|
||||||
case 0x4003:
|
case 0x4003:
|
||||||
/* off_t regn_offset = read_32bitBE(0x18 + i * 0xc, streamFile); */
|
/* off_t regn_offset = read_32bit(0x18 + i * 0xc, streamFile); */
|
||||||
/* size_t regn_size = read_32bitBE(0x1c + i * 0xc, streamFile); */
|
/* size_t regn_size = read_32bit(0x1c + i * 0xc, streamFile); */
|
||||||
break;
|
break;
|
||||||
case 0x4004:
|
case 0x4004:
|
||||||
/* off_t pdat_offset = read_32bitBE(0x18 + i * 0xc, streamFile); */
|
/* off_t pdat_offset = read_32bit(0x18 + i * 0xc, streamFile); */
|
||||||
/* size_t pdat_size = read_32bitBE(0x1c + i * 0xc, streamFile); */
|
/* size_t pdat_size = read_32bit(0x1c + i * 0xc, streamFile); */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (info_offset == 0) goto fail;
|
if (info_offset == 0) goto fail;
|
||||||
if ((uint32_t)read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
|
if ((uint32_t)read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
@ -88,17 +93,16 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
if (channel_count < 1) goto fail;
|
if (channel_count < 1) goto fail;
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
|
|
||||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
/* fill in the vital statistics */
|
||||||
vgmstream->num_samples = read_32bitBE(info_offset + 0x2c, streamFile);
|
vgmstream->num_samples = read_32bit(info_offset + 0x2c, streamFile);
|
||||||
vgmstream->sample_rate = (uint16_t)read_16bitBE(info_offset + 0x26, streamFile);
|
vgmstream->sample_rate = read_32bit(info_offset + 0x24, streamFile);
|
||||||
/* channels and loop flag are set by allocate_vgmstream */
|
/* channels and loop flag are set by allocate_vgmstream */
|
||||||
if (ima) //Shift the loop points back slightly to avoid stupid pops in some IMA streams due to DC offsetting
|
if (ima) //Shift the loop points back slightly to avoid stupid pops in some IMA streams due to DC offsetting
|
||||||
{
|
{
|
||||||
vgmstream->loop_start_sample = read_32bitBE(info_offset + 0x28, streamFile);
|
vgmstream->loop_start_sample = read_32bit(info_offset + 0x28, streamFile);
|
||||||
if (vgmstream->loop_start_sample > 10000)
|
if (vgmstream->loop_start_sample > 10000)
|
||||||
{
|
{
|
||||||
vgmstream->loop_start_sample -= 5000;
|
vgmstream->loop_start_sample -= 5000;
|
||||||
|
@ -109,7 +113,7 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vgmstream->loop_start_sample = read_32bitBE(info_offset + 0x28, streamFile);
|
vgmstream->loop_start_sample = read_32bit(info_offset + 0x28, streamFile);
|
||||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,25 +132,25 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
if (ima)
|
if (ima)
|
||||||
vgmstream->interleave_block_size = 0x200;
|
vgmstream->interleave_block_size = 0x200;
|
||||||
else {
|
else {
|
||||||
vgmstream->interleave_block_size = read_32bitBE(info_offset + 0x34, streamFile);
|
vgmstream->interleave_block_size = read_32bit(info_offset + 0x34, streamFile);
|
||||||
vgmstream->interleave_smallblock_size = read_32bitBE(info_offset + 0x44, streamFile);
|
vgmstream->interleave_smallblock_size = read_32bit(info_offset + 0x44, streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vgmstream->coding_type == coding_NGC_DSP) {
|
if (vgmstream->coding_type == coding_NGC_DSP) {
|
||||||
off_t coeff_ptr_table;
|
off_t coeff_ptr_table;
|
||||||
VARDECL(off_t, coef_offset);
|
VARDECL(off_t, coef_offset);
|
||||||
ALLOC(coef_offset, channel_count, off_t);
|
ALLOC(coef_offset, channel_count, off_t);
|
||||||
coeff_ptr_table = read_32bitBE(info_offset + 0x1c, streamFile) + info_offset + 8; // Getting pointer for coefficient pointer table
|
coeff_ptr_table = read_32bit(info_offset + 0x1c, streamFile) + info_offset + 8; // Getting pointer for coefficient pointer table
|
||||||
|
|
||||||
for (i = 0; i < channel_count; i++) {
|
for (i = 0; i < channel_count; i++) {
|
||||||
tempoffset1 = read_32bitBE(coeff_ptr_table + 8 + i * 8, streamFile);
|
tempoffset1 = read_32bit(coeff_ptr_table + 8 + i * 8, streamFile);
|
||||||
coef_offset[i] = tempoffset1 + coeff_ptr_table;
|
coef_offset[i] = tempoffset1 + coeff_ptr_table;
|
||||||
coef_offset[i] += read_32bitBE(coef_offset[i] + 4, streamFile);
|
coef_offset[i] += read_32bit(coef_offset[i] + 4, streamFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j<vgmstream->channels; j++) {
|
for (j = 0; j<vgmstream->channels; j++) {
|
||||||
for (i = 0; i<16; i++) {
|
for (i = 0; i<16; i++) {
|
||||||
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_offset[j] + i * 2, streamFile);
|
vgmstream->ch[j].adpcm_coef[i] = read_16bit(coef_offset[j] + i * 2, streamFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,33 +164,13 @@ VGMSTREAM * init_vgmstream_bfstm(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* open the file for reading by each channel */
|
/* open the file for reading by each channel */
|
||||||
{
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
int i;
|
goto fail;
|
||||||
for (i = 0; i<channel_count; i++) {
|
|
||||||
if (vgmstream->layout_type == layout_interleave_shortblock)
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
vgmstream->interleave_block_size);
|
|
||||||
else if (vgmstream->layout_type == layout_interleave)
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
||||||
else
|
|
||||||
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
|
|
||||||
0x1000);
|
|
||||||
|
|
||||||
if (!vgmstream->ch[i].streamfile) goto fail;
|
|
||||||
|
|
||||||
vgmstream->ch[i].channel_start_offset =
|
|
||||||
vgmstream->ch[i].offset =
|
|
||||||
start_offset + i*vgmstream->interleave_block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,34 +279,26 @@ VGMSTREAM * init_vgmstream_fsb_offset(STREAMFILE *streamFile, off_t offset) {
|
||||||
#if defined(VGM_USE_MPEG)
|
#if defined(VGM_USE_MPEG)
|
||||||
mpeg_codec_data *mpeg_data = NULL;
|
mpeg_codec_data *mpeg_data = NULL;
|
||||||
coding_t mpeg_coding_type;
|
coding_t mpeg_coding_type;
|
||||||
|
|
||||||
#if 0
|
|
||||||
int fsb_padding = 0;
|
int fsb_padding = 0;
|
||||||
|
|
||||||
|
//VGM_ASSERT(fsbh.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n");/* not always set anyway */
|
||||||
|
VGM_ASSERT(fsbh.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n");
|
||||||
|
|
||||||
if (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED)
|
if (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED)
|
||||||
fsb_padding = fsbh.numchannels > 2 ? 16 : 2;
|
fsb_padding = fsbh.numchannels > 2 ? 16 : 2;
|
||||||
else if (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4)
|
else if (fsbh.flags & FMOD_FSB_SOURCE_MPEG_PADDED4)
|
||||||
fsb_padding = fsbh.numchannels > 2 ? 16 : 4;
|
fsb_padding = fsbh.numchannels > 2 ? 16 : 4;
|
||||||
else /* seems to be needed with no flag */
|
else /* needed by multichannel with no flags */
|
||||||
fsb_padding = fsbh.numchannels > 2 ? 16 : 0;
|
fsb_padding = fsbh.numchannels > 2 ? 16 : 0;
|
||||||
|
|
||||||
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
||||||
if (!mpeg_data) goto fail;
|
if (!mpeg_data) goto fail;
|
||||||
|
|
||||||
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
|
||||||
if (vgmstream->channels > 2) vgmstream->loop_flag = 0;//todo not implemented yet
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VGM_ASSERT(fsbh.mode & FSOUND_MPEG_LAYER2, "FSB FSOUND_MPEG_LAYER2 found\n");
|
|
||||||
VGM_ASSERT(fsbh.mode & FSOUND_IGNORETAGS, "FSB FSOUND_IGNORETAGS found\n");
|
|
||||||
|
|
||||||
mpeg_data = init_mpeg_codec_data(streamFile, start_offset, &mpeg_coding_type, vgmstream->channels);
|
|
||||||
if (!mpeg_data) goto fail;
|
|
||||||
|
|
||||||
vgmstream->codec_data = mpeg_data;
|
vgmstream->codec_data = mpeg_data;
|
||||||
vgmstream->coding_type = mpeg_coding_type;
|
vgmstream->coding_type = mpeg_coding_type;
|
||||||
vgmstream->layout_type = layout_mpeg;
|
vgmstream->layout_type = layout_mpeg;
|
||||||
|
|
||||||
mpeg_set_error_logging(mpeg_data, 0);
|
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
||||||
|
//mpeg_set_error_logging(mpeg_data, 0); /* should not be needed anymore with the interleave decoder */
|
||||||
|
|
||||||
#elif defined(VGM_USE_FFMPEG)
|
#elif defined(VGM_USE_FFMPEG)
|
||||||
/* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset */
|
/* FFmpeg can't properly read FSB4 or FMOD's 0-padded MPEG data @ start_offset */
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
#include "../coding/coding.h"
|
#include "../coding/coding.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
|
||||||
/* FSB5 header */
|
/* FSB5 - FMOD Studio multiplatform format */
|
||||||
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
off_t StartOffset = 0;
|
off_t StartOffset = 0;
|
||||||
off_t SampleHeaderStart = 0, DSPInfoStart = 0;
|
off_t SampleHeaderStart = 0, DSPInfoStart = 0;
|
||||||
size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength;
|
size_t SampleHeaderLength, NameTableLength, SampleDataLength, BaseHeaderLength, StreamSize = 0;
|
||||||
|
|
||||||
uint32_t BaseSamples = 0, LoopStart = 0, LoopEnd = 0, NumSamples = 0;
|
uint32_t BaseSamples = 0, LoopStart = 0, LoopEnd = 0, NumSamples = 0;
|
||||||
int LoopFlag = 0, ChannelCount = 0, SampleRate = 0, CodingID;
|
int LoopFlag = 0, ChannelCount = 0, SampleRate = 0, CodingID;
|
||||||
|
@ -20,7 +20,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x46534235) goto fail; /* "FSB5" */
|
if (read_32bitBE(0x00,streamFile) != 0x46534235) goto fail; /* "FSB5" */
|
||||||
|
|
||||||
//v0 has extra flags at 0x1c and SampleHeaderStart = 0x40?
|
//v0 has extra flags at 0x1c and BaseHeaderLength = 0x40?
|
||||||
if (read_32bitLE(0x04,streamFile) != 0x01) goto fail; /* Version ID */
|
if (read_32bitLE(0x04,streamFile) != 0x01) goto fail; /* Version ID */
|
||||||
|
|
||||||
TotalStreams = read_32bitLE(0x08,streamFile);
|
TotalStreams = read_32bitLE(0x08,streamFile);
|
||||||
|
@ -35,11 +35,11 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
if ((SampleHeaderLength + NameTableLength + SampleDataLength + 0x3C) != get_streamfile_size(streamFile)) goto fail;
|
if ((SampleHeaderLength + NameTableLength + SampleDataLength + 0x3C) != get_streamfile_size(streamFile)) goto fail;
|
||||||
if (TargetStream == 0) TargetStream = 1; /* default to 1 */
|
if (TargetStream == 0) TargetStream = 1; /* default to 1 */
|
||||||
if (TargetStream > TotalStreams || TotalStreams < 0) goto fail;
|
if (TargetStream > TotalStreams || TotalStreams <= 0) goto fail;
|
||||||
|
|
||||||
/* find target stream header and data offset and read all needed values for later use
|
/* find target stream header and data offset, and read all needed values for later use
|
||||||
* (reads one by one as the size of a single stream header is variable) */
|
* (reads one by one as the size of a single stream header is variable) */
|
||||||
for (i = 0; i < TotalStreams; i++) {
|
for (i = 1; i <= TotalStreams; i++) {
|
||||||
off_t DataStart = 0;
|
off_t DataStart = 0;
|
||||||
size_t StreamHeaderLength = 0;
|
size_t StreamHeaderLength = 0;
|
||||||
uint32_t SampleMode;
|
uint32_t SampleMode;
|
||||||
|
@ -48,8 +48,18 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
BaseSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile);
|
BaseSamples = read_32bitLE(SampleHeaderStart+0x04,streamFile);
|
||||||
StreamHeaderLength += 0x08;
|
StreamHeaderLength += 0x08;
|
||||||
|
|
||||||
/* get global offset */
|
/* get offset inside data section */
|
||||||
DataStart = (SampleMode >> 7) * 0x20;
|
DataStart = (SampleMode >> 7) * 0x20; /* bits 31..8 */
|
||||||
|
|
||||||
|
/* get channels (from tests seems correct, but multichannel isn't very common, ex. no 4ch mode?) */
|
||||||
|
switch ((SampleMode >> 5) & 0x03) { /* bits 7..6 */
|
||||||
|
case 0: ChannelCount = 1; break;
|
||||||
|
case 1: ChannelCount = 2; break;
|
||||||
|
case 2: ChannelCount = 6; break;/* some Dark Souls 2 MPEG; some IMA ADPCM */
|
||||||
|
case 3: ChannelCount = 8; break;/* some IMA ADPCM */
|
||||||
|
default: /* other values (ex. 10ch) are specified in the extra flags, using 0 here */
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* get sample rate */
|
/* get sample rate */
|
||||||
switch ((SampleMode >> 1) & 0x0f) { /* bits 5..1 */
|
switch ((SampleMode >> 1) & 0x0f) { /* bits 5..1 */
|
||||||
|
@ -64,19 +74,9 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
case 8: SampleRate = 44100; break;
|
case 8: SampleRate = 44100; break;
|
||||||
case 9: SampleRate = 48000; break;
|
case 9: SampleRate = 48000; break;
|
||||||
case 10: SampleRate = 96000; break; //???
|
case 10: SampleRate = 96000; break; //???
|
||||||
default:
|
default: /* probably specified in the extra flags */
|
||||||
SampleRate = 44100;
|
SampleRate = 44100;
|
||||||
break; /* probably specified in the extra flags */
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/* get channels (from tests seems correct, but multichannel isn't very common, ex. no 4ch mode?) */
|
|
||||||
switch ((SampleMode >> 5) & 0x03) { /* bits 7..6 */
|
|
||||||
case 0: ChannelCount = 1; break;
|
|
||||||
case 1: ChannelCount = 2; break;
|
|
||||||
case 2: ChannelCount = 6; break;/* some Dark Souls 2 MPEG; some IMA ADPCM */
|
|
||||||
case 3: ChannelCount = 8; break;/* some IMA ADPCM */
|
|
||||||
default: /* other values (ex. 10ch) seem specified in the extra flags */
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get extra flags */
|
/* get extra flags */
|
||||||
|
@ -102,14 +102,23 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
if (ExtraFlagSize > 0x04) /* probably no needed */
|
if (ExtraFlagSize > 0x04) /* probably no needed */
|
||||||
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
LoopEnd = read_32bitLE(ExtraFlagStart+0x08,streamFile);
|
||||||
|
|
||||||
/* when start is 0 seems the song reoeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
/* when start is 0 seems the song repeats with no real looping (ex. Sonic Boom Fire & Ice jingles) */
|
||||||
LoopFlag = (LoopStart != 0x00);
|
LoopFlag = (LoopStart != 0x00);
|
||||||
break;
|
break;
|
||||||
case 0x07: /* DSP Info (Coeffs), only used if coding is DSP??? */
|
case 0x04: /* free comment, or maybe SFX info */
|
||||||
|
break;
|
||||||
|
case 0x06: /* XMA seek table */
|
||||||
|
/* no need for it */
|
||||||
|
break;
|
||||||
|
case 0x07: /* DSP Info (Coeffs) */
|
||||||
DSPInfoStart = ExtraFlagStart + 0x04;
|
DSPInfoStart = ExtraFlagStart + 0x04;
|
||||||
break;
|
break;
|
||||||
|
case 0x0b: /* Vorbis data */
|
||||||
|
break;
|
||||||
|
case 0x0d: /* Unknown XMA value (size 4) */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
VGM_LOG("FSB5: unknown extra flag %i at 0x%04x\n", ExtraFlagType, ExtraFlagStart);
|
VGM_LOG("FSB5: unknown extra flag 0x%x at 0x%04x (size 0x%x)\n", ExtraFlagType, ExtraFlagStart, ExtraFlagSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,17 +128,26 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* stream found */
|
/* stream found */
|
||||||
if (i == TotalStreams-1) {
|
if (i == TargetStream) {
|
||||||
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
StartOffset = BaseHeaderLength + SampleHeaderLength + NameTableLength + DataStart;
|
||||||
|
|
||||||
|
/* get stream size from next stream or datasize if there is only one */
|
||||||
|
if (i == TotalStreams) {
|
||||||
|
StreamSize = SampleDataLength - DataStart;
|
||||||
|
} else {
|
||||||
|
uint32_t NextSampleMode = read_32bitLE(SampleHeaderStart+StreamHeaderLength+0x00,streamFile);
|
||||||
|
StreamSize = ((NextSampleMode >> 7) * 0x20) - DataStart;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* continue searching */
|
/* continue searching */
|
||||||
SampleHeaderStart += StreamHeaderLength;
|
SampleHeaderStart += StreamHeaderLength;
|
||||||
}
|
}
|
||||||
/* target stream not found*/
|
|
||||||
if (!StartOffset) goto fail;
|
|
||||||
|
|
||||||
|
/* target stream not found*/
|
||||||
|
if (!StartOffset || !StreamSize) goto fail;
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(ChannelCount,LoopFlag);
|
vgmstream = allocate_vgmstream(ChannelCount,LoopFlag);
|
||||||
|
@ -140,6 +158,7 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
vgmstream->sample_rate = SampleRate;
|
vgmstream->sample_rate = SampleRate;
|
||||||
vgmstream->num_streams = TotalStreams;
|
vgmstream->num_streams = TotalStreams;
|
||||||
vgmstream->meta_type = meta_FSB5;
|
vgmstream->meta_type = meta_FSB5;
|
||||||
|
NumSamples = BaseSamples / 4; /* not affected by channels */
|
||||||
|
|
||||||
switch (CodingID) {
|
switch (CodingID) {
|
||||||
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
case 0x00: /* FMOD_SOUND_FORMAT_NONE */
|
||||||
|
@ -149,7 +168,6 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 */
|
case 0x02: /* FMOD_SOUND_FORMAT_PCM16 */
|
||||||
NumSamples = BaseSamples / 4;
|
|
||||||
if (ChannelCount == 1) {
|
if (ChannelCount == 1) {
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
} else {
|
} else {
|
||||||
|
@ -171,10 +189,8 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
|
|
||||||
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM */
|
case 0x06: /* FMOD_SOUND_FORMAT_GCADPCM */
|
||||||
if (ChannelCount == 1) {
|
if (ChannelCount == 1) {
|
||||||
NumSamples = BaseSamples / 4;
|
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
} else {
|
} else {
|
||||||
NumSamples = BaseSamples / (2*ChannelCount);
|
|
||||||
vgmstream->layout_type = layout_interleave_byte;
|
vgmstream->layout_type = layout_interleave_byte;
|
||||||
vgmstream->interleave_block_size = 0x02;
|
vgmstream->interleave_block_size = 0x02;
|
||||||
}
|
}
|
||||||
|
@ -184,7 +200,6 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */
|
case 0x07: /* FMOD_SOUND_FORMAT_IMAADPCM */
|
||||||
NumSamples = BaseSamples / 4;
|
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->coding_type = coding_XBOX;
|
vgmstream->coding_type = coding_XBOX;
|
||||||
if (vgmstream->channels > 2) /* multichannel FSB IMA (interleaved header) */
|
if (vgmstream->channels > 2) /* multichannel FSB IMA (interleaved header) */
|
||||||
|
@ -197,37 +212,41 @@ VGMSTREAM * init_vgmstream_fsb5(STREAMFILE *streamFile) {
|
||||||
case 0x09: /* FMOD_SOUND_FORMAT_HEVAG */
|
case 0x09: /* FMOD_SOUND_FORMAT_HEVAG */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
case 0x0A: /* FMOD_SOUND_FORMAT_XMA */
|
#ifdef VGM_USE_FFMPEG
|
||||||
goto fail;
|
case 0x0A: {/* FMOD_SOUND_FORMAT_XMA */
|
||||||
|
uint8_t buf[100];
|
||||||
|
int bytes, block_size, block_count;
|
||||||
|
|
||||||
|
block_size = 0x10000; /* XACT default */
|
||||||
|
block_count = StreamSize / block_size + (StreamSize % block_size ? 1 : 0);
|
||||||
|
|
||||||
|
bytes = ffmpeg_make_riff_xma2(buf, 100, vgmstream->num_samples, StreamSize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||||
|
if (bytes <= 0) goto fail;
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, StartOffset,StreamSize);
|
||||||
|
if ( !vgmstream->codec_data ) goto fail;
|
||||||
|
vgmstream->coding_type = coding_FFmpeg;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef VGM_USE_MPEG
|
#ifdef VGM_USE_MPEG
|
||||||
case 0x0B: {/* FMOD_SOUND_FORMAT_MPEG */
|
case 0x0B: {/* FMOD_SOUND_FORMAT_MPEG */
|
||||||
mpeg_codec_data *mpeg_data = NULL;
|
mpeg_codec_data *mpeg_data = NULL;
|
||||||
coding_t mpeg_coding_type;
|
coding_t mpeg_coding_type;
|
||||||
|
int fsb_padding = 0;
|
||||||
|
|
||||||
NumSamples = BaseSamples / 2 / ChannelCount;
|
fsb_padding = vgmstream->channels > 2 ? 16 : 4; /* observed default */
|
||||||
|
|
||||||
#if 0
|
|
||||||
int fsb_padding = vgmstream->channels > 2 ? 16 : 0;//todo fix
|
|
||||||
|
|
||||||
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
mpeg_data = init_mpeg_codec_data_interleaved(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels, 0, fsb_padding);
|
||||||
if (!mpeg_data) goto fail;
|
if (!mpeg_data) goto fail;
|
||||||
|
|
||||||
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
|
||||||
if (vgmstream->channels > 2) vgmstream->loop_flag = 0;//todo not implemented yet
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (vgmstream->channels > 2)
|
|
||||||
goto fail; /* no multichannel for now */
|
|
||||||
|
|
||||||
mpeg_data = init_mpeg_codec_data(streamFile, StartOffset, &mpeg_coding_type, vgmstream->channels);
|
|
||||||
if (!mpeg_data) goto fail;
|
|
||||||
|
|
||||||
vgmstream->codec_data = mpeg_data;
|
vgmstream->codec_data = mpeg_data;
|
||||||
vgmstream->coding_type = mpeg_coding_type;
|
vgmstream->coding_type = mpeg_coding_type;
|
||||||
vgmstream->layout_type = layout_mpeg;
|
vgmstream->layout_type = layout_mpeg;
|
||||||
|
|
||||||
mpeg_set_error_logging(mpeg_data, 0);
|
vgmstream->interleave_block_size = mpeg_data->current_frame_size + mpeg_data->current_padding;
|
||||||
|
//mpeg_set_error_logging(mpeg_data, 0); /* should not be needed anymore with the interleave decoder */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -785,6 +785,8 @@ typedef struct {
|
||||||
int channels_per_frame;
|
int channels_per_frame;
|
||||||
size_t samples_per_frame;
|
size_t samples_per_frame;
|
||||||
|
|
||||||
|
size_t samples_to_discard; /* for interleaved looping */
|
||||||
|
|
||||||
/* interleaved MPEG internals */
|
/* interleaved MPEG internals */
|
||||||
int interleaved; /* flag */
|
int interleaved; /* flag */
|
||||||
mpg123_handle **ms; /* array of MPEG streams */
|
mpg123_handle **ms; /* array of MPEG streams */
|
||||||
|
@ -798,8 +800,7 @@ typedef struct {
|
||||||
|
|
||||||
/* messy stuff for padded FSB frames */
|
/* messy stuff for padded FSB frames */
|
||||||
size_t fixed_frame_size; /* when given a fixed size (XVAG) */
|
size_t fixed_frame_size; /* when given a fixed size (XVAG) */
|
||||||
size_t base_frame_size; /* without header padding byte */
|
size_t current_frame_size;
|
||||||
size_t current_frame_size; /* with padding byte applied if needed */
|
|
||||||
int fsb_padding; /* for FSBs that have extra garbage between frames */
|
int fsb_padding; /* for FSBs that have extra garbage between frames */
|
||||||
size_t current_padding; /* padding needed for current frame size */
|
size_t current_padding; /* padding needed for current frame size */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue