mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-15 02:57:38 +01:00
Merge pull request #203 from bnnm/segments-wave-misc
Segments, WAVE, misc
This commit is contained in:
commit
95d9a7f566
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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). */
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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++)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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"},
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
21
src/layout/blocked_caf.c
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
140
src/layout/segmented.c
Normal 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]);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
756
src/meta/aax.c
756
src/meta/aax.c
@ -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;
|
||||
}
|
||||
|
@ -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
442
src/meta/aax_utf.h
Normal 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
65
src/meta/caf.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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*/
|
||||
|
468
src/meta/musx.c
468
src/meta/musx.c
@ -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) */
|
||||
|
@ -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) ||
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
108
src/meta/wave.c
Normal 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
222
src/meta/wave_segmented.c
Normal 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;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user