Merge pull request #203 from bnnm/segments-wave-misc

Segments, WAVE, misc
This commit is contained in:
Christopher Snowhill 2018-03-11 18:32:35 -07:00 committed by GitHub
commit 95d9a7f566
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1690 additions and 1338 deletions

View File

@ -139,7 +139,9 @@ void input_vgmstream::get_info(t_uint32 p_subsong, file_info & p_info, abort_cal
p_info.info_set_int("samplerate", samplerate);
p_info.info_set_int("channels", channels);
p_info.info_set_int("bitspersample",16);
p_info.info_set("encoding","lossless");
/* not quite accurate but some people are confused by this
* (could set lossless if PCM, but then again PCMFloat or PCM8 are converted/"lossy" in vgmstream) */
p_info.info_set("encoding","lossy");
p_info.info_set_bitrate(bitrate / 1000);
if (total_samples > 0)
p_info.info_set_int("stream_total_samples", total_samples);

View File

@ -51,6 +51,7 @@ void decode_at3plus(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing,
void reset_at3plus(VGMSTREAM *vgmstream) {
maiatrac3plus_codec_data *data = vgmstream->codec_data;
if (!data) return;
if (data->handle)
Atrac3plusDecoder_closeContext(data->handle);
@ -62,6 +63,8 @@ void seek_at3plus(VGMSTREAM *vgmstream, int32_t num_sample) {
int blocks_to_skip = num_sample / 2048;
int samples_to_discard = num_sample % 2048;
maiatrac3plus_codec_data *data = (maiatrac3plus_codec_data *)(vgmstream->codec_data);
if (!data) return;
vgmstream->loop_ch[0].offset =
vgmstream->loop_ch[0].channel_start_offset +
vgmstream->interleave_block_size * blocks_to_skip;

View File

@ -152,6 +152,7 @@ decode_fail:
void reset_atrac9(VGMSTREAM *vgmstream) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;
if (!data->handle)
goto fail;
@ -184,6 +185,7 @@ fail:
void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
atrac9_codec_data *data = vgmstream->codec_data;
if (!data) return;
reset_atrac9(vgmstream);
@ -196,8 +198,7 @@ void seek_atrac9(VGMSTREAM *vgmstream, int32_t num_sample) {
}
void free_atrac9(atrac9_codec_data *data) {
if (!data)
return;
if (!data) return;
if (data->handle) Atrac9ReleaseHandle(data->handle);
free(data->data_buffer);

View File

@ -534,6 +534,8 @@ static void flush_ea_mt_internal(VGMSTREAM *vgmstream, int is_start) {
int i;
size_t bytes;
if (!data) return;
/* the decoder needs to be notified when offsets change */
for (i = 0; i < vgmstream->channels; i++) {
UTKContext *ctx = data->utk_context[i];

View File

@ -1,5 +1,5 @@
#include "coding.h"
#include "../util.h"
/* FADPCM table */
static const int8_t fadpcm_coefs[8][2] = {
@ -20,7 +20,7 @@ void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
off_t frame_offset;
int i, j, k;
int block_samples, num_frame, samples_done = 0, sample_count = 0;
int coef_index[8], shift_factor[8];
uint32_t coefs, shifts;
int32_t hist1; //= stream->adpcm_history1_32;
int32_t hist2; //= stream->adpcm_history2_32;
@ -32,29 +32,25 @@ void decode_fadpcm(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacin
frame_offset = stream->offset + 0x8c*num_frame;
/* parse 0xc header */
{
uint32_t coefs, shifts;
coefs = read_32bitLE(frame_offset + 0x00, stream->streamfile);
shifts = read_32bitLE(frame_offset + 0x04, stream->streamfile);
hist1 = read_16bitLE(frame_offset + 0x08, stream->streamfile);
hist2 = read_16bitLE(frame_offset + 0x0a, stream->streamfile);
for (i = 0; i < 8; i++) {
coef_index[i] = (coefs >> i*4) & 0x0f;
shift_factor[i] = (shifts >> i*4) & 0x0f;
}
/* header samples are not written to outbuf */
}
/* parse 0xc header (header samples are not written to outbuf) */
coefs = read_32bitLE(frame_offset + 0x00, stream->streamfile);
shifts = read_32bitLE(frame_offset + 0x04, stream->streamfile);
hist1 = read_16bitLE(frame_offset + 0x08, stream->streamfile);
hist2 = read_16bitLE(frame_offset + 0x0a, stream->streamfile);
/* decode nibbles, grouped in 0x10 * 0x04 * 2 */
/* decode nibbles, grouped in 8 sets of 0x10 * 0x04 * 2 */
for (i = 0; i < 8; i++) {
int32_t coef1, coef2, shift, coef_index, shift_factor;
off_t group_offset = frame_offset + 0x0c + 0x10*i;
int32_t coef1 = fadpcm_coefs[(coef_index[i] % 0x07)][0]; /* indexes > 7 are repeats (ex. 0x9 is 0x2) */
int32_t coef2 = fadpcm_coefs[(coef_index[i] % 0x07)][1];
int32_t shift = 0x16 - shift_factor[i];
/* each set has its own coefs/shifts (indexes > 7 are repeat, ex. 0x9 is 0x2) */
coef_index = ((coefs >> i*4) & 0x0f) % 0x07;
shift_factor = (shifts >> i*4) & 0x0f;
coef1 = fadpcm_coefs[coef_index][0];
coef2 = fadpcm_coefs[coef_index][1];
shift = 0x16 - shift_factor;
for (j = 0; j < 4; j++) {
uint32_t nibbles = read_32bitLE(group_offset + 0x04*j, stream->streamfile);

View File

@ -706,6 +706,7 @@ end:
void reset_ffmpeg(VGMSTREAM *vgmstream) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
if (!data) return;
if (data->formatCtx) {
avformat_seek_file(data->formatCtx, data->streamIndex, 0, 0, 0, AVSEEK_FLAG_ANY);
@ -733,6 +734,7 @@ void reset_ffmpeg(VGMSTREAM *vgmstream) {
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
ffmpeg_codec_data *data = (ffmpeg_codec_data *) vgmstream->codec_data;
int64_t ts;
if (!data) return;
/* Start from 0 and discard samples until loop_start (slower but not too noticeable).
* Due to various FFmpeg quirks seeking to a sample is erratic in many formats (would need extra steps). */

View File

@ -53,6 +53,7 @@ void decode_g719(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, int
void reset_g719(VGMSTREAM *vgmstream) {
g719_codec_data *data = vgmstream->codec_data;
int i;
if (!data) return;
for (i = 0; i < vgmstream->channels; i++)
{

View File

@ -52,6 +52,7 @@ void decode_g7221(VGMSTREAM * vgmstream, sample * outbuf, int channelspacing, in
void reset_g7221(VGMSTREAM *vgmstream) {
g7221_codec_data *data = vgmstream->codec_data;
int i;
if (!data) return;
for (i = 0; i < vgmstream->channels; i++)
{

View File

@ -2,7 +2,6 @@
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) {
int samples_done = 0;
int32_t samples_remain = clHCA_samplesPerBlock - data->sample_ptr;
void *hca_data = NULL;
@ -84,7 +83,8 @@ void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, i
void reset_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = vgmstream->codec_data;
/*clHCA *hca = (clHCA *)(data + 1);*/
if (!data) return;
data->curblock = 0;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;
@ -92,6 +92,8 @@ void reset_hca(VGMSTREAM *vgmstream) {
void loop_hca(VGMSTREAM *vgmstream) {
hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data);
if (!data) return;
data->curblock = data->info.loopStart;
data->sample_ptr = clHCA_samplesPerBlock;
data->samples_discard = 0;

View File

@ -86,6 +86,8 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
void reset_mp4_aac(VGMSTREAM *vgmstream) {
mp4_aac_codec_data *data = vgmstream->codec_data;
if (!data) return;
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = 0;
@ -93,6 +95,8 @@ void reset_mp4_aac(VGMSTREAM *vgmstream) {
void seek_mp4_aac(VGMSTREAM *vgmstream, int32_t num_sample) {
mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data);
if (!data) return;
data->sampleId = 0;
data->sample_ptr = data->samples_per_frame;
data->samples_discard = num_sample;

View File

@ -500,6 +500,7 @@ void free_mpeg(mpeg_codec_data *data) {
void reset_mpeg(VGMSTREAM *vgmstream) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
if (!data) return;
/* reset multistream */ //todo check if stream offsets are properly reset
@ -524,6 +525,7 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
off_t input_offset;
mpeg_codec_data *data = vgmstream->codec_data;
if (!data) return;
/* seek multistream */
if (!data->custom) {

View File

@ -22,15 +22,21 @@ void decode_ogg_vorbis(ogg_vorbis_codec_data * data, sample * outbuf, int32_t sa
void reset_ogg_vorbis(VGMSTREAM *vgmstream) {
OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = vgmstream->codec_data;
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
if (!data) return;
ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek(ogg_vorbis_file, 0);
}
void seek_ogg_vorbis(VGMSTREAM *vgmstream, int32_t num_sample) {
OggVorbis_File *ogg_vorbis_file;
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *)(vgmstream->codec_data);
OggVorbis_File *ogg_vorbis_file = &(data->ogg_vorbis_file);
if (!data) return;
ogg_vorbis_file = &(data->ogg_vorbis_file);
ov_pcm_seek_lap(ogg_vorbis_file, num_sample);
}

View File

@ -207,6 +207,7 @@ void free_vorbis_custom(vorbis_custom_codec_data * data) {
void reset_vorbis_custom(VGMSTREAM *vgmstream) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */
@ -216,6 +217,7 @@ void reset_vorbis_custom(VGMSTREAM *vgmstream) {
void seek_vorbis_custom(VGMSTREAM *vgmstream, int32_t num_sample) {
vorbis_custom_codec_data *data = vgmstream->codec_data;
if (!data) return;
/* Seeking is provided by the Ogg layer, so with custom vorbis we'd need seek tables instead.
* To avoid having to parse different formats we'll just discard until the expected sample */

View File

@ -88,7 +88,7 @@ static const char* extension_list[] = {
"cbd2",
"ccc",
"cd",
"cfn",
"cfn", //fake extension/header id for .caf (to be removed)
"ckd",
"cnk",
"cps",
@ -245,6 +245,7 @@ static const char* extension_list[] = {
"raw",
"rkv",
"rnd",
"rof",
"rrds",
"rsd",
"rsf",
@ -358,6 +359,7 @@ static const char* extension_list[] = {
"wam",
"was",
//"wav", //common
"wave",
"wavm",
"wb",
"wem",
@ -500,7 +502,7 @@ static const coding_info coding_info_list[] = {
{coding_MTAF, "Konami MTAF 4-bit ADPCM"},
{coding_MTA2, "Konami MTA2 4-bit ADPCM"},
{coding_MC3, "Paradigm MC3 3-bit ADPCM"},
{coding_FADPCM, "FMOD FADPCM 4-bit ADCPM"},
{coding_FADPCM, "FMOD FADPCM 4-bit ADPCM"},
{coding_SDX2, "Squareroot-delta-exact (SDX2) 8-bit DPCM"},
{coding_SDX2_int, "Squareroot-delta-exact (SDX2) 8-bit DPCM with 1 byte interleave"},
@ -519,7 +521,7 @@ static const coding_info coding_info_list[] = {
{coding_CRI_HCA, "CRI HCA"},
#ifdef VGM_USE_VORBIS
{coding_ogg_vorbis, "Ogg Vorbis"},
{coding_OGG_VORBIS, "Ogg Vorbis"},
{coding_VORBIS_custom, "Custom Vorbis"},
#endif
#ifdef VGM_USE_MPEG
@ -557,7 +559,7 @@ static const layout_info layout_info_list[] = {
{layout_xa_blocked, "CD-ROM XA"},
{layout_blocked_ea_schl, "blocked (EA SCHl)"},
{layout_blocked_ea_1snh, "blocked (EA 1SNh)"},
{layout_caf_blocked, "CAF blocked"},
{layout_blocked_caf, "blocked (CAF)"},
{layout_wsi_blocked, ".wsi blocked"},
{layout_xvas_blocked, ".xvas blocked"},
{layout_str_snds_blocked, ".str SNDS blocked"},
@ -582,7 +584,7 @@ static const layout_info layout_info_list[] = {
{layout_acm, "ACM blocked"},
{layout_mus_acm, "multiple ACM files, ACM blocked"},
{layout_aix, "AIX interleave, internally 18-byte interleaved"},
{layout_aax, "AAX blocked, 18-byte interleaved"},
{layout_segmented, "segmented"},
{layout_scd_int, "SCD multistream interleave"},
{layout_blocked_ea_sns, "blocked (EA SNS)"},
{layout_blocked_awc, "blocked (AWC)"},
@ -651,7 +653,7 @@ static const meta_info meta_info_list[] = {
{meta_DSP_STR, "assumed Conan Gamecube STR File by .str extension"},
{meta_EA_SCHL, "Electronic Arts SCHl header (variable)"},
{meta_EA_SCHL_fixed, "Electronic Arts SCHl header (fixed)"},
{meta_CFN, "tri-Crescendo CAF Header"},
{meta_CAF, "tri-Crescendo CAF Header"},
{meta_PS2_VPK, "VPK Header"},
{meta_GENH, "GENH Generic Header"},
{meta_DSP_SADB, "Procyon Studio SADB header"},
@ -749,6 +751,7 @@ static const meta_info meta_info_list[] = {
{meta_RSD6WADP, "RSD6/WADP Header"},
{meta_RSD6RADP, "RSD6/RADP Header"},
{meta_RSD6XMA, "RSD6/XMA Header"},
{meta_RSD6AT3P, "RSD6/AT3+ Header"},
{meta_DC_ASD, "ASD Header"},
{meta_NAOMI_SPSD, "SPSD Header"},
{meta_FFXI_BGW, "BGW BGMStream header"},
@ -965,6 +968,8 @@ static const meta_info meta_info_list[] = {
{meta_SQEX_MAB, "Square-Enix MAB header"},
{meta_OGG_L2SD, "Ogg Vorbis (L2SD)"},
{meta_WAF, "KID WAF header"},
{meta_WAVE, "WayForward .WAVE header"},
{meta_WAVE_segmented, "WayForward .WAVE header (segmented)"},
#ifdef VGM_USE_MP4V2
{meta_MP4, "AAC header"},

View File

@ -1,67 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../coding/coding.h"
void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
aax_codec_data *data = vgmstream->codec_data;
while (samples_written<sample_count) {
int samples_to_do;
int samples_this_block = data->sample_counts[data->current_segment];
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
int i;
data->current_segment = data->loop_segment;
reset_vgmstream(data->adxs[data->current_segment]);
/* carry over the history from the loop point */
if (data->loop_segment > 0)
{
for (i=0;i<data->adxs[0]->channels;i++)
{
data->adxs[data->loop_segment]->ch[i].adpcm_history1_32 =
data->adxs[data->loop_segment-1]->ch[i].adpcm_history1_32;
data->adxs[data->loop_segment]->ch[i].adpcm_history2_32 =
data->adxs[data->loop_segment-1]->ch[i].adpcm_history2_32;
}
}
vgmstream->samples_into_block = 0;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
/*printf("samples_to_do=%d,samples_this_block=%d,samples_written=%d,sample_count=%d\n",samples_to_do,samples_this_block,samples_written,sample_count);*/
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
if (samples_to_do == 0)
{
int i;
data->current_segment++;
/*printf("advance to %d at %d samples\n",data->current_segment,vgmstream->current_sample);*/
reset_vgmstream(data->adxs[data->current_segment]);
/* carry over the history from the previous segment */
for (i=0;i<data->adxs[0]->channels;i++)
{
data->adxs[data->current_segment]->ch[i].adpcm_history1_32 =
data->adxs[data->current_segment-1]->ch[i].adpcm_history1_32;
data->adxs[data->current_segment]->ch[i].adpcm_history2_32 =
data->adxs[data->current_segment-1]->ch[i].adpcm_history2_32;
}
vgmstream->samples_into_block = 0;
continue;
}
render_vgmstream(&buffer[samples_written*data->adxs[data->current_segment]->channels],
samples_to_do,data->adxs[data->current_segment]);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
}
}

View File

@ -86,8 +86,8 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
case layout_blocked_ea_1snh:
block_update_ea_1snh(vgmstream->next_block_offset,vgmstream);
break;
case layout_caf_blocked:
caf_block_update(vgmstream->next_block_offset,vgmstream);
case layout_blocked_caf:
block_update_caf(vgmstream->next_block_offset,vgmstream);
break;
case layout_wsi_blocked:
wsi_block_update(vgmstream->next_block_offset,vgmstream);

View File

@ -25,7 +25,6 @@ void block_update_adm(off_t block_offset, VGMSTREAM * vgmstream) {
/* check if unused line (all blocks should only use flags 0x06/0x03/0x02) */
if (read_32bitLE(next_block_offset, streamFile) == 0x00000000) {
interleave_data -= 0x10;
next_block_offset -= 0x10;
}
else {
break;

21
src/layout/blocked_caf.c Normal file
View File

@ -0,0 +1,21 @@
#include "layout.h"
#include "../vgmstream.h"
/* each block is a new CAF header */
void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream) {
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
int i,ch;
vgmstream->current_block_offset = block_offset;
vgmstream->next_block_offset = block_offset + read_32bitBE(block_offset+0x04, streamFile);
vgmstream->current_block_size = read_32bitBE(block_offset+0x14, streamFile);
for (ch = 0; ch < vgmstream->channels; ch++) {
vgmstream->ch[ch].offset = block_offset + read_32bitBE(block_offset+0x10+(0x08*ch), streamFile);
/* re-read coeffs (though blocks seem to repeat them) */
for (i = 0; i < 16; i++) {
vgmstream->ch[ch].adpcm_coef[i] = read_16bitBE(block_offset+0x34 + 0x2c*ch + 0x02*i, streamFile);
}
}
}

View File

@ -1,26 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
/* set up for the block at the given offset */
void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
int i;
vgmstream->current_block_offset = block_offset;
vgmstream->current_block_size = read_32bitBE(
vgmstream->current_block_offset+0x14,
vgmstream->ch[0].streamfile);
vgmstream->next_block_offset = vgmstream->current_block_offset +
(off_t)read_32bitBE(vgmstream->current_block_offset+0x04,
vgmstream->ch[0].streamfile);
for (i=0;i<vgmstream->channels;i++) {
vgmstream->ch[i].offset = vgmstream->current_block_offset +
read_32bitBE(block_offset+0x10+(8*i),vgmstream->ch[0].streamfile);
}
/* coeffs */
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(block_offset+0x34+(2*i),vgmstream->ch[0].streamfile);
vgmstream->ch[1].adpcm_coef[i] = read_16bitBE(block_offset+0x60+(2*i),vgmstream->ch[0].streamfile);
}
}

View File

@ -17,8 +17,7 @@ void xa_block_update(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_schl(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_ea_1snh(off_t block_offset, VGMSTREAM * vgmstream);
void caf_block_update(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_caf(off_t block_offset, VGMSTREAM * vgmstream);
void wsi_block_update(off_t block_offset, VGMSTREAM * vgmstream);
@ -73,7 +72,11 @@ void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM *
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_aax(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
segmented_layout_data* init_layout_segmented(int segment_count);
int setup_layout_segmented(segmented_layout_data* data);
void free_layout_segmented(segmented_layout_data *data);
void reset_layout_segmented(segmented_layout_data *data);
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

140
src/layout/segmented.c Normal file
View File

@ -0,0 +1,140 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../coding/coding.h"
segmented_layout_data* init_layout_segmented(int segment_count) {
segmented_layout_data *data = NULL;
if (segment_count <= 0 || segment_count > 255)
goto fail;
data = calloc(1, sizeof(segmented_layout_data));
if (!data) goto fail;
data->segment_count = segment_count;
data->current_segment = 0;
data->segments = calloc(segment_count, sizeof(VGMSTREAM*));
if (!data->segments) goto fail;
return data;
fail:
free_layout_segmented(data);
return NULL;
}
int setup_layout_segmented(segmented_layout_data* data) {
int i;
/* setup each VGMSTREAM (roughly equivalent to vgmstream.c's init_vgmstream_internal stuff) */
for (i = 0; i < data->segment_count; i++) {
if (!data->segments[i])
goto fail;
if (data->segments[i]->num_samples <= 0)
goto fail;
/* shouldn't happen */
if (data->segments[i]->loop_flag != 0) {
VGM_LOG("segmented layout: segment %i is looped\n", i);
data->segments[i]->loop_flag = 0;
}
if (i > 0) {
if (data->segments[i]->channels != data->segments[i-1]->channels)
goto fail;
/* a bit weird, but no matter */
if (data->segments[i]->sample_rate != data->segments[i-1]->sample_rate) {
VGM_LOG("segmented layout: segment %i has different sample rate\n", i);
}
//if (data->segments[i]->coding_type != data->segments[i-1]->coding_type)
// goto fail; /* perfectly acceptable */
}
/* save start things so we can restart for seeking/looping */
memcpy(data->segments[i]->start_ch,data->segments[i]->ch,sizeof(VGMSTREAMCHANNEL)*data->segments[i]->channels);
memcpy(data->segments[i]->start_vgmstream,data->segments[i],sizeof(VGMSTREAM));
}
return 1;
fail:
return 0; /* caller is expected to free */
}
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
segmented_layout_data *data = vgmstream->layout_data;
//int samples_per_frame = get_vgmstream_samples_per_frame(vgmstream);
while (samples_written<sample_count) {
int samples_to_do;
int samples_this_block = data->segments[data->current_segment]->num_samples;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
//todo can only loop in a segment start
// (for arbitrary values find loop segment from loop_start_sample, and skip N samples until loop start)
data->current_segment = data->loop_segment;
reset_vgmstream(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0;
continue;
}
samples_to_do = vgmstream_samples_to_do(samples_this_block, 1, vgmstream);
if (samples_written+samples_to_do > sample_count)
samples_to_do=sample_count-samples_written;
if (samples_to_do == 0) {
data->current_segment++;
reset_vgmstream(data->segments[data->current_segment]);
vgmstream->samples_into_block = 0;
continue;
}
render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels],
samples_to_do,data->segments[data->current_segment]);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
}
}
void free_layout_segmented(segmented_layout_data *data) {
int i;
if (!data)
return;
if (data->segments) {
for (i = 0; i < data->segment_count; i++) {
/* note that the close_streamfile won't do anything but deallocate itself,
* there is only one open file in vgmstream->ch[0].streamfile */
close_vgmstream(data->segments[i]);
}
free(data->segments);
}
free(data);
}
void reset_layout_segmented(segmented_layout_data *data) {
int i;
if (!data)
return;
data->current_segment = 0;
for (i = 0; i < data->segment_count; i++) {
reset_vgmstream(data->segments[i]);
}
}

View File

@ -209,7 +209,7 @@
>
</File>
<File
RelativePath=".\meta\aax_streamfile.h"
RelativePath=".\meta\aax_utf.h"
>
</File>
<File
@ -615,7 +615,7 @@
>
</File>
<File
RelativePath=".\meta\ngc_caf.c"
RelativePath=".\meta\caf.c"
>
</File>
<File
@ -1282,6 +1282,14 @@
RelativePath=".\meta\waf.c"
>
</File>
<File
RelativePath=".\meta\wave_segmented.c"
>
</File>
<File
RelativePath=".\meta\wave.c"
>
</File>
<File
RelativePath=".\meta\wii_04sw.c"
>
@ -1667,7 +1675,7 @@
Name="Source Files"
>
<File
RelativePath=".\layout\aax_layout.c"
RelativePath=".\layout\segmented.c"
>
</File>
<File
@ -1707,7 +1715,7 @@
>
</File>
<File
RelativePath=".\layout\caf_blocked.c"
RelativePath=".\layout\blocked_caf.c"
>
</File>
<File

View File

@ -94,7 +94,7 @@
<ClInclude Include="util.h" />
<ClInclude Include="vgmstream.h" />
<ClInclude Include="meta\adx_keys.h" />
<ClInclude Include="meta\aax_streamfile.h" />
<ClInclude Include="meta\aax_utf.h" />
<ClInclude Include="meta\aix_streamfile.h" />
<ClInclude Include="meta\bar_streamfile.h" />
<ClInclude Include="meta\sqex_scd_streamfile.h" />
@ -259,7 +259,7 @@
<ClCompile Include="meta\ngc_adpdtk.c" />
<ClCompile Include="meta\ngc_bh2pcm.c" />
<ClCompile Include="meta\ngc_bo2.c" />
<ClCompile Include="meta\ngc_caf.c" />
<ClCompile Include="meta\caf.c" />
<ClCompile Include="meta\ngc_dsp_konami.c" />
<ClCompile Include="meta\ngc_dsp_mpds.c" />
<ClCompile Include="meta\ngc_dsp_std.c" />
@ -400,6 +400,8 @@
<ClCompile Include="meta\vxn.c" />
<ClCompile Include="meta\waa_wac_wad_wam.c" />
<ClCompile Include="meta\waf.c" />
<ClCompile Include="meta\wave_segmented.c" />
<ClCompile Include="meta\wave.c" />
<ClCompile Include="meta\wii_04sw.c" />
<ClCompile Include="meta\wii_bns.c" />
<ClCompile Include="meta\wii_mus.c" />
@ -465,7 +467,7 @@
<ClCompile Include="coding\vorbis_custom_utils_wwise.c" />
<ClCompile Include="coding\ws_decoder.c" />
<ClCompile Include="coding\xa_decoder.c" />
<ClCompile Include="layout\aax_layout.c" />
<ClCompile Include="layout\segmented.c" />
<ClCompile Include="layout\aix_layout.c" />
<ClCompile Include="layout\ast_blocked.c" />
<ClCompile Include="layout\bdsp_blocked.c" />
@ -475,7 +477,7 @@
<ClCompile Include="layout\blocked_vgs.c" />
<ClCompile Include="layout\blocked_vawx.c" />
<ClCompile Include="layout\blocked_xvag.c" />
<ClCompile Include="layout\caf_blocked.c" />
<ClCompile Include="layout\blocked_caf.c" />
<ClCompile Include="layout\blocked_dec.c" />
<ClCompile Include="layout\blocked_ea_schl.c" />
<ClCompile Include="layout\blocked_ea_sns.c" />

View File

@ -62,7 +62,7 @@
<ClInclude Include="meta\adx_keys.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\aax_streamfile.h">
<ClInclude Include="meta\aax_utf.h">
<Filter>meta\Header Files</Filter>
</ClInclude>
<ClInclude Include="meta\aix_streamfile.h">
@ -361,7 +361,7 @@
<ClCompile Include="meta\ngc_bo2.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ngc_caf.c">
<ClCompile Include="meta\caf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\ngc_dsp_konami.c">
@ -784,6 +784,12 @@
<ClCompile Include="meta\waf.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wave_segmented.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wave.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
<ClCompile Include="meta\wii_04sw.c">
<Filter>meta\Source Files</Filter>
</ClCompile>
@ -970,7 +976,7 @@
<ClCompile Include="coding\xa_decoder.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\aax_layout.c">
<ClCompile Include="layout\segmented.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\aix_layout.c">
@ -1000,7 +1006,7 @@
<ClCompile Include="layout\blocked_xvag.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\caf_blocked.c">
<ClCompile Include="layout\blocked_caf.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\blocked_dec.c">

View File

@ -1,673 +1,193 @@
#include "meta.h"
#include "aax_streamfile.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "aax_utf.h"
struct utf_query
{
/* if 0 */
const char *name;
int index;
};
struct offset_size_pair
{
uint32_t offset;
uint32_t size;
};
struct utf_query_result
{
int valid; /* table is valid */
int found;
int type; /* one of COLUMN_TYPE_* */
union
{
uint64_t value_u64;
uint32_t value_u32;
uint16_t value_u16;
uint8_t value_u8;
float value_float;
struct offset_size_pair value_data;
uint32_t value_string;
} value;
/* info for the queried table */
uint32_t rows;
uint32_t name_offset;
uint32_t string_table_offset;
uint32_t data_offset;
};
static struct utf_query_result analyze_utf(STREAMFILE *infile, long offset,
const struct utf_query *query);
static struct utf_query_result query_utf(STREAMFILE *infile, long offset,
const struct utf_query *query);
static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset,
const struct utf_query *query, int *error);
static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset,
int index, const char *name, int *error);
static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset,
int index, const char *name, int *error);
static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
int index, const char *name, int *error);
#define COLUMN_STORAGE_MASK 0xf0
#define COLUMN_STORAGE_PERROW 0x50
#define COLUMN_STORAGE_CONSTANT 0x30
#define COLUMN_STORAGE_ZERO 0x10
#define COLUMN_TYPE_MASK 0x0f
#define COLUMN_TYPE_DATA 0x0b
#define COLUMN_TYPE_STRING 0x0a
#define COLUMN_TYPE_FLOAT 0x08
#define COLUMN_TYPE_8BYTE 0x06
#define COLUMN_TYPE_4BYTE 0x04
#define COLUMN_TYPE_2BYTE2 0x03
#define COLUMN_TYPE_2BYTE 0x02
#define COLUMN_TYPE_1BYTE2 0x01
#define COLUMN_TYPE_1BYTE 0x00
struct utf_column_info
{
uint8_t type;
const char *column_name;
long constant_offset;
};
struct utf_table_info
{
long table_offset;
uint32_t table_size;
uint32_t schema_offset;
uint32_t rows_offset;
uint32_t string_table_offset;
uint32_t data_offset;
const char *string_table;
const char *table_name;
uint16_t columns;
uint16_t row_width;
uint32_t rows;
const struct utf_column_info *schema;
};
static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext);
/* AAX - segmented ADX [Padora's Tower (Wii)] */
#define MAX_SEGMENTS 2 /* usually segment0=intro, segment1=loop/main */
/* AAX - segmented ADX [Bayonetta (PS3), Pandora's Tower (Wii), Catherine (X360), Binary Domain (PS3)] */
VGMSTREAM * init_vgmstream_aax(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
STREAMFILE * streamFileAAX = NULL;
STREAMFILE * streamFileADX = NULL;
char filename[PATH_LIMIT];
off_t *segment_offset = NULL;
off_t *segment_size = NULL;
int32_t sample_count;
int is_hca;
int loop_flag = 0, channel_count = 0;
int32_t sample_count, loop_start_sample = 0, loop_end_sample = 0;
int segment_count, loop_segment = 0;
segmented_layout_data *data = NULL;
int table_error = 0;
int loop_flag = 0;
int32_t loop_start_sample=0;
int32_t loop_end_sample=0;
int loop_segment = 0;
aax_codec_data *data = NULL;
const long AAX_offset = 0;
int channel_count = 0, segment_count;
int sample_rate = 0;
const long top_offset = 0x00;
off_t segment_offset[MAX_SEGMENTS];
size_t segment_size[MAX_SEGMENTS];
int i;
long aax_data_offset;
/* checks */
if (!check_extensions(streamFile, "aax"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
goto fail;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("aax",filename_extension(filename))) goto fail;
/* get AAX entry count, data offset */
/* get segment count, offsets and sizes */
{
struct utf_query_result result;
long aax_string_table_offset;
long aax_string_table_size;
result = query_utf_nofail(streamFile, AAX_offset, NULL, &table_error);
long aax_data_offset;
result = query_utf_nofail(streamFile, top_offset, NULL, &table_error);
if (table_error) goto fail;
segment_count = result.rows;
aax_string_table_offset = AAX_offset + 8 + result.string_table_offset;
aax_data_offset = AAX_offset + 8 + result.data_offset;
if (segment_count > MAX_SEGMENTS) goto fail;
aax_string_table_offset = top_offset+0x08 + result.string_table_offset;
aax_data_offset = top_offset+0x08 + result.data_offset;
aax_string_table_size = aax_data_offset - aax_string_table_offset;
if (result.name_offset+4 > aax_string_table_size) goto fail;
if (read_32bitBE(aax_string_table_offset + result.name_offset,
streamFile) != 0x41415800) /* "AAX\0" */
if (result.name_offset+0x04 > aax_string_table_size)
goto fail;
}
segment_offset = calloc(segment_count,sizeof(off_t));
if (!segment_offset)
goto fail;
segment_size = calloc(segment_count,sizeof(off_t));
if (!segment_size)
goto fail;
/* get offsets of constituent ADXs */
for (i = 0; i < segment_count; i++)
{
struct offset_size_pair offset_size;
offset_size = query_utf_data(streamFile, AAX_offset, i, "data", &table_error);
if (table_error) goto fail;
segment_offset[i] = aax_data_offset + offset_size.offset;
segment_size[i] = offset_size.size;
}
streamFileAAX = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!streamFileAAX) goto fail;
data = malloc(sizeof(aax_codec_data));
if (!data) goto fail;
data->segment_count = segment_count;
data->adxs = malloc(sizeof(STREAMFILE *)*segment_count);
if (!data->adxs) goto fail;
for (i=0;i<segment_count;i++) {
data->adxs[i] = NULL;
}
data->sample_counts = calloc(segment_count,sizeof(int32_t));
if (!data->sample_counts) goto fail;
/* for each segment */
for (i = 0; i < segment_count; i++)
{
VGMSTREAM *adx;
/*printf("try opening segment %d/%d %x\n",i,segment_count,segment_offset[i]);*/
streamFileADX = open_aax_with_STREAMFILE(streamFileAAX,segment_offset[i],segment_size[i]);
if (!streamFileADX) goto fail;
adx = data->adxs[i] = init_vgmstream_adx(streamFileADX);
if (!adx)
goto fail;
data->sample_counts[i] = adx->num_samples;
close_streamfile(streamFileADX); streamFileADX = NULL;
if (i == 0)
{
channel_count = adx->channels;
sample_rate = adx->sample_rate;
}
if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) == 0x41415800) /* "AAX\0" */
is_hca = 0;
else if (read_32bitBE(aax_string_table_offset + result.name_offset, streamFile) == 0x48434100) /* "HCA\0" */
is_hca = 1;
else
{
if (channel_count != adx->channels)
goto fail;
if (sample_rate != adx->sample_rate)
goto fail;
}
if (adx->loop_flag != 0)
goto fail;
/* save start things so we can restart for seeking/looping */
/* copy the channels */
memcpy(adx->start_ch,adx->ch,sizeof(VGMSTREAMCHANNEL)*adx->channels);
/* copy the whole VGMSTREAM */
memcpy(adx->start_vgmstream,adx,sizeof(VGMSTREAM));
/* get offsets of constituent segments */
for (i = 0; i < segment_count; i++) {
struct offset_size_pair offset_size;
offset_size = query_utf_data(streamFile, top_offset, i, "data", &table_error);
if (table_error) goto fail;
segment_offset[i] = aax_data_offset + offset_size.offset;
segment_size[i] = offset_size.size;
}
}
/* init layout */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
/* open each segment subfile */
for (i = 0; i < segment_count; i++) {
STREAMFILE* temp_streamFile = setup_aax_streamfile(streamFile, segment_offset[i],segment_size[i], (is_hca ? "hca" : "adx"));
if (!temp_streamFile) goto fail;
data->segments[i] = is_hca ?
init_vgmstream_hca(temp_streamFile) :
init_vgmstream_adx(temp_streamFile);
close_streamfile(temp_streamFile);
if (!data->segments[i]) goto fail;
}
/* setup segmented VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
/* get looping and samples */
sample_count = 0;
loop_flag = 0;
for (i = 0; i < segment_count; i++)
{
int segment_loop_flag = query_utf_1byte(streamFile, AAX_offset, i,
"lpflg", &table_error);
for (i = 0; i < segment_count; i++) {
int segment_loop_flag = query_utf_1byte(streamFile, top_offset, i, "lpflg", &table_error);
if (table_error) segment_loop_flag = 0;
if (!loop_flag && segment_loop_flag)
{
if (!loop_flag && segment_loop_flag) {
loop_start_sample = sample_count;
loop_segment = i;
}
sample_count += data->sample_counts[i];
sample_count += data->segments[i]->num_samples;
if (!loop_flag && segment_loop_flag)
{
if (!loop_flag && segment_loop_flag) {
loop_end_sample = sample_count;
loop_flag = 1;
}
}
channel_count = data->segments[0]->channels;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = data->segments[0]->sample_rate;
vgmstream->num_samples = sample_count;
vgmstream->sample_rate = sample_rate;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->coding_type = data->adxs[0]->coding_type;
vgmstream->layout_type = layout_aax;
vgmstream->meta_type = meta_AAX;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->layout_type = layout_segmented;
vgmstream->ch[0].streamfile = streamFileAAX;
data->current_segment = 0;
vgmstream->layout_data = data;
data->loop_segment = loop_segment;
vgmstream->codec_data = data;
free(segment_offset);
free(segment_size);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (streamFileAAX) close_streamfile(streamFileAAX);
if (streamFileADX) close_streamfile(streamFileADX);
if (vgmstream) close_vgmstream(vgmstream);
if (segment_offset) free(segment_offset);
if (segment_size) free(segment_size);
if (data) {
if (data->adxs)
{
int i;
for (i=0;i<data->segment_count;i++)
if (data->adxs)
close_vgmstream(data->adxs[i]);
free(data->adxs);
}
if (data->sample_counts)
{
free(data->sample_counts);
}
free(data);
}
close_vgmstream(vgmstream);
free_layout_segmented(data);
return NULL;
}
/* @UTF table reading, abridged */
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
{
unsigned char buf[4];
struct utf_table_info table_info;
char *string_table = NULL;
struct utf_column_info * schema = NULL;
struct utf_query_result result;
uint32_t table_name_string;
int string_table_size;
result.valid = 0;
static STREAMFILE* setup_aax_streamfile(STREAMFILE *streamFile, off_t subfile_offset, size_t subfile_size, const char* fake_ext) {
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
table_info.table_offset = offset;
/* setup subfile */
new_streamFile = open_wrap_streamfile(streamFile);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
/* check header */
{
static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error;
if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
{
goto cleanup_error;
}
}
new_streamFile = open_clamp_streamfile(temp_streamFile, subfile_offset,subfile_size);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
/* get table size */
table_info.table_size = read_32bitBE(offset+4, infile);
new_streamFile = open_fakename_streamfile(temp_streamFile, NULL,fake_ext);
if (!new_streamFile) goto fail;
temp_streamFile = new_streamFile;
table_info.schema_offset = 0x20;
table_info.rows_offset = read_32bitBE(offset+8, infile);
table_info.string_table_offset = read_32bitBE(offset+0xc,infile);
table_info.data_offset = read_32bitBE(offset+0x10,infile);
table_name_string = read_32bitBE(offset+0x14,infile);
table_info.columns = read_16bitBE(offset+0x18,infile);
table_info.row_width = read_16bitBE(offset+0x1a,infile);
table_info.rows = read_32bitBE(offset+0x1c,infile);
return temp_streamFile;
/* allocate for string table */
string_table_size = table_info.data_offset-table_info.string_table_offset;
string_table = malloc(string_table_size+1);
if (!string_table) goto cleanup_error;
table_info.string_table = string_table;
memset(string_table, 0, string_table_size+1);
/* load schema */
schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
if (!schema) goto cleanup_error;
{
int i;
long schema_current_offset = table_info.schema_offset;
for (i = 0; i < table_info.columns; i++)
{
schema[i].type = read_8bit(schema_current_offset,infile);
schema_current_offset ++;
schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile);
schema_current_offset += 4;
if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
{
schema[i].constant_offset = schema_current_offset;
switch (schema[i].type & COLUMN_TYPE_MASK)
{
case COLUMN_TYPE_8BYTE:
case COLUMN_TYPE_DATA:
schema_current_offset+=8;
break;
case COLUMN_TYPE_STRING:
case COLUMN_TYPE_FLOAT:
case COLUMN_TYPE_4BYTE:
schema_current_offset+=4;
break;
case COLUMN_TYPE_2BYTE2:
case COLUMN_TYPE_2BYTE:
schema_current_offset+=2;
break;
case COLUMN_TYPE_1BYTE2:
case COLUMN_TYPE_1BYTE:
schema_current_offset++;
break;
default:
goto cleanup_error;
}
}
}
}
table_info.schema = schema;
/* read string table */
read_streamfile((unsigned char *)string_table,
table_info.string_table_offset+8+offset,
string_table_size, infile);
table_info.table_name = table_info.string_table+table_name_string;
/* fill in the default stuff */
result.found = 0;
result.rows = table_info.rows;
result.name_offset = table_name_string;
result.string_table_offset = table_info.string_table_offset;
result.data_offset = table_info.data_offset;
/* explore the values */
if (query) {
int i, j;
for (i = 0; i < table_info.rows; i++)
{
uint32_t row_offset =
table_info.table_offset + 8 + table_info.rows_offset +
i * table_info.row_width;
const uint32_t row_start_offset = row_offset;
if (query && i != query->index) continue;
for (j = 0; j < table_info.columns; j++)
{
uint8_t type = table_info.schema[j].type;
long constant_offset = table_info.schema[j].constant_offset;
int constant = 0;
int qthis = (query && i == query->index &&
!strcmp(table_info.schema[j].column_name, query->name));
if (qthis)
{
result.found = 1;
result.type = schema[j].type & COLUMN_TYPE_MASK;
}
switch (schema[j].type & COLUMN_STORAGE_MASK)
{
case COLUMN_STORAGE_PERROW:
break;
case COLUMN_STORAGE_CONSTANT:
constant = 1;
break;
case COLUMN_STORAGE_ZERO:
if (qthis)
{
memset(&result.value, 0,
sizeof(result.value));
}
continue;
default:
goto cleanup_error;
}
if (1)
{
long data_offset;
int bytes_read;
if (constant)
{
data_offset = constant_offset;
}
else
{
data_offset = row_offset;
}
switch (type & COLUMN_TYPE_MASK)
{
case COLUMN_TYPE_STRING:
{
uint32_t string_offset;
string_offset = read_32bitBE(data_offset, infile);
bytes_read = 4;
if (qthis)
{
result.value.value_string = string_offset;
}
}
break;
case COLUMN_TYPE_DATA:
{
uint32_t vardata_offset, vardata_size;
vardata_offset = read_32bitBE(data_offset, infile);
vardata_size = read_32bitBE(data_offset+4, infile);
bytes_read = 8;
if (qthis)
{
result.value.value_data.offset = vardata_offset;
result.value.value_data.size = vardata_size;
}
}
break;
case COLUMN_TYPE_8BYTE:
{
uint64_t value =
read_32bitBE(data_offset, infile);
value <<= 32;
value |=
read_32bitBE(data_offset+4, infile);
if (qthis)
{
result.value.value_u64 = value;
}
bytes_read = 8;
break;
}
case COLUMN_TYPE_4BYTE:
{
uint32_t value =
read_32bitBE(data_offset, infile);
if (qthis)
{
result.value.value_u32 = value;
}
bytes_read = 4;
}
break;
case COLUMN_TYPE_2BYTE2:
case COLUMN_TYPE_2BYTE:
{
uint16_t value =
read_16bitBE(data_offset, infile);
if (qthis)
{
result.value.value_u16 = value;
}
bytes_read = 2;
}
break;
case COLUMN_TYPE_FLOAT:
if (sizeof(float) == 4)
{
union {
float float_value;
uint32_t int_value;
} int_float;
int_float.int_value = read_32bitBE(data_offset, infile);
if (qthis)
{
result.value.value_float = int_float.float_value;
}
}
else
{
read_32bitBE(data_offset, infile);
if (qthis)
{
goto cleanup_error;
}
}
bytes_read = 4;
break;
case COLUMN_TYPE_1BYTE2:
case COLUMN_TYPE_1BYTE:
{
uint8_t value =
read_8bit(data_offset, infile);
if (qthis)
{
result.value.value_u8 = value;
}
bytes_read = 1;
}
break;
default:
goto cleanup_error;
}
if (!constant)
{
row_offset += bytes_read;
}
} /* useless if end */
} /* column for loop end */
if (row_offset - row_start_offset != table_info.row_width)
goto cleanup_error;
if (query && i >= query->index) break;
} /* row for loop end */
} /* explore values block end */
//cleanup:
result.valid = 1;
cleanup_error:
if (string_table)
{
free(string_table);
string_table = NULL;
}
if (schema)
{
free(schema);
schema = NULL;
}
return result;
fail:
close_streamfile(temp_streamFile);
return NULL;
}
static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
{
return analyze_utf(infile, offset, query);
}
static struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error)
{
const struct utf_query_result result = query_utf(infile, offset, query);
if (error)
{
*error = 0;
if (!result.valid) *error = 1;
if (query && !result.found) *error = 1;
}
return result;
}
static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query query;
query.index = index;
query.name = name;
return query_utf_nofail(infile, offset, &query, error);
}
static uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_1BYTE) *error = 1;
}
return result.value.value_u8;
}
static uint32_t query_utf_4byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_4BYTE) *error = 1;
}
return result.value.value_u32;
}
static struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_DATA) *error = 1;
}
return result.value.value_data;
}
/* CRI's UTF wrapper around DSP */
/* CRI's UTF wrapper around DSP [Sonic Colors sfx (Wii), NiGHTS: Journey of Dreams sfx (Wii)] */
VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int table_error = 0;
off_t start_offset;
size_t channel_size;
int loop_flag = 0;
const long top_offset = 0;
int channel_count;
int sample_rate;
int loop_flag = 0, channel_count, sample_rate;
long sample_count;
int table_error = 0;
const long top_offset = 0x00;
long top_data_offset, segment_count;
long body_offset, body_size;
long header_offset, header_size;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
//if (strcasecmp("aax",filename_extension(filename))) goto fail;
/* get entry count, data offset */
/* checks */
/* files don't have extension, we accept "" for CLI and .aax for plugins (they aren't exactly .aax though) */
if (!check_extensions(streamFile, "aax,"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x40555446) /* "@UTF" */
goto fail;
/* get segment count, offsets and sizes*/
{
struct utf_query_result result;
long top_string_table_offset;
@ -676,8 +196,10 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
result = query_utf_nofail(streamFile, top_offset, NULL, &table_error);
if (table_error) goto fail;
segment_count = result.rows;
if (segment_count != 1) goto fail; // only simple stuff for now
if (segment_count != 1) goto fail; /* only simple stuff for now (multisegment not known) */
top_string_table_offset = top_offset + 8 + result.string_table_offset;
top_data_offset = top_offset + 8 + result.data_offset;
top_string_table_size = top_data_offset - top_string_table_offset;
@ -685,12 +207,13 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
if (result.name_offset+10 > top_string_table_size) goto fail;
name_offset = top_string_table_offset + result.name_offset;
if (read_32bitBE(name_offset, streamFile) != 0x41445043 ||// "ADPC"
read_32bitBE(name_offset+4, streamFile) != 0x4D5F5749 ||// "M_WI"
read_16bitBE(name_offset+8, streamFile) != 0x4900) // "I\0"
if (read_32bitBE(name_offset+0x00, streamFile) != 0x41445043 || /* "ADPC" */
read_32bitBE(name_offset+0x04, streamFile) != 0x4D5F5749 || /* "M_WI" */
read_16bitBE(name_offset+0x08, streamFile) != 0x4900) /* "I\0" */
goto fail;
}
/* get sizes */
{
struct offset_size_pair offset_size;
@ -712,36 +235,29 @@ VGMSTREAM * init_vgmstream_utf_dsp(STREAMFILE *streamFile) {
if (channel_count != 1 && channel_count != 2) goto fail;
if (header_size != channel_count * 0x60) goto fail;
start_offset = body_offset;
channel_size = (body_size+7) / 8 * 8 / channel_count;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = sample_count;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = sample_count;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_UTF_DSP;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = channel_size;
{
int i,j;
long channel_size = (body_size+7)/8*8/channel_count;
for (i = 0; i < channel_count; i++)
{
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset = body_offset + i * channel_size;
for (j=0;j<16;j++)
{
vgmstream->ch[i].adpcm_coef[j] =
read_16bitBE(header_offset + 0x60*i + 0x1c + j*2, streamFile);
}
}
}
dsp_read_coefs_be(vgmstream, streamFile, header_offset+0x1c, 0x60);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,83 +0,0 @@
#ifndef _AAX_STREAMFILE_H_
#define _AAX_STREAMFILE_H_
#include "../streamfile.h"
/* a streamfile representing a subfile inside another */
typedef struct _AAXSTREAMFILE {
STREAMFILE sf;
STREAMFILE *real_file;
off_t start_physical_offset;
size_t file_size;
} AAXSTREAMFILE;
static size_t read_aax(AAXSTREAMFILE *streamfile,uint8_t *dest,off_t offset,size_t length) {
/* truncate at end of logical file */
if (offset+length > streamfile->file_size) {
long signed_length = length;
signed_length = streamfile->file_size - offset;
if (signed_length < 0) signed_length = 0;
length = signed_length;
}
return read_streamfile(dest, streamfile->start_physical_offset+offset, length,streamfile->real_file);
}
static void close_aax(AAXSTREAMFILE *streamfile) {
free(streamfile);
return;
}
static size_t get_size_aax(AAXSTREAMFILE *streamfile) {
return 0;
}
static size_t get_offset_aax(AAXSTREAMFILE *streamfile) {
long offset = streamfile->real_file->get_offset(streamfile->real_file);
offset -= streamfile->start_physical_offset;
if (offset < 0) offset = 0;
if (offset > streamfile->file_size) offset = streamfile->file_size;
return offset;
}
static void get_name_aax(AAXSTREAMFILE *streamfile,char *buffer,size_t length) {
strncpy(buffer,"ARBITRARY.ADX",length);
buffer[length-1]='\0';
}
static STREAMFILE *open_aax_impl(AAXSTREAMFILE *streamfile,const char * const filename,size_t buffersize) {
AAXSTREAMFILE *newfile;
if (strcmp(filename,"ARBITRARY.ADX"))
return NULL;
newfile = malloc(sizeof(AAXSTREAMFILE));
if (!newfile)
return NULL;
memcpy(newfile,streamfile,sizeof(AAXSTREAMFILE));
return &newfile->sf;
}
static STREAMFILE *open_aax_with_STREAMFILE(STREAMFILE *file,off_t start_offset,size_t file_size) {
AAXSTREAMFILE *streamfile = malloc(sizeof(AAXSTREAMFILE));
if (!streamfile)
return NULL;
/* success, set our pointers */
streamfile->sf.read = (void*)read_aax;
streamfile->sf.get_size = (void*)get_size_aax;
streamfile->sf.get_offset = (void*)get_offset_aax;
streamfile->sf.get_name = (void*)get_name_aax;
streamfile->sf.get_realname = (void*)get_name_aax;
streamfile->sf.open = (void*)open_aax_impl;
streamfile->sf.close = (void*)close_aax;
streamfile->real_file = file;
streamfile->start_physical_offset = start_offset;
streamfile->file_size = file_size;
return &streamfile->sf;
}
#endif /* _AAX_STREAMFILE_H_ */

442
src/meta/aax_utf.h Normal file
View File

@ -0,0 +1,442 @@
#ifndef _AAX_UTF_H_
#define _AAX_UTF_H_
struct utf_query
{
/* if 0 */
const char *name;
int index;
};
struct offset_size_pair
{
uint32_t offset;
uint32_t size;
};
struct utf_query_result
{
int valid; /* table is valid */
int found;
int type; /* one of COLUMN_TYPE_* */
union
{
uint64_t value_u64;
uint32_t value_u32;
uint16_t value_u16;
uint8_t value_u8;
float value_float;
struct offset_size_pair value_data;
uint32_t value_string;
} value;
/* info for the queried table */
uint32_t rows;
uint32_t name_offset;
uint32_t string_table_offset;
uint32_t data_offset;
};
#define COLUMN_STORAGE_MASK 0xf0
#define COLUMN_STORAGE_PERROW 0x50
#define COLUMN_STORAGE_CONSTANT 0x30
#define COLUMN_STORAGE_ZERO 0x10
#define COLUMN_TYPE_MASK 0x0f
#define COLUMN_TYPE_DATA 0x0b
#define COLUMN_TYPE_STRING 0x0a
#define COLUMN_TYPE_FLOAT 0x08
#define COLUMN_TYPE_8BYTE 0x06
#define COLUMN_TYPE_4BYTE 0x04
#define COLUMN_TYPE_2BYTE2 0x03
#define COLUMN_TYPE_2BYTE 0x02
#define COLUMN_TYPE_1BYTE2 0x01
#define COLUMN_TYPE_1BYTE 0x00
struct utf_column_info
{
uint8_t type;
const char *column_name;
long constant_offset;
};
struct utf_table_info
{
long table_offset;
uint32_t table_size;
uint32_t schema_offset;
uint32_t rows_offset;
uint32_t string_table_offset;
uint32_t data_offset;
const char *string_table;
const char *table_name;
uint16_t columns;
uint16_t row_width;
uint32_t rows;
const struct utf_column_info *schema;
};
/* @UTF table reading, abridged */
static struct utf_query_result analyze_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
{
unsigned char buf[4];
struct utf_table_info table_info;
char *string_table = NULL;
struct utf_column_info * schema = NULL;
struct utf_query_result result;
uint32_t table_name_string;
int string_table_size;
result.valid = 0;
table_info.table_offset = offset;
/* check header */
{
static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
if (4 != read_streamfile(buf, offset, 4, infile)) goto cleanup_error;
if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
{
goto cleanup_error;
}
}
/* get table size */
table_info.table_size = read_32bitBE(offset+4, infile);
table_info.schema_offset = 0x20;
table_info.rows_offset = read_32bitBE(offset+8, infile);
table_info.string_table_offset = read_32bitBE(offset+0xc,infile);
table_info.data_offset = read_32bitBE(offset+0x10,infile);
table_name_string = read_32bitBE(offset+0x14,infile);
table_info.columns = read_16bitBE(offset+0x18,infile);
table_info.row_width = read_16bitBE(offset+0x1a,infile);
table_info.rows = read_32bitBE(offset+0x1c,infile);
/* allocate for string table */
string_table_size = table_info.data_offset-table_info.string_table_offset;
string_table = malloc(string_table_size+1);
if (!string_table) goto cleanup_error;
table_info.string_table = string_table;
memset(string_table, 0, string_table_size+1);
/* load schema */
schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
if (!schema) goto cleanup_error;
{
int i;
long schema_current_offset = table_info.schema_offset;
for (i = 0; i < table_info.columns; i++)
{
schema[i].type = read_8bit(schema_current_offset,infile);
schema_current_offset ++;
schema[i].column_name = string_table + read_32bitBE(schema_current_offset,infile);
schema_current_offset += 4;
if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
{
schema[i].constant_offset = schema_current_offset;
switch (schema[i].type & COLUMN_TYPE_MASK)
{
case COLUMN_TYPE_8BYTE:
case COLUMN_TYPE_DATA:
schema_current_offset+=8;
break;
case COLUMN_TYPE_STRING:
case COLUMN_TYPE_FLOAT:
case COLUMN_TYPE_4BYTE:
schema_current_offset+=4;
break;
case COLUMN_TYPE_2BYTE2:
case COLUMN_TYPE_2BYTE:
schema_current_offset+=2;
break;
case COLUMN_TYPE_1BYTE2:
case COLUMN_TYPE_1BYTE:
schema_current_offset++;
break;
default:
goto cleanup_error;
}
}
}
}
table_info.schema = schema;
/* read string table */
read_streamfile((unsigned char *)string_table,
table_info.string_table_offset+8+offset,
string_table_size, infile);
table_info.table_name = table_info.string_table+table_name_string;
/* fill in the default stuff */
result.found = 0;
result.rows = table_info.rows;
result.name_offset = table_name_string;
result.string_table_offset = table_info.string_table_offset;
result.data_offset = table_info.data_offset;
/* explore the values */
if (query) {
int i, j;
for (i = 0; i < table_info.rows; i++)
{
uint32_t row_offset =
table_info.table_offset + 8 + table_info.rows_offset +
i * table_info.row_width;
const uint32_t row_start_offset = row_offset;
if (query && i != query->index) continue;
for (j = 0; j < table_info.columns; j++)
{
uint8_t type = table_info.schema[j].type;
long constant_offset = table_info.schema[j].constant_offset;
int constant = 0;
int qthis = (query && i == query->index &&
!strcmp(table_info.schema[j].column_name, query->name));
if (qthis)
{
result.found = 1;
result.type = schema[j].type & COLUMN_TYPE_MASK;
}
switch (schema[j].type & COLUMN_STORAGE_MASK)
{
case COLUMN_STORAGE_PERROW:
break;
case COLUMN_STORAGE_CONSTANT:
constant = 1;
break;
case COLUMN_STORAGE_ZERO:
if (qthis)
{
memset(&result.value, 0,
sizeof(result.value));
}
continue;
default:
goto cleanup_error;
}
if (1)
{
long data_offset;
int bytes_read;
if (constant)
{
data_offset = constant_offset;
}
else
{
data_offset = row_offset;
}
switch (type & COLUMN_TYPE_MASK)
{
case COLUMN_TYPE_STRING:
{
uint32_t string_offset;
string_offset = read_32bitBE(data_offset, infile);
bytes_read = 4;
if (qthis)
{
result.value.value_string = string_offset;
}
}
break;
case COLUMN_TYPE_DATA:
{
uint32_t vardata_offset, vardata_size;
vardata_offset = read_32bitBE(data_offset, infile);
vardata_size = read_32bitBE(data_offset+4, infile);
bytes_read = 8;
if (qthis)
{
result.value.value_data.offset = vardata_offset;
result.value.value_data.size = vardata_size;
}
}
break;
case COLUMN_TYPE_8BYTE:
{
uint64_t value =
read_32bitBE(data_offset, infile);
value <<= 32;
value |=
read_32bitBE(data_offset+4, infile);
if (qthis)
{
result.value.value_u64 = value;
}
bytes_read = 8;
break;
}
case COLUMN_TYPE_4BYTE:
{
uint32_t value =
read_32bitBE(data_offset, infile);
if (qthis)
{
result.value.value_u32 = value;
}
bytes_read = 4;
}
break;
case COLUMN_TYPE_2BYTE2:
case COLUMN_TYPE_2BYTE:
{
uint16_t value =
read_16bitBE(data_offset, infile);
if (qthis)
{
result.value.value_u16 = value;
}
bytes_read = 2;
}
break;
case COLUMN_TYPE_FLOAT:
if (sizeof(float) == 4)
{
union {
float float_value;
uint32_t int_value;
} int_float;
int_float.int_value = read_32bitBE(data_offset, infile);
if (qthis)
{
result.value.value_float = int_float.float_value;
}
}
else
{
read_32bitBE(data_offset, infile);
if (qthis)
{
goto cleanup_error;
}
}
bytes_read = 4;
break;
case COLUMN_TYPE_1BYTE2:
case COLUMN_TYPE_1BYTE:
{
uint8_t value =
read_8bit(data_offset, infile);
if (qthis)
{
result.value.value_u8 = value;
}
bytes_read = 1;
}
break;
default:
goto cleanup_error;
}
if (!constant)
{
row_offset += bytes_read;
}
} /* useless if end */
} /* column for loop end */
if (row_offset - row_start_offset != table_info.row_width)
goto cleanup_error;
if (query && i >= query->index) break;
} /* row for loop end */
} /* explore values block end */
//cleanup:
result.valid = 1;
cleanup_error:
if (string_table)
{
free(string_table);
string_table = NULL;
}
if (schema)
{
free(schema);
schema = NULL;
}
return result;
}
static struct utf_query_result query_utf(STREAMFILE *infile, const long offset, const struct utf_query *query)
{
return analyze_utf(infile, offset, query);
}
/*static*/ struct utf_query_result query_utf_nofail(STREAMFILE *infile, const long offset, const struct utf_query *query, int *error)
{
const struct utf_query_result result = query_utf(infile, offset, query);
if (error)
{
*error = 0;
if (!result.valid) *error = 1;
if (query && !result.found) *error = 1;
}
return result;
}
static struct utf_query_result query_utf_key(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query query;
query.index = index;
query.name = name;
return query_utf_nofail(infile, offset, &query, error);
}
/*static*/ uint8_t query_utf_1byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_1BYTE) *error = 1;
}
return result.value.value_u8;
}
/*static*/ uint32_t query_utf_4byte(STREAMFILE *infile, const long offset, int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_4BYTE) *error = 1;
}
return result.value.value_u32;
}
/*static*/ struct offset_size_pair query_utf_data(STREAMFILE *infile, const long offset,
int index, const char *name, int *error)
{
struct utf_query_result result = query_utf_key(infile, offset, index, name, error);
if (error)
{
if (result.type != COLUMN_TYPE_DATA) *error = 1;
}
return result.value.value_data;
}
#endif /* SRC_META_AAX_UTF_H_ */

65
src/meta/caf.c Normal file
View File

@ -0,0 +1,65 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util.h"
/* CAF - from tri-Crescendo games [Baten Kaitos 1/2 (GC), Fragile (Wii)] */
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, offset;
size_t file_size;
int channel_count, loop_flag;
int32_t num_samples = 0;
uint32_t loop_start = -1;
/* checks */
/* .caf: header id, .cfn: fake extension? , "" is accepted as files don't have extensions in the disc */
if (!check_extensions(streamFile,"caf,cfn,"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x43414620) /* "CAF " */
goto fail;
/* get total samples */
offset = 0;
file_size = get_streamfile_size(streamFile);
while (offset < file_size) {
off_t next_block = read_32bitBE(offset+0x04,streamFile);
num_samples += read_32bitBE(offset+0x14,streamFile)/8*14;
if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) {
loop_start = num_samples - read_32bitBE(offset+0x14,streamFile)/8*14;
}
offset += next_block;
}
start_offset = 0x00;
channel_count = 2; /* always stereo */
loop_flag = (loop_start!=-1);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = 32000;
vgmstream->num_samples = num_samples;
if (loop_flag) {
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = num_samples;
}
vgmstream->meta_type = meta_CAF;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_caf;
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
goto fail;
block_update_caf(start_offset,vgmstream);
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,69 +1,42 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
/* GCA (from Metal Slug Anthology [Wii]) */
/* GCA - Terminal Reality games [Metal Slug Anthology (Wii), BlowOut (GC)] */
VGMSTREAM * init_vgmstream_gca(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag = 0;
int channel_count = 1;
int loop_flag, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("gca",filename_extension(filename))) goto fail;
/* checks */
if (!check_extensions(streamFile, "gca"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x47434131) /* "GCA1" */
goto fail;
start_offset = 0x40;
loop_flag = 0;
channel_count = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x40;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitBE(0x2A,streamFile);
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->num_samples = read_32bitBE(0x26,streamFile)*7/8;
if (loop_flag) {
vgmstream->loop_start_sample = 0;
vgmstream->loop_end_sample = read_32bitBE(0x26,streamFile)*7/8;
}
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(0x26,streamFile));//read_32bitBE(0x26,streamFile)*7/8;
/* We have no interleave, so we have no layout */
vgmstream->layout_type = layout_none;
vgmstream->layout_type = layout_none; /* we have no interleave, so we have no layout */
vgmstream->meta_type = meta_GCA;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
/*Retrieving the coef table */
{
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = read_16bitBE(0x04+i*2,streamFile);
}
}
dsp_read_coefs_be(vgmstream,streamFile,0x04,0x00);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -307,6 +307,7 @@ VGMSTREAM * init_vgmstream_rsd6xadp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6radp(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_rsd6oogv(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_rsd6xma(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_dc_asd(STREAMFILE * streamFile);
@ -706,4 +707,8 @@ VGMSTREAM * init_vgmstream_atx(STREAMFILE *streamFile);
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_waf(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wave(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -2,180 +2,163 @@
#include "../util.h"
/* MUSX (Version 004) --------------------------------------->*/
/* MUSX (Version 004) */
VGMSTREAM * init_vgmstream_musx_v004(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag;
int channel_count;
off_t start_offset;
int loop_flag, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("musx",filename_extension(filename))) goto fail;
/* check header */
/* checks */
if (!check_extensions(streamFile, "musx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x04000000) /* "0x04000000" */
goto fail;
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x04000000)
goto fail;
loop_flag = (read_32bitLE(0x840,streamFile) != 0xFFFFFFFF);
channel_count = 2;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
switch (read_32bitBE(0x10,streamFile))
{
case 0x5053325F: /* PS2_ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX; // PS2 ADPCM
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x58425F5F: /* XB__ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
switch (read_32bitBE(0x10,streamFile)) {
case 0x5053325F: /* PS2_ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x58425F5F: /* XB__ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
default:
goto fail;
goto fail;
}
vgmstream->meta_type = meta_MUSX_V004;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* <--------------------------------------- MUSX (Version 004) */
/* MUSX (Version 005) --------------------------------------->*/
/* MUSX (Version 005) [Predator: Concrete Jungle (PS2/Xbox) ] */
VGMSTREAM * init_vgmstream_musx_v005(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
int loop_flag;
int channel_count;
off_t start_offset;
int loop_flag, channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("musx",filename_extension(filename))) goto fail;
/* check header */
/* checks */
if (!check_extensions(streamFile, "musx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x05000000) /* "0x04000000" */
goto fail;
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x05000000)
goto fail;
loop_flag = (read_32bitLE(0x840,streamFile) != 0xFFFFFFFF);
channel_count = 2;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
switch (read_32bitBE(0x10,streamFile))
{
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA; // Eurocom DAT4 4-bit IMA ADPCM
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
}
break;
switch (read_32bitBE(0x10,streamFile)) {
case 0x5053325F: /* PS2_ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))/16/channel_count*28;
}
break;
case 0x58425F5F: /* XB__ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 44100;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitLE(0x2C,streamFile))/16/channel_count*28;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))/16/channel_count*28;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))/16/channel_count*28;
}
break;
default:
goto fail;
goto fail;
}
vgmstream->meta_type = meta_MUSX_V005;
/* open the file for reading */
{
int i;
STREAMFILE * file;
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!file) goto fail;
for (i=0;i<channel_count;i++) {
vgmstream->ch[i].streamfile = file;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* <--------------------------------------- MUSX (Version 005) */
/* MUSX (Version 006) ---------------------------------------> */
/* MUSX (Version 006) */
VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
@ -189,53 +172,48 @@ VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x06000000) /* "0x06000000" */
goto fail;
goto fail;
loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF);
channel_count = 2;
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
if (!vgmstream) goto fail;
/* fill in the vital statistics */
switch (read_32bitBE(0x10,streamFile))
{
case 0x5053325F: /* PS2_ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
vgmstream->meta_type = meta_MUSX_V006;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count;
}
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))*28/16/channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
vgmstream->meta_type = meta_MUSX_V006;
if (loop_flag)
{
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))*28/16/channel_count;
}
break;
default:
goto fail;
switch (read_32bitBE(0x10,streamFile)) {
case 0x5053325F: /* PS2_ */
start_offset = read_32bitLE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile))*28/16/channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
vgmstream->meta_type = meta_MUSX_V006;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitLE(0x890,streamFile))*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitLE(0x89C,streamFile))*28/16/channel_count;
}
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA;
vgmstream->num_samples = (read_32bitBE(0x2C,streamFile))*28/16/channel_count;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x20;
vgmstream->meta_type = meta_MUSX_V006;
if (loop_flag) {
vgmstream->loop_start_sample = (read_32bitBE(0x890,streamFile))*28/16/channel_count;
vgmstream->loop_end_sample = (read_32bitBE(0x89C,streamFile))*28/16/channel_count;
}
break;
default:
goto fail;
}
/* open the file for reading */
@ -256,24 +234,21 @@ VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* <--------------------------------------- MUSX (Version 006) */
/* MUSX (Version 010) --------------------------------------->*/
/* WII_ in Dead Space: Extraction */
/* MUSX (Version 010) [Dead Space: Extraction (Wii), Rio (PS3), Pirates of the Caribbean: At World's End (PSP)] */
VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */
//int musx_version; /* 0x08 provides a "version" byte */
int loop_flag = 0;
int channel_count;
int musx_type; /* determining the decoder by strings like "PS2_", "GC__" and so on */
//int musx_version; /* 0x08 provides a "version" byte */
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
@ -281,17 +256,17 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
goto fail;
if (read_32bitBE(0x800,streamFile) == 0x53424E4B) /* "SBNK", */ // SoundBank, refuse
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */
goto fail;
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x0A000000) /* "0x0A000000" */
goto fail;
loop_flag = ((read_32bitLE(0x34,streamFile)!=0x00000000) &&
(read_32bitLE(0x34,streamFile)!=0xABABABAB));
loop_flag = ((read_32bitLE(0x34,streamFile)!=0x00000000) &&
(read_32bitLE(0x34,streamFile)!=0xABABABAB));
channel_count = 2;
musx_type=(read_32bitBE(0x10,streamFile));
musx_type=(read_32bitBE(0x10,streamFile));
if (musx_type == 0x5749495F && /* WII_ */
(read_16bitBE(0x40,streamFile) == 0x4441) && /* DA */
@ -300,7 +275,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
channel_count = read_32bitLE(0x48,streamFile);
loop_flag = (read_32bitLE(0x64,streamFile) != -1);
}
if (musx_type == 0x5053335F && /* PS3_ */
if (musx_type == 0x5053335F && /* PS3_ */
(read_16bitBE(0x40,streamFile) == 0x4441) && /* DA */
(read_8bit(0x42,streamFile) == 0x54)) /* T */
{
@ -312,11 +287,11 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
loop_flag = 0;
}
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
/* fill in the vital statistics */
switch (musx_type) {
case 0x5053325F: /* PS2_ */
start_offset = 0x800;
@ -351,24 +326,24 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = 0x20;
vgmstream->meta_type = meta_MUSX_V010;
if (read_32bitBE(0x40,streamFile)==0x44415438){
if (read_32bitBE(0x40,streamFile)==0x44415438){
vgmstream->num_samples = read_32bitLE(0x60,streamFile);
vgmstream->sample_rate = read_32bitLE(0x4C,streamFile);
if (loop_flag)
vgmstream->sample_rate = read_32bitLE(0x4C,streamFile);
if (loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x64,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x60,streamFile);
}
}
else {
vgmstream->sample_rate = 44100;
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/(0x20)*((0x20-4)*2);
if (loop_flag)
}
else {
vgmstream->sample_rate = 44100;
vgmstream->num_samples = (get_streamfile_size(streamFile)-0x800)/2/(0x20)*((0x20-4)*2);
if (loop_flag)
{
vgmstream->loop_start_sample = read_32bitLE(0x44,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x40,streamFile);
}
}
}
break;
case 0x5749495F: /* WII_ */
start_offset = 0x800;
@ -377,7 +352,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
switch (read_32bitBE(0x40,streamFile))
{
case 0x44415434: /* DAT4 */
case 0x44415438: /* DAT8 */
case 0x44415438: /* DAT8 [GoldenEye 007 (Wii)] */
vgmstream->coding_type = coding_DAT4_IMA;
break;
default:
@ -406,7 +381,7 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
break;
default:
goto fail;
}
}
/* open the file for reading */
{
@ -426,79 +401,78 @@ VGMSTREAM * init_vgmstream_musx_v010(STREAMFILE *streamFile) {
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* <--------------------------------------- MUSX (Version 010) */
/* MUSX (Version 201) --------------------------------------->*/
/* MUSX (Version 201) */
VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
//int musx_version; /* 0x08 provides a "version" byte */
int loop_flag;
int channel_count;
int loop_detect;
int loop_offsets;
//int musx_version; /* 0x08 provides a "version" byte */
int loop_flag;
int channel_count;
int loop_detect;
int loop_offsets;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("musx",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
if ((read_32bitBE(0x08,streamFile) != 0xC9000000) &&
(read_32bitLE(0x08,streamFile) != 0xC9000000)) /* "0xC9000000" */
goto fail;
goto fail;
if ((read_32bitBE(0x08,streamFile) != 0xC9000000) &&
(read_32bitLE(0x08,streamFile) != 0xC9000000)) /* "0xC9000000" */
goto fail;
channel_count = 2;
loop_detect = read_32bitBE(0x800,streamFile);
switch (loop_detect) {
case 0x02000000:
loop_offsets = 0x8E0;
break;
case 0x03000000:
loop_offsets = 0x880;
break;
case 0x04000000:
loop_offsets = 0x8B4;
break;
case 0x05000000:
loop_offsets = 0x8E8;
break;
case 0x06000000:
loop_offsets = 0x91C;
break;
default:
goto fail;
}
loop_detect = read_32bitBE(0x800,streamFile);
switch (loop_detect) {
case 0x02000000:
loop_offsets = 0x8E0;
break;
case 0x03000000:
loop_offsets = 0x880;
break;
case 0x04000000:
loop_offsets = 0x8B4;
break;
case 0x05000000:
loop_offsets = 0x8E8;
break;
case 0x06000000:
loop_offsets = 0x91C;
break;
default:
goto fail;
}
loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000);
loop_flag = (read_32bitLE(loop_offsets+0x04,streamFile) !=0x00000000);
start_offset = read_32bitLE(0x18,streamFile);
/* build the VGMSTREAM */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = read_32bitLE(0x18,streamFile);
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count;
vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
vgmstream->meta_type = meta_MUSX_V201;
{
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_PSX;
vgmstream->num_samples = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(loop_offsets+0x10,streamFile)*28/16/channel_count;
vgmstream->loop_end_sample = read_32bitLE(loop_offsets,streamFile)*28/16/channel_count;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x80;
vgmstream->meta_type = meta_MUSX_V201;
}
/* open the file for reading */
{
int i;
@ -517,9 +491,7 @@ VGMSTREAM * init_vgmstream_musx_v201(STREAMFILE *streamFile) {
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}
/* <--------------------------------------- MUSX (Version 201) */

View File

@ -2,17 +2,19 @@
#include "meta.h"
#include "../util.h"
/* DTK - headerless Nintendo DTK file [Harvest Moon - Another Wonderful Life (GC), XGRA (GC)] */
VGMSTREAM * init_vgmstream_ngc_adpdtk(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset = 0;
int channel_count = 2, loop_flag = 0; /* always stereo, no loop */
/* check extension, case insensitive */
if ( !check_extensions(streamFile,"dtk,adp"))
/* checks */
/* dtk: standard [XGRA (GC)], adp: standard [Harvest Moon AWL (GC)], wav/lwav: Alien Hominid (GC) */
if ( !check_extensions(streamFile,"dtk,adp,wav,lwav"))
goto fail;
/* .adp files have no header, and the ext is common, so all we can do is look for valid first frames */
if (check_extensions(streamFile,"adp")) {
/* files have no header, and the ext is common, so all we can do is look for valid first frames */
if (check_extensions(streamFile,"adp,wav,lwav")) {
int i;
for (i = 0; i < 10; i++) { /* try a bunch of frames */
if (read_8bit(0x00 + i*0x20,streamFile) != read_8bit(0x02 + i*0x20,streamFile) ||

View File

@ -1,75 +0,0 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_caf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
// Calculate sample length ...
int32_t num_of_samples=0;
int32_t block_count=0;
uint32_t loop_start=-1;
off_t offset=0;
off_t next_block;
off_t file_length;
int i;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("cfn",filename_extension(filename))) goto fail;
/* Check "CAF " ID */
if (read_32bitBE(0,streamFile)!=0x43414620) goto fail;
// Calculate sample length ...
file_length=(off_t)get_streamfile_size(streamFile);
do {
next_block=read_32bitBE(offset+0x04,streamFile);
num_of_samples+=read_32bitBE(offset+0x14,streamFile)/8*14;
if(read_32bitBE(offset+0x20,streamFile)==read_32bitBE(offset+0x08,streamFile)) {
loop_start=num_of_samples-read_32bitBE(offset+0x14,streamFile)/8*14;
}
offset+=next_block;
block_count++;
} while(offset<file_length);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(2,(loop_start!=-1)); /* always stereo */
if (!vgmstream) goto fail;
vgmstream->channels=2;
vgmstream->sample_rate=32000;
vgmstream->num_samples=num_of_samples;
if(loop_start!=-1) {
vgmstream->loop_start_sample=loop_start;
vgmstream->loop_end_sample=num_of_samples;
}
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_caf_blocked;
vgmstream->meta_type = meta_CFN;
/* open the file for reading by each channel */
{
for (i=0;i<2;i++) {
vgmstream->ch[i].streamfile = streamFile->open(streamFile,filename,0x8000);
if (!vgmstream->ch[i].streamfile) goto fail;
}
}
caf_block_update(0,vgmstream);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -193,7 +193,8 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
/* check extension */
if (check_extensions(streamFile,"ogg,logg,adx")) { /* .ogg: standard/psychic, .logg: renamed for plugins, .adx: KID [Remember11 (PC)] */
/* .ogg: standard/psychic, .logg: renamed for plugins, .adx: KID [Remember11 (PC)], .rof: The Rhythm of Fighters (Mobile) */
if (check_extensions(streamFile,"ogg,logg,adx,rof")) {
is_ogg = 1;
} else if (check_extensions(streamFile,"um3")) {
is_um3 = 1;
@ -455,7 +456,7 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
vgmstream->loop_end_sample = vgmstream->num_samples;
}
vgmstream->coding_type = coding_ogg_vorbis;
vgmstream->coding_type = coding_OGG_VORBIS;
vgmstream->layout_type = vgm_inf->layout_type;
vgmstream->meta_type = vgm_inf->meta_type;

View File

@ -163,7 +163,7 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
#ifdef VGM_USE_VORBIS
case 0x6771: /* Ogg Vorbis (mode 3+) */
fmt->coding_type = coding_ogg_vorbis;
fmt->coding_type = coding_OGG_VORBIS;
break;
#else
goto fail;
@ -423,7 +423,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
#ifdef VGM_USE_VORBIS
/* special case using init_vgmstream_ogg_vorbis */
if (fmt.coding_type == coding_ogg_vorbis) {
if (fmt.coding_type == coding_OGG_VORBIS) {
return parse_riff_ogg(streamFile, start_offset, data_size);
}
#endif

View File

@ -1081,3 +1081,76 @@ fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}
/* RSD6AT3+ [Crash of the Titans (PSP)] */
VGMSTREAM * init_vgmstream_rsd6at3p(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"rsd"))
goto fail;
/* check header */
if (read_32bitBE(0x0, streamFile) != 0x52534436) /* "RSD6" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x4154332B) /* "AT3+" */
goto fail;
loop_flag = 0;
channel_count = read_32bitLE(0x8, streamFile);
start_offset = 0x800;
data_size = get_streamfile_size(streamFile) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_RSD6AT3P;
vgmstream->sample_rate = read_32bitLE(0x10, streamFile);
#ifdef VGM_USE_FFMPEG
{
ffmpeg_codec_data *ffmpeg_data = NULL;
/* full RIFF header at start_offset/post_meta_offset (same) */
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size);
if (!ffmpeg_data) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
if (channel_count != ffmpeg_data->channels) goto fail;
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
/* manually read skip_samples if FFmpeg didn't do it */
if (ffmpeg_data->skipSamples <= 0) {
off_t chunk_offset;
size_t chunk_size, fact_skip_samples = 0;
if (!find_chunk_le(streamFile, 0x66616374,start_offset+0xc,0, &chunk_offset,&chunk_size)) /* find "fact" */
goto fail;
if (chunk_size == 0x08) {
fact_skip_samples = read_32bitLE(chunk_offset+0x4, streamFile);
} else if (chunk_size == 0xc) {
fact_skip_samples = read_32bitLE(chunk_offset+0x8, streamFile);
}
ffmpeg_set_skip_samples(ffmpeg_data, fact_skip_samples);
}
#else
goto fail;
#endif
}
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -7,8 +7,8 @@ static STREAMFILE* setup_sead_hca_streamfile(STREAMFILE *streamFile, off_t subfi
/* SABF/MABF - Square Enix's "sead" audio games [Dragon Quest Builders (PS3), Dissidia Opera Omnia (mobile), FF XV (PS4)] */
VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, tables_offset, mtrl_offset, meta_offset, post_meta_offset; //, info_offset, name_offset = 0;
size_t stream_size, descriptor_size, subheader_size, special_size; //, name_size = 0;
off_t start_offset, tables_offset, mtrl_offset, meta_offset, extradata_offset; //, info_offset, name_offset = 0;
size_t stream_size, descriptor_size, extradata_size, special_size; //, name_size = 0;
int loop_flag = 0, channel_count, codec, sample_rate, loop_start, loop_end;
@ -118,12 +118,12 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
loop_start = read_32bit(meta_offset+0x0c,streamFile); /* in samples but usually ignored */
loop_end = read_32bit(meta_offset+0x10,streamFile);
subheader_size = read_32bit(meta_offset+0x14,streamFile); /* including subfile header */
extradata_size = read_32bit(meta_offset+0x14,streamFile); /* including subfile header, can be 0 */
stream_size = read_32bit(meta_offset+0x18,streamFile); /* not including subfile header */
special_size = read_32bit(meta_offset+0x1c,streamFile);
loop_flag = (loop_end > 0);
post_meta_offset = meta_offset + 0x20;
extradata_offset = meta_offset + 0x20;
/** info section (get stream name) **/
@ -155,19 +155,32 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
switch(codec) {
case 0x01: { /* PCM [Chrono Trigger sfx (PC)] */
start_offset = extradata_offset + extradata_size;
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, vgmstream->channels, 16);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
break;
}
case 0x02: { /* MSADPCM [Dragon Quest Builders (Vita) sfx] */
start_offset = post_meta_offset + subheader_size;
start_offset = extradata_offset + extradata_size;
/* 0x00 (2): null?, 0x02(2): entry size? */
vgmstream->coding_type = coding_MSADPCM;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = read_16bit(post_meta_offset+0x04,streamFile);
vgmstream->interleave_block_size = read_16bit(extradata_offset+0x04,streamFile);
/* much like AKBs, there are slightly different loop values here, probably more accurate
* (if no loop, loop_end doubles as num_samples) */
vgmstream->num_samples = msadpcm_bytes_to_samples(stream_size, vgmstream->interleave_block_size, vgmstream->channels);
vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x08, streamFile); //loop_start
vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x0c, streamFile); //loop_end
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x08, streamFile); //loop_start
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x0c, streamFile); //loop_end
break;
}
@ -175,7 +188,7 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
case 0x03: { /* OGG [Final Fantasy XV Benchmark sfx (PC)] */
VGMSTREAM *ogg_vgmstream = NULL;
vgm_vorbis_info_t inf = {0};
off_t subfile_offset = post_meta_offset + subheader_size;
off_t subfile_offset = extradata_offset + extradata_size;
char filename[PATH_LIMIT];
streamFile->get_name(streamFile,filename,sizeof(filename));
@ -206,21 +219,21 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
case 0x04: { /* ATRAC9 [Dragon Quest Builders (Vita), Final Fantaxy XV (PS4)] */
atrac9_config cfg = {0};
start_offset = post_meta_offset + subheader_size;
start_offset = extradata_offset + extradata_size;
/* post header has various typical ATRAC9 values */
cfg.channels = vgmstream->channels;
cfg.config_data = read_32bit(post_meta_offset+0x0c,streamFile);
cfg.encoder_delay = read_32bit(post_meta_offset+0x18,streamFile);
cfg.config_data = read_32bit(extradata_offset+0x0c,streamFile);
cfg.encoder_delay = read_32bit(extradata_offset+0x18,streamFile);
vgmstream->codec_data = init_atrac9(&cfg);
if (!vgmstream->codec_data) goto fail;
vgmstream->coding_type = coding_ATRAC9;
vgmstream->layout_type = layout_none;
vgmstream->sample_rate = read_32bit(post_meta_offset+0x1c,streamFile); /* SAB's sample rate can be different but it's ignored */
vgmstream->num_samples = read_32bit(post_meta_offset+0x10,streamFile); /* loop values above are also weird and ignored */
vgmstream->loop_start_sample = read_32bit(post_meta_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
vgmstream->loop_end_sample = read_32bit(post_meta_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
vgmstream->sample_rate = read_32bit(extradata_offset+0x1c,streamFile); /* SAB's sample rate can be different but it's ignored */
vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
break;
}
#endif
@ -230,7 +243,7 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
mpeg_codec_data *mpeg_data = NULL;
mpeg_custom_config cfg = {0};
start_offset = post_meta_offset + subheader_size;
start_offset = extradata_offset + extradata_size;
/* post header is a proper MSF, but sample rate/loops are ignored in favor of SAB's */
mpeg_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_STANDARD, &cfg);
@ -249,13 +262,13 @@ VGMSTREAM * init_vgmstream_sqex_sead(STREAMFILE * streamFile) {
//todo there is no easy way to use the HCA decoder; try subfile hack for now
VGMSTREAM *temp_vgmstream = NULL;
STREAMFILE *temp_streamFile = NULL;
off_t subfile_offset = post_meta_offset + 0x10;
size_t subfile_size = stream_size + subheader_size - 0x10;
off_t subfile_offset = extradata_offset + 0x10;
size_t subfile_size = stream_size + extradata_size - 0x10;
/* post header: values from the HCA header, in file endianness + HCA header */
size_t key_start = special_size & 0xff;
size_t header_size = read_16bit(post_meta_offset+0x02, streamFile);
int encryption = read_16bit(post_meta_offset+0x0c, streamFile); //maybe 8bit?
size_t header_size = read_16bit(extradata_offset+0x02, streamFile);
int encryption = read_16bit(extradata_offset+0x0c, streamFile); //maybe 8bit?
/* encryption type 0x01 found in Final Fantasy XII TZA (PS4/PC) */
temp_streamFile = setup_sead_hca_streamfile(streamFile, subfile_offset, subfile_size, encryption, header_size, key_start);

108
src/meta/wave.c Normal file
View File

@ -0,0 +1,108 @@
#include "meta.h"
#include "../coding/coding.h"
/* .WAVE - WayForward "EngineBlack" games [Mighty Switch Force! (3DS), Adventure Time: Hey Ice King! Why'd You Steal Our Garbage?! (3DS)] */
VGMSTREAM * init_vgmstream_wave(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, extradata_offset;
int loop_flag = 0, channel_count, sample_rate, codec;
int32_t num_samples, loop_start = 0, loop_end = 0;
size_t interleave;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
//int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "wave"))
goto fail;
if (read_32bitLE(0x00,streamFile) != 0xE5B7ECFE && /* header id */
read_32bitBE(0x00,streamFile) != 0xE5B7ECFE)
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x00) /* version? */
goto fail;
/* assumed */
big_endian = read_32bitBE(0x00,streamFile) == 0xE5B7ECFE;
if (big_endian) {
read_32bit = read_32bitBE;
//read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
//read_16bit = read_16bitLE;
}
channel_count = read_8bit(0x05,streamFile);
if (read_32bit(0x08,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_8bit(0x0c,streamFile) != 0x00) /* ? */
goto fail;
/* sample rate in 32b float (WHY?)*/
{
uint32_t sample_int = (uint32_t)read_32bit(0x0c, streamFile);
float* sample_float;
sample_float = (float*)&sample_int;
sample_rate = (int)(*sample_float);
}
num_samples = read_32bit(0x10, streamFile);
loop_start = read_32bit(0x14, streamFile);
loop_end = read_32bit(0x18, streamFile);
codec = read_8bit(0x1c, streamFile);
channel_count = read_8bit(0x1d, streamFile);
if (read_8bit(0x1e, streamFile) != 0x00) goto fail; /* unknown */
if (read_8bit(0x1f, streamFile) != 0x00) goto fail; /* unknown */
start_offset = read_32bit(0x20, streamFile);
interleave = read_32bit(0x24, streamFile); /* typically half data_size */
extradata_offset = read_32bit(0x28, streamFile); /* OR: extradata size (0x2c) */
loop_flag = (loop_start > 0);
/* some songs (ex. Adventure Time's m_candykingdom_overworld.wave) do full loops, but there is no way
* to tell them apart from sfx/voices, so we try to detect if it's long enough. */
if(!loop_flag
&& loop_start == 0 && loop_end == num_samples /* full loop */
&& channel_count > 1
&& num_samples > 20*sample_rate) { /* in seconds */
loop_flag = 1;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->meta_type = meta_WAVE;
/* not sure if there are other codecs but anyway */
switch(codec) {
case 0x02:
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
/* ADPCM setup: 0x20 coefs + 0x06 initial ps/hist1/hist2 + 0x06 loop ps/hist1/hist2, per channel */
dsp_read_coefs(vgmstream, streamFile, extradata_offset+0x00, 0x2c, big_endian);
dsp_read_hist(vgmstream, streamFile, extradata_offset+0x22, 0x2c, big_endian);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

222
src/meta/wave_segmented.c Normal file
View File

@ -0,0 +1,222 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../layout/layout.h"
#define MAX_SEGMENTS 4
/* .WAVE - WayForward "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t segments_offset;
int loop_flag = 0, channel_count, sample_rate;
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
segmented_layout_data *data = NULL;
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
/* checks */
if (!check_extensions(streamFile, "wave"))
goto fail;
if (read_32bitLE(0x00,streamFile) != 0x4DF72D4A && /* header id */
read_32bitBE(0x00,streamFile) != 0x4DF72D4A)
goto fail;
if (read_8bit(0x04,streamFile) != 0x01) /* version? */
goto fail;
/* PS3/X360 games */
big_endian = read_32bitBE(0x00,streamFile) == 0x4DF72D4A;
if (big_endian) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
} else {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
}
channel_count = read_8bit(0x05,streamFile);
segment_count = read_16bit(0x06,streamFile);
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
loop_start_segment = read_16bit(0x08, streamFile);
loop_end_segment = read_16bit(0x0a, streamFile);
segments_offset = read_32bit(0x0c, streamFile);
sample_rate = read_32bit(0x10, streamFile);
num_samples = read_32bit(0x14, streamFile);
/* 0x18: unknown (usually 0, maybe some count) */
/* init layout */
data = init_layout_segmented(segment_count);
if (!data) goto fail;
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
{
off_t extradata_offset, table_offset, segment_offset;
size_t segment_size;
int32_t segment_samples;
int codec;
int i, ch;
/* open each segment subfile */
for (i = 0; i < segment_count; i++) {
codec = read_8bit(segments_offset+0x10*i+0x00, streamFile);
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
if (read_8bit(segments_offset+0x10*i+0x02, streamFile) != 0x01) goto fail; /* unknown */
if (read_8bit(segments_offset+0x10*i+0x03, streamFile) != 0x00) goto fail; /* unknown */
segment_samples = read_32bit(segments_offset+0x10*i+0x04, streamFile);
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, streamFile);
table_offset = read_32bit(segments_offset+0x10*i+0x0c, streamFile);
/* create a sub-VGMSTREAM per segment
* (we'll reopen this streamFile as needed, so each sub-VGMSTREAM is fully independent) */
switch(codec) {
case 0x02: { /* "adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_IMA_int;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
/* ADPCM setup */
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, streamFile);
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, streamFile);
/* 0x03: reserved */
}
break;
}
case 0x03: { /* "dsp-adpcm" */
data->segments[i] = allocate_vgmstream(channel_count, 0);
if (!data->segments[i]) goto fail;
data->segments[i]->sample_rate = sample_rate;
data->segments[i]->meta_type = meta_WAVE;
data->segments[i]->coding_type = coding_NGC_DSP;
data->segments[i]->layout_type = layout_none;
data->segments[i]->num_samples = segment_samples;
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
goto fail;
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
for (ch = 0; ch < channel_count; ch++) {
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
data->segments[i]->ch[ch].channel_start_offset =
data->segments[i]->ch[ch].offset = segment_offset;
}
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
dsp_read_hist(data->segments[i], streamFile, extradata_offset+0x02, 0x06, big_endian);
dsp_read_coefs(data->segments[i], streamFile, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
break;
}
case 0x04: { /* "vorbis" */
char filename[PATH_LIMIT];
vgm_vorbis_info_t ovi = {0};
segment_offset = read_32bit(table_offset, streamFile);
segment_size = read_32bitBE(segment_offset, streamFile); /* always BE */
ovi.layout_type = layout_ogg_vorbis;
ovi.meta_type = meta_WAVE;
ovi.stream_size = segment_size;
streamFile->get_name(streamFile,filename,sizeof(filename));
data->segments[i] = init_vgmstream_ogg_vorbis_callbacks(streamFile, filename, NULL, segment_offset+0x04, &ovi);
if (!data->segments[i]) goto fail;
if (data->segments[i]->num_samples != segment_samples) {
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
goto fail;
}
break;
}
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
VGM_LOG("WAVE: unknown codec\n");
goto fail;
}
}
}
/* setup segmented VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
/* parse samples */
{
int32_t sample_count = 0;
int i;
loop_flag = (loop_start_segment > 0);
for (i = 0; i < segment_count; i++) {
if (loop_flag && loop_start_segment == i) {
loop_start_sample = sample_count;
}
sample_count += data->segments[i]->num_samples;
if (loop_flag && loop_end_segment-1 == i) {
loop_end_sample = sample_count;
}
}
if (sample_count != num_samples) {
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
goto fail;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start_sample;
vgmstream->loop_end_sample = loop_end_sample;
vgmstream->meta_type = meta_WAVE_segmented;
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
if (loop_flag)
data->loop_segment = (loop_start_segment);
return vgmstream;
fail:
free_layout_segmented(data);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -44,7 +44,7 @@ typedef struct {
uint32_t base_flags;
size_t entry_elem_size;
size_t entry_alignment;
int streams;
int total_subsongs;
uint32_t entry_flags;
uint32_t format;
@ -63,27 +63,25 @@ typedef struct {
uint32_t loop_end_sample;
} xwb_header;
static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamFile);
static void get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile);
/* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */
VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, off, suboff;
xwb_header xwb;
int target_stream = streamFile->stream_index;
xwb_header xwb = {0};
int target_subsong = streamFile->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
/* basic checks */
if (!check_extensions(streamFile,"xwb")) goto fail;
/* checks */
if (!check_extensions(streamFile,"xwb"))
goto fail;
if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */
(read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */
goto fail;
memset(&xwb,0,sizeof(xwb_header));
xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44;/* WBND */
if (xwb.little_endian) {
read_32bit = read_32bitLE;
@ -101,11 +99,11 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read segment offsets (SEGIDX) */
if (xwb.version <= XACT1_0_MAX) {
xwb.streams = read_32bit(0x0c, streamFile);
xwb.total_subsongs = read_32bit(0x0c, streamFile);
/* 0x10: bank name */
xwb.entry_elem_size = 0x14;
xwb.entry_offset= 0x50;
xwb.entry_size = xwb.entry_elem_size * xwb.streams;
xwb.entry_size = xwb.entry_elem_size * xwb.total_subsongs;
xwb.data_offset = xwb.entry_offset + xwb.entry_size;
xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset;
}
@ -128,7 +126,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read base entry (WAVEBANKDATA) */
off = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.streams = read_32bit(off+0x04, streamFile);
xwb.total_subsongs = read_32bit(off+0x04, streamFile);
/* 0x08 bank_name */
suboff = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile);
@ -138,26 +136,32 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* suboff+0x10: build time 64b (XACT2/3) */
}
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */
if (target_stream < 0 || target_stream > xwb.streams || xwb.streams < 1) goto fail;
if (target_subsong == 0) target_subsong = 1; /* auto: default to 1 */
if (target_subsong < 0 || target_subsong > xwb.total_subsongs || xwb.total_subsongs < 1) goto fail;
/* read stream entry (WAVEBANKENTRY) */
off = xwb.entry_offset + (target_stream-1) * xwb.entry_elem_size;
off = xwb.entry_offset + (target_subsong-1) * xwb.entry_elem_size;
if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry */
/* offset_in_sectors:21 and sector_alignment_in_bytes:11 */
uint32_t entry = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.stream_offset = xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF);
if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry [NFL Fever 2004 demo from Amped 2 (Xbox)] */
uint32_t entry, size_deviation, sector_offset;
off_t next_stream_offset;
/* find size (up to next entry or data end) */
if (xwb.streams > 1) {
entry = (uint32_t)read_32bit(off+xwb.entry_size, streamFile);
xwb.stream_size = xwb.stream_offset -
(xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF));
} else {
xwb.stream_size = xwb.data_size;
entry = (uint32_t)read_32bit(off+0x00, streamFile);
size_deviation = ((entry >> 21) & 0x7FF); /* 11b, padding data for sector alignment in bytes*/
sector_offset = (entry & 0x1FFFFF); /* 21b, offset within data in sectors */
xwb.stream_offset = xwb.data_offset + sector_offset*xwb.entry_alignment;
/* find size using next offset */
if (target_subsong < xwb.total_subsongs) {
uint32_t next_entry = (uint32_t)read_32bit(off+0x04, streamFile);
next_stream_offset = xwb.data_offset + (next_entry & 0x1FFFFF)*xwb.entry_alignment;
}
else { /* for last entry (or first, when subsongs = 1) */
next_stream_offset = xwb.data_offset + xwb.data_size;
}
xwb.stream_size = next_stream_offset - xwb.stream_offset - size_deviation;
}
else if (xwb.version <= XACT1_0_MAX) {
xwb.format = (uint32_t)read_32bit(off+0x00, streamFile);
@ -353,10 +357,10 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->num_samples = xwb.num_samples;
vgmstream->loop_start_sample = xwb.loop_start_sample;
vgmstream->loop_end_sample = xwb.loop_end_sample;
vgmstream->num_streams = xwb.streams;
vgmstream->num_streams = xwb.total_subsongs;
vgmstream->stream_size = xwb.stream_size;
vgmstream->meta_type = meta_XWB;
get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_stream, &xwb, streamFile);
get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, streamFile);
switch(xwb.codec) {
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
@ -535,7 +539,7 @@ typedef struct {
/* try to find the stream name in a companion XSB file, a comically complex cue format. */
static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamXwb) {
static void get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamXwb) {
STREAMFILE *streamFile = NULL;
int i,j, start_sound, cfg__start_sound = 0, cfg__selected_wavebank = 0;
int xsb_version;
@ -609,8 +613,8 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
xsb.xsb_sounds_offset = read_32bit(0x46, streamFile);
}
VGM_ASSERT(xsb.xsb_sounds_count < xwb->streams,
"XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->streams);
VGM_ASSERT(xsb.xsb_sounds_count < xwb->total_subsongs,
"XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->total_subsongs);
VGM_ASSERT(xsb.xsb_simple_sounds_count + xsb.xsb_complex_sounds_count != xsb.xsb_sounds_count,
"XSB: number of xsb sounds doesn't match simple + complex sounds (simple %i, complex %i, total %i)\n", xsb.xsb_simple_sounds_count, xsb.xsb_complex_sounds_count, xsb.xsb_sounds_count);
@ -747,7 +751,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
//CHECK_EXIT(w->sound_count == 0, "ERROR: xsb wavebank %i has no sounds", i); //Ikaruga PC
if (w->sound_count == xwb->streams) {
if (w->sound_count == xwb->total_subsongs) {
if (!cfg__selected_wavebank) {
VGM_LOG("XSB: multiple xsb wavebanks with the same number of sounds, use -w to specify one of the wavebanks\n");
goto fail;
@ -773,22 +777,22 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
}
if (cfg__start_sound) {
if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->streams) {
VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->streams + 1);
if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->total_subsongs) {
VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->total_subsongs + 1);
goto fail;
}
} else {
/*
if (!cfg->ignore_names_not_found)
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
if (!cfg->ignore_names_not_found)
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
*/
//if (!cfg->ignore_names_not_found)
// CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count);
// CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
}
/* *************************** */
@ -799,7 +803,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
for (i = start_sound; i < xsb.xsb_sounds_count; i++) {
xsb_sound *s = &(xsb.xsb_sounds[i]);
if (s->wavebank == cfg__selected_wavebank-1
&& s->stream_index == target_stream-1){
&& s->stream_index == target_subsong-1){
name_offset = s->name_offset;
break;
}

View File

@ -380,6 +380,9 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
init_vgmstream_atx,
init_vgmstream_sqex_sead,
init_vgmstream_waf,
init_vgmstream_wave,
init_vgmstream_wave_segmented,
init_vgmstream_rsd6at3p,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG
@ -503,7 +506,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
* really hit the loop start. */
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
if (vgmstream->coding_type==coding_OGG_VORBIS) {
reset_ogg_vorbis(vgmstream);
}
@ -570,10 +573,11 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
if (vgmstream->coding_type==coding_ACM) {
mus_acm_codec_data *data = vgmstream->codec_data;
int i;
data->current_file = 0;
for (i=0;i<data->file_count;i++) {
acm_reset(data->files[i]);
if (data) {
data->current_file = 0;
for (i=0;i<data->file_count;i++) {
acm_reset(data->files[i]);
}
}
}
@ -586,7 +590,8 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
vgmstream->coding_type == coding_NWA5
) {
nwa_codec_data *data = vgmstream->codec_data;
reset_nwa(data->nwa);
if (data)
reset_nwa(data->nwa);
}
@ -600,14 +605,8 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
}
}
if (vgmstream->layout_type==layout_aax) {
aax_codec_data *data = vgmstream->codec_data;
int i;
data->current_segment = 0;
for (i=0;i<data->segment_count;i++) {
reset_vgmstream(data->adxs[i]);
}
if (vgmstream->layout_type==layout_segmented) {
reset_layout_segmented(vgmstream->layout_data);
}
if (vgmstream->layout_type==layout_scd_int) {
@ -689,7 +688,7 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
return;
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
if (vgmstream->coding_type==coding_OGG_VORBIS) {
free_ogg_vorbis(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
@ -824,25 +823,8 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
vgmstream->codec_data = NULL;
}
if (vgmstream->layout_type==layout_aax) {
aax_codec_data *data = (aax_codec_data *) vgmstream->codec_data;
if (data) {
if (data->adxs) {
int i;
for (i=0;i<data->segment_count;i++) {
/* note that the close_streamfile won't do anything but deallocate itself,
* there is only one open file in vgmstream->ch[0].streamfile */
close_vgmstream(data->adxs[i]);
}
free(data->adxs);
}
if (data->sample_counts) {
free(data->sample_counts);
}
free(data);
}
if (vgmstream->layout_type==layout_segmented) {
free_layout_segmented(vgmstream->layout_data);
vgmstream->codec_data = NULL;
}
@ -956,7 +938,7 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_xa_blocked:
case layout_blocked_ea_schl:
case layout_blocked_ea_1snh:
case layout_caf_blocked:
case layout_blocked_caf:
case layout_wsi_blocked:
case layout_str_snds_blocked:
case layout_ws_aud_blocked:
@ -992,8 +974,8 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_aix:
render_vgmstream_aix(buffer,sample_count,vgmstream);
break;
case layout_aax:
render_vgmstream_aax(buffer,sample_count,vgmstream);
case layout_segmented:
render_vgmstream_segmented(buffer,sample_count,vgmstream);
break;
case layout_scd_int:
render_vgmstream_scd_int(buffer,sample_count,vgmstream);
@ -1038,7 +1020,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_PCMFLOAT:
return 1;
#ifdef VGM_USE_VORBIS
case coding_ogg_vorbis:
case coding_OGG_VORBIS:
case coding_VORBIS_custom:
#endif
#ifdef VGM_USE_MPEG
@ -1636,7 +1618,7 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
}
break;
#ifdef VGM_USE_VORBIS
case coding_ogg_vorbis:
case coding_OGG_VORBIS:
decode_ogg_vorbis(vgmstream->codec_data,
buffer+samples_written*vgmstream->channels,samples_to_do,
vgmstream->channels);
@ -2019,7 +2001,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
if (vgmstream->coding_type==coding_OGG_VORBIS) {
seek_ogg_vorbis(vgmstream, vgmstream->loop_sample);
}
@ -2070,7 +2052,8 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
vgmstream->coding_type == coding_NWA5)
{
nwa_codec_data *data = vgmstream->codec_data;
seek_nwa(data->nwa, vgmstream->loop_sample);
if (data)
seek_nwa(data->nwa, vgmstream->loop_sample);
}
/* restore! */
@ -2429,7 +2412,7 @@ static int get_vgmstream_average_bitrate_channel_count(VGMSTREAM * vgmstream)
return (data) ? data->substream_count : 0;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
if (vgmstream->coding_type==coding_OGG_VORBIS) {
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data;
return (data) ? 1 : 0;
}
@ -2463,7 +2446,7 @@ static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM *
return data->intfiles[channel];
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_ogg_vorbis) {
if (vgmstream->coding_type==coding_OGG_VORBIS) {
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data;
return data->ov_streamfile.streamfile;
}
@ -2503,10 +2486,10 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
int bitrate = 0;
int sample_rate = vgmstream->sample_rate;
int length_samples = vgmstream->num_samples;
int channels = get_vgmstream_average_bitrate_channel_count(vgmstream);
int channels;
STREAMFILE * streamFile;
if (!sample_rate || !channels || !length_samples)
if (!sample_rate || !length_samples)
return 0;
/* subsongs need to report this to properly calculate */
@ -2514,6 +2497,16 @@ int get_vgmstream_average_bitrate(VGMSTREAM * vgmstream) {
return get_vgmstream_average_bitrate_from_size(vgmstream->stream_size, sample_rate, length_samples);
}
/* segmented layout is handled differently as it has multiple sub-VGMSTREAMs (may include special codecs) */
//todo not correct with multifile segments (ex. .ACM Ogg)
if (vgmstream->layout_type==layout_segmented) {
segmented_layout_data *data = (segmented_layout_data *) vgmstream->layout_data;
return get_vgmstream_average_bitrate(data->segments[0]);
}
channels = get_vgmstream_average_bitrate_channel_count(vgmstream);
if (!channels) return 0;
if (channels >= 1) {
streamFile = get_vgmstream_average_bitrate_channel_streamfile(vgmstream, 0);
if (streamFile) {
@ -2557,9 +2550,9 @@ int vgmstream_open_stream(VGMSTREAM * vgmstream, STREAMFILE *streamFile, off_t s
int use_same_offset_per_channel = 0;
/* stream/offsets not needed, manages themselves */
/* stream/offsets not needed, manage themselves */
if (vgmstream->layout_type == layout_aix ||
vgmstream->layout_type == layout_aax ||
vgmstream->layout_type == layout_segmented ||
vgmstream->layout_type == layout_scd_int)
return 1;

View File

@ -152,7 +152,7 @@ typedef enum {
coding_MTAF, /* Konami MTAF ADPCM */
coding_MTA2, /* Konami MTA2 ADPCM */
coding_MC3, /* Paradigm MC3 3-bit ADPCM */
coding_FADPCM, /* FMOD FADPCM 4-bit ADCPM */
coding_FADPCM, /* FMOD FADPCM 4-bit ADPCM */
/* others */
coding_SDX2, /* SDX2 2:1 Squareroot-Delta-Exact compression DPCM */
@ -172,7 +172,7 @@ typedef enum {
coding_CRI_HCA, /* CRI High Compression Audio (MDCT-based) */
#ifdef VGM_USE_VORBIS
coding_ogg_vorbis, /* Xiph Vorbis with Ogg layer (MDCT-based) */
coding_OGG_VORBIS, /* Xiph Vorbis with Ogg layer (MDCT-based) */
coding_VORBIS_custom, /* Xiph Vorbis with custom layer (MDCT-based) */
#endif
@ -225,7 +225,7 @@ typedef enum {
layout_xa_blocked,
layout_blocked_ea_schl,
layout_blocked_ea_1snh,
layout_caf_blocked,
layout_blocked_caf,
layout_wsi_blocked,
layout_str_snds_blocked,
layout_ws_aud_blocked,
@ -258,7 +258,7 @@ typedef enum {
layout_acm, /* libacm layout */
layout_mus_acm, /* mus has multi-files to deal with */
layout_aix, /* CRI AIX's wheels within wheels */
layout_aax, /* CRI AAX's wheels within databases */
layout_segmented, /* song divided in segments, each a complete VGMSTREAM */
layout_scd_int, /* deinterleave done by the SCDINTSTREAMFILE */
#ifdef VGM_USE_VORBIS
@ -319,7 +319,7 @@ typedef enum {
meta_RSF, /* Retro Studios RSF (Metroid Prime .rsf) [no header_id] */
meta_HALPST, /* HAL Labs HALPST */
meta_GCSW, /* GCSW (PCM) */
meta_CFN, /* Namco CAF Audio File */
meta_CAF, /* tri-Crescendo CAF */
meta_MYSPD, /* U-Sing .myspd */
meta_HIS, /* Her Ineractive .his */
meta_BNSF, /* Bandai Namco Sound Format */
@ -434,6 +434,7 @@ typedef enum {
meta_RSD6RADP, /* RSD6RADP */
meta_RSD6OOGV, /* RSD6OOGV */
meta_RSD6XMA, /* RSD6XMA */
meta_RSD6AT3P, /* RSD6AT3+ */
meta_PS2_ASS, /* ASS */
meta_PS2_SEG, /* Eragon */
@ -662,6 +663,8 @@ typedef enum {
meta_SQEX_MAB, /* Square-Enix newest middleware (music) */
meta_OGG_L2SD, /* Ogg Vorbis with obfuscation [Lineage II Chronicle 4 (PC)] */
meta_WAF, /* KID WAF [Ever 17 (PC)] */
meta_WAVE, /* WayForward "EngineBlack" games [Mighty Switch Force! (3DS)] */
meta_WAVE_segmented, /* WayForward "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC)] */
#ifdef VGM_USE_MP4V2
meta_MP4, /* AAC (iOS) */
@ -797,6 +800,10 @@ typedef struct {
* Note also that support must be added for resetting, looping and
* closing for every codec that uses this, as it will not be handled. */
void * codec_data;
/* Same, for special layouts.
* Reusing the above pointer causes bugs when it's using special layout + codec
* (vgmstream may try to free/loop/etc codec_data). */
void * layout_data;
} VGMSTREAM;
#ifdef VGM_USE_VORBIS
@ -1065,14 +1072,13 @@ typedef struct {
VGMSTREAM **adxs;
} aix_codec_data;
/* for files made of segments, each a full subfile (VGMSTREAM) */
typedef struct {
int segment_count;
int current_segment;
int loop_segment;
/* one per segment */
int32_t *sample_counts;
VGMSTREAM **adxs;
} aax_codec_data;
VGMSTREAM **segments;
} segmented_layout_data;
/* for compressed NWA */
typedef struct {