Merge pull request #204 from bnnm/acm-caff

ACM, CAFF
This commit is contained in:
Christopher Snowhill 2018-03-17 14:06:14 -07:00 committed by GitHub
commit ee26f6ca53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 429 additions and 528 deletions

View File

@ -205,9 +205,10 @@ are used in few games.
- SDX2 2:1 Squareroot-Delta-Exact compression DPCM
- CBD2 2:1 Cuberoot-Delta-Exact compression DPCM
- InterPlay ACM
- Visual Art's NWA
- VisualArt's NWA
- CRI HCA
- Electronic Arts MicroTalk a.k.a. UTK or UMT
- FMOD FADPCM 4-bit ADPCM
- Xiph Vorbis (Ogg, FSB5, Wwise, OGL, Silicon Knights)
- MPEG MP1/2/3 (standard, AHX, XVAG, FSB, AWC, P3D, etc)
- ITU-T G.722.1 (Polycom Siren 7)

View File

@ -817,23 +817,65 @@ void acm_reset(ACMStream *acm)
memset(acm->wrapbuf, 0, acm->wrapbuf_len * sizeof(int));
}
/* interface to vgmstream */
void decode_acm(ACMStream * acm, sample * outbuf,
int32_t samples_to_do, int channelspacing) {
/***********************************************
* interface to vgmstream
***********************************************/
acm_codec_data *init_acm(STREAMFILE *streamFile) {
acm_codec_data* data = NULL;
ACMStream *acm_stream = NULL;
char filename[PATH_LIMIT];
data = calloc(1,sizeof(acm_codec_data));
if (!data) goto fail;
streamFile->get_name(streamFile,filename,sizeof(filename));
if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK)
goto fail;
data->file = acm_stream;
return data;
fail:
free_acm(data);
return NULL;
}
void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing) {
ACMStream * acm = data->file;
int32_t samples_read = 0;
while (samples_read < samples_to_do) {
int32_t bytes_read_just_now;
bytes_read_just_now =
acm_read(acm,(char*)(
outbuf+samples_read*channelspacing),
(samples_to_do-samples_read)*sizeof(sample)*
channelspacing,0,2,1);
int32_t bytes_read_just_now = acm_read(
acm,
(char*)(outbuf+samples_read*channelspacing),
(samples_to_do-samples_read)*sizeof(sample)*channelspacing,
0,2,1);
if (bytes_read_just_now > 0) {
samples_read +=
bytes_read_just_now/sizeof(sample)/channelspacing;
samples_read += bytes_read_just_now/sizeof(sample)/channelspacing;
} else {
return;
}
}
}
void reset_acm(VGMSTREAM *vgmstream) {
acm_codec_data *data = vgmstream->codec_data;
if (data && data->file) {
acm_reset(data->file);
}
}
void free_acm(acm_codec_data *data) {
if (data) {
if (data->file) {
acm_close(data->file);
}
free(data);
}
}

View File

@ -36,6 +36,7 @@ size_t ima_bytes_to_samples(size_t bytes, int channels);
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
size_t xbox_ima_bytes_to_samples(size_t bytes, int channels);
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset);
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels);
/* ngc_dsp_decoder */
void decode_ngc_dsp(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
@ -102,7 +103,10 @@ void decode_cbd2_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
void decode_ws(VGMSTREAM * vgmstream, int channel, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
/* acm_decoder */
void decode_acm(ACMStream * acm, sample * outbuf, int32_t samples_to_do, int channelspacing);
acm_codec_data *init_acm();
void decode_acm(acm_codec_data *data, sample * outbuf, int32_t samples_to_do, int channelspacing);
void reset_acm(VGMSTREAM *vgmstream);
void free_acm(acm_codec_data *data);
/* nwa_decoder */
void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do);

View File

@ -867,6 +867,12 @@ size_t xbox_ima_bytes_to_samples(size_t bytes, int channels) {
+ ((bytes % block_align) ? ((bytes % block_align) - 4 * channels) * 2 / channels : 0); /* unlikely (encoder aligns) */
}
size_t apple_ima4_bytes_to_samples(size_t bytes, int channels) {
int block_align = 0x22 * channels;
return (bytes / block_align) * (block_align - 0x02*channels) * 2 / channels
+ ((bytes % block_align) ? ((bytes % block_align) - 0x02*channels) * 2 / channels : 0);
}
size_t ubi_ima_bytes_to_samples(size_t bytes, int channels, STREAMFILE *streamFile, off_t offset) {
int version, big_endian, header_samples;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;

View File

@ -197,6 +197,7 @@ static const char* extension_list[] = {
"mpdsp",
"mpds",
"msa",
"msd",
"msf",
"mss",
"msvp",
@ -509,12 +510,7 @@ static const coding_info coding_info_list[] = {
{coding_CBD2, "Cuberoot-delta-exact (CBD2) 8-bit DPCM"},
{coding_CBD2_int, "Cuberoot-delta-exact (CBD2) 8-bit DPCM with 1 byte interleave"},
{coding_ACM, "InterPlay ACM"},
{coding_NWA0, "NWA DPCM Level 0"},
{coding_NWA1, "NWA DPCM Level 1"},
{coding_NWA2, "NWA DPCM Level 2"},
{coding_NWA3, "NWA DPCM Level 3"},
{coding_NWA4, "NWA DPCM Level 4"},
{coding_NWA5, "NWA DPCM Level 5"},
{coding_NWA, "VisualArt's NWA DPCM"},
{coding_EA_MT, "Electronic Arts MicroTalk"},
@ -581,8 +577,6 @@ static const layout_info layout_info_list[] = {
{layout_blocked_rws, "blocked (RWS)"},
{layout_blocked_hwas, "blocked (HWAS)"},
{layout_tra_blocked, "TRA blocked"},
{layout_acm, "ACM blocked"},
{layout_mus_acm, "multiple ACM files, ACM blocked"},
{layout_aix, "AIX interleave, internally 18-byte interleaved"},
{layout_segmented, "segmented"},
{layout_scd_int, "SCD multistream interleave"},
@ -669,9 +663,9 @@ static const meta_info meta_info_list[] = {
{meta_PS2_SVS, "Square SVS header"},
{meta_RIFF_WAVE, "RIFF WAVE header"},
{meta_RIFF_WAVE_POS, "RIFF WAVE header and .pos for looping"},
{meta_NWA, "Visual Art's NWA header"},
{meta_NWA_NWAINFOINI, "Visual Art's NWA header and NWAINFO.INI for looping"},
{meta_NWA_GAMEEXEINI, "Visual Art's NWA header and Gameexe.ini for looping"},
{meta_NWA, "VisualArt's NWA header"},
{meta_NWA_NWAINFOINI, "VisualArt's NWA header (NWAINFO.INI looping)"},
{meta_NWA_GAMEEXEINI, "VisualArt's NWA header (Gameexe.ini looping)"},
{meta_XSS, "Dino Crisis 3 XSS File"},
{meta_HGC1, "Knights of the Temple 2 hgC1 Header"},
{meta_AUS, "Capcom AUS Header"},
@ -701,7 +695,7 @@ static const meta_info meta_info_list[] = {
{meta_BG00, "Falcom BG00 Header"},
{meta_PS2_RSTM, "Rockstar Games RSTM Header"},
{meta_ACM, "InterPlay ACM Header"},
{meta_MUS_ACM, "MUS playlist and multiple InterPlay ACM Headered files"},
{meta_MUS_ACM, "InterPlay MUS ACM header"},
{meta_PS2_KCES, "Konami KCES Header"},
{meta_PS2_DXH, "Tokobot Plus DXH Header"},
{meta_PS2_PSH, "Dawn of Mana - Seiken Densetsu 4 PSH Header"},
@ -813,7 +807,7 @@ static const meta_info meta_info_list[] = {
{meta_NGC_GCUB, "GCub Header"},
{meta_NGC_SCK_DSP, "The Scorpion King SCK Header"},
{meta_NGC_SWD, "PSF + Standard DSP Headers"},
{meta_CAFF, "Apple Core Audio Format Header"},
{meta_CAFF, "Apple Core Audio Format File header"},
{meta_PC_MXST, "Lego Island MxSt Header"},
{meta_SAB, "Team17 SAB header"},
{meta_MAXIS_XA, "Maxis XAI/XAJ Header"},
@ -968,8 +962,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)"},
{meta_WAVE, "EngineBlack .WAVE header"},
{meta_WAVE_segmented, "EngineBlack .WAVE header (segmented)"},
#ifdef VGM_USE_MP4V2
{meta_MP4, "AAC header"},

View File

@ -68,8 +68,6 @@ void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREA
void render_vgmstream_nolayout(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_aix(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);

View File

@ -1,50 +0,0 @@
#include "layout.h"
#include "../vgmstream.h"
#include "../coding/acm_decoder.h"
#include "../coding/coding.h"
void render_vgmstream_mus_acm(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) {
int samples_written=0;
mus_acm_codec_data *data = vgmstream->codec_data;
while (samples_written<sample_count) {
ACMStream *acm = data->files[data->current_file];
int samples_to_do;
int samples_this_block = acm->total_values / acm->info.channels;
if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) {
data->current_file = data->loop_start_file;
acm_reset(data->files[data->current_file]);
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)
{
data->current_file++;
/*printf("next %d, %d samples\n",data->current_file,data->files[data->current_file]->total_values/data->files[data->current_file]->info.channels);*/
/* force loop back to first file in case we're still playing for some
* reason, prevent out of bounds stuff */
if (data->current_file >= data->file_count) data->current_file = 0;
acm_reset(data->files[data->current_file]);
vgmstream->samples_into_block = 0;
continue;
}
/*printf("decode %d samples file %d\n",samples_to_do,data->current_file);*/
decode_acm(acm,
buffer+samples_written*vgmstream->channels,
samples_to_do, vgmstream->channels);
samples_written += samples_to_do;
vgmstream->current_sample += samples_to_do;
vgmstream->samples_into_block+=samples_to_do;
}
}

View File

@ -1758,10 +1758,6 @@
RelativePath=".\layout\blocked_ivaud.c"
>
</File>
<File
RelativePath=".\layout\mus_acm_layout.c"
>
</File>
<File
RelativePath=".\layout\mxch_blocked.c"
>

View File

@ -488,7 +488,6 @@
<ClCompile Include="layout\ims_block.c" />
<ClCompile Include="layout\interleave.c" />
<ClCompile Include="layout\blocked_ivaud.c" />
<ClCompile Include="layout\mus_acm_layout.c" />
<ClCompile Include="layout\mxch_blocked.c" />
<ClCompile Include="layout\nolayout.c" />
<ClCompile Include="layout\blocked_adm.c" />

View File

@ -1042,9 +1042,6 @@
<ClCompile Include="layout\blocked_ivaud.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\mus_acm_layout.c">
<Filter>layout\Source Files</Filter>
</ClCompile>
<ClCompile Include="layout\mxch_blocked.c">
<Filter>layout\Source Files</Filter>
</ClCompile>

View File

@ -1,66 +1,49 @@
#include "../vgmstream.h"
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../coding/acm_decoder.h"
/* InterPlay ACM */
/* The real work is done by libacm */
/* ACM - InterPlay infinity engine games [Planescape: Torment (PC), Baldur's Gate (PC)] */
VGMSTREAM * init_vgmstream_acm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
ACMStream *acm_stream = NULL;
mus_acm_codec_data *data;
int loop_flag = 0, channel_count, sample_rate, num_samples;
acm_codec_data *data = NULL;
char filename[PATH_LIMIT];
int loop_flag = 0;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("acm",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x0,streamFile) != 0x97280301)
goto fail;
data = calloc(1,sizeof(mus_acm_codec_data));
if (!data) goto fail;
data->files = calloc(1,sizeof(ACMStream *));
if (!data->files) {
free(data); data = NULL;
/* checks */
if (!check_extensions(streamFile, "acm"))
goto fail;
if (read_32bitBE(0x0,streamFile) != 0x97280301) /* header id */
goto fail;
/* init decoder */
{
data = init_acm(streamFile);
if (!data) goto fail;
channel_count = data->file->info.channels;
sample_rate = data->file->info.rate;
num_samples = data->file->total_values / data->file->info.channels;
}
/* gonna do this a little backwards, open and parse the file
before creating the vgmstream */
if (acm_open_decoder(&acm_stream,streamFile,filename) != ACM_OK) {
goto fail;
}
channel_count = acm_stream->info.channels;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->sample_rate = acm_stream->info.rate;
vgmstream->coding_type = coding_ACM;
vgmstream->num_samples = acm_stream->total_values / acm_stream->info.channels;
vgmstream->layout_type = layout_acm;
vgmstream->meta_type = meta_ACM;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = num_samples;
data->file_count = 1;
data->current_file = 0;
data->files[0] = acm_stream;
/*data->end_file = -1;*/
vgmstream->meta_type = meta_ACM;
vgmstream->coding_type = coding_ACM;
vgmstream->layout_type = layout_none;
vgmstream->codec_data = data;
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
free_acm(data);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,170 +1,160 @@
#include "meta.h"
#include "../util.h"
/* Apple Core Audio Format */
#include "../coding/coding.h"
/* Apple Core Audio Format File - from iOS games [Vectros (iOS), Ridge Racer Accelerated (iOS)] */
VGMSTREAM * init_vgmstream_apple_caff(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset = 0, chunk_offset;
size_t file_size, data_size = 0;
int loop_flag, channel_count = 0, sample_rate = 0;
off_t start_offset = 0;
off_t data_size = 0;
off_t sample_count = 0;
off_t interleave = 0;
int sample_rate = -1, unused_frames = 0;
int channel_count = 0;
off_t file_length;
off_t chunk_offset = 8;
int found_desc = 0, found_pakt = 0, found_data = 0;
int found_desc = 0 /*, found_pakt = 0*/, found_data = 0;
uint32_t codec = 0 /*, codec_flags = 0*/;
uint32_t bytes_per_packet = 0, samples_per_packet = 0, channels_per_packet = 0, bits_per_sample = 0;
int valid_samples = 0 /*, priming_samples = 0, unused_samples = 0*/;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("caf",filename_extension(filename))) goto fail;
/* check "caff" id */
if (read_32bitBE(0,streamFile)!=0x63616666) goto fail;
/* check version, flags */
if (read_32bitBE(4,streamFile)!=0x00010000) goto fail;
/* checks */
if (!check_extensions(streamFile, "caf"))
goto fail;
file_length = (off_t)get_streamfile_size(streamFile);
if (read_32bitBE(0x00,streamFile) != 0x63616666) /* "caff" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x00010000) /* version/flags */
goto fail;
while (chunk_offset < file_length)
{
/* high half of size (expect 0s) */
if (read_32bitBE(chunk_offset+4,streamFile) != 0) goto fail;
file_size = get_streamfile_size(streamFile);
chunk_offset = 0x08;
/* handle chunk type */
switch (read_32bitBE(chunk_offset,streamFile))
{
case 0x64657363: /* desc */
while (chunk_offset < file_size) {
uint32_t chunk_type = read_32bitBE(chunk_offset+0x00,streamFile);
uint32_t chunk_size = (uint32_t)read_64bitBE(chunk_offset+0x04,streamFile);
chunk_offset += 0x0c;
switch (chunk_type) {
case 0x64657363: /* "desc" */
found_desc = 1;
{
/* rather than put a convoluted conversion here for
portability, just look it up */
uint32_t sratefloat = read_32bitBE(chunk_offset+0x0c, streamFile);
if (read_32bitBE(chunk_offset+0x10, streamFile) != 0) goto fail;
switch (sratefloat)
{
case 0x40D19400:
sample_rate = 18000;
break;
case 0x40D58880:
sample_rate = 22050;
break;
case 0x40DF4000:
sample_rate = 32000;
break;
case 0x40E58880:
sample_rate = 44100;
break;
case 0x40E77000:
sample_rate = 48000;
break;
default:
goto fail;
}
}
{
uint32_t bytes_per_packet, frames_per_packet, channels_per_frame, bits_per_channel;
uint32_t codec_4cc = read_32bitBE(chunk_offset+0x14, streamFile);
/* only supporting ima4 for now */
if (codec_4cc != 0x696d6134) goto fail;
uint64_t sample_long = (uint64_t)read_64bitBE(chunk_offset+0x00, streamFile);
double* sample_double; /* double sample rate, double the fun */
/* format flags */
if (read_32bitBE(chunk_offset+0x18, streamFile) != 0) goto fail;
bytes_per_packet = read_32bitBE(chunk_offset+0x1c, streamFile);
frames_per_packet = read_32bitBE(chunk_offset+0x20, streamFile);
channels_per_frame = read_32bitBE(chunk_offset+0x24, streamFile);
bits_per_channel = read_32bitBE(chunk_offset+0x28, streamFile);
interleave = bytes_per_packet / channels_per_frame;
channel_count = channels_per_frame;
if (channels_per_frame != 1 && channels_per_frame != 2)
goto fail;
/* ima4-specific */
if (frames_per_packet != 64) goto fail;
if ((frames_per_packet / 2 + 2) * channels_per_frame !=
bytes_per_packet) goto fail;
if (bits_per_channel != 0) goto fail;
sample_double = (double*)&sample_long;
sample_rate = (int)(*sample_double);
}
codec = read_32bitBE(chunk_offset+0x08, streamFile);
//codec_flags = read_32bitBE(chunk_offset+0x0c, streamFile);
bytes_per_packet = read_32bitBE(chunk_offset+0x10, streamFile);
samples_per_packet = read_32bitBE(chunk_offset+0x14, streamFile);
channels_per_packet = read_32bitBE(chunk_offset+0x18, streamFile);
bits_per_sample = read_32bitBE(chunk_offset+0x1C, streamFile);
break;
case 0x70616b74: /* pakt */
found_pakt = 1;
/* 64-bit packet table size, 0 for constant bitrate */
if (
read_32bitBE(chunk_offset+0x0c,streamFile) != 0 ||
read_32bitBE(chunk_offset+0x10,streamFile) != 0) goto fail;
/* high half of valid frames count */
if (read_32bitBE(chunk_offset+0x14,streamFile) != 0) goto fail;
/* frame count */
sample_count = read_32bitBE(chunk_offset+0x18,streamFile);
/* priming frames */
if (read_32bitBE(chunk_offset+0x1c,streamFile) != 0) goto fail;
/* remainder (unused) frames */
unused_frames = read_32bitBE(chunk_offset+0x20,streamFile);
case 0x70616b74: /* "pakt" */
//found_pakt = 1;
//packets_table_size = (uint32_t)read_64bitBE(chunk_offset+0x00,streamFile); /* 0 for constant bitrate */
valid_samples = (uint32_t)read_64bitBE(chunk_offset+0x08,streamFile);
//priming_samples = read_32bitBE(chunk_offset+0x10,streamFile); /* encoder delay samples */
//unused_samples = read_32bitBE(chunk_offset+0x14,streamFile); /* footer samples */
break;
case 0x66726565: /* free */
/* padding, ignore */
break;
case 0x64617461: /* data */
if (read_32bitBE(chunk_offset+12,streamFile) != 1) goto fail;
case 0x64617461: /* "data" */
found_data = 1;
start_offset = chunk_offset + 16;
data_size = read_32bitBE(chunk_offset+8,streamFile) - 4;
/* 0x00: version? 0x00/0x01 */
start_offset = chunk_offset + 0x04;
data_size = chunk_size - 0x4;
break;
default: /* "free" "kuki" "info" "chan" etc: ignore */
break;
default:
goto fail;
}
/* done with chunk */
chunk_offset += 12 + read_32bitBE(chunk_offset+8,streamFile);
chunk_offset += chunk_size;
}
if (!found_pakt || !found_desc || !found_data) goto fail;
if (start_offset == 0 || data_size == 0 || sample_count == 0 ||
sample_rate == -1 || channel_count == 0) goto fail;
if (!found_desc || !found_data)
goto fail;
if (start_offset == 0 || data_size == 0)
goto fail;
/* ima4-specific */
/* check for full packets */
if (data_size % (interleave*channel_count) != 0) goto fail;
if ((sample_count+unused_frames)%((interleave-2)*2) != 0) goto fail;
/* check that all packets are accounted for */
if (data_size/interleave/channel_count !=
(sample_count+unused_frames)/((interleave-2)*2)) goto fail;
vgmstream = allocate_vgmstream(channel_count,0);
loop_flag = 0;
channel_count = channels_per_packet;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = sample_count;
/* ima4-specific */
vgmstream->coding_type = coding_APPLE_IMA4;
if (channel_count == 2)
vgmstream->layout_type = layout_interleave;
else
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = interleave;
vgmstream->meta_type = meta_CAFF;
/* open the file for reading by each channel */
{
int i;
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;
switch(codec) {
case 0x6C70636D: /* "lpcm" */
vgmstream->num_samples = valid_samples;
if (!vgmstream->num_samples)
vgmstream->num_samples = pcm_bytes_to_samples(data_size, channel_count, bits_per_sample);
vgmstream->ch[i].offset =
vgmstream->ch[i].channel_start_offset =
start_offset + interleave * i;
}
//todo check codec_flags for BE/LE, signed/etc
if (bits_per_sample == 8) {
vgmstream->coding_type = coding_PCM8;
}
else {
goto fail;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = bytes_per_packet / channels_per_packet;
break;
case 0x696D6134: /* "ima4" */
vgmstream->num_samples = valid_samples;
if (!vgmstream->num_samples) /* rare [Endless Fables 2 (iOS) */
vgmstream->num_samples = apple_ima4_bytes_to_samples(data_size, channel_count);
vgmstream->coding_type = coding_APPLE_IMA4;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = bytes_per_packet / channels_per_packet;
/* ima4 defaults */
//if (channels_per_packet != 1 && channels_per_packet != 2)
// goto fail;
if (samples_per_packet != 64)
goto fail;
if ((samples_per_packet / 2 + 2) * channels_per_packet != bytes_per_packet)
goto fail;
if (bits_per_sample != 0 && bits_per_sample != 4) /* 4 is rare too [Endless Fables 2 (iOS) */
goto fail;
/* check for full packets and that all packets are accounted for */
//if (found_pakt) {
// if (data_size % (vgmstream->interleave_block_size*channel_count) != 0)
// goto fail;
// if ((valid_samples+unused_samples)%((vgmstream->interleave_block_size-2)*2) != 0)
// goto fail;
// if (data_size/vgmstream->interleave_block_size/channel_count !=
// (valid_samples+unused_samples)/((vgmstream->interleave_block_size-2)*2))
// goto fail;
//}
break;
default: /* "aac " "alac" etc: probably parsed by FFMpeg... */
VGM_LOG("CAFF: unknown codec %x\n", codec);
goto fail;
}
goto fail;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
return vgmstream;
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -181,8 +181,9 @@ VGMSTREAM * init_vgmstream_mp4_aac_ffmpeg(STREAMFILE *streamFile) {
/* check extension, case insensitive */
/* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS) */
if (!check_extensions(streamFile,"mp4,m4a,m4v,lmp4,bin"))
/* .bin: Final Fantasy Dimensions (iOS), Final Fantasy V (iOS)
* .msd: UNO (iOS) */
if (!check_extensions(streamFile,"mp4,m4a,m4v,lmp4,bin,msd"))
goto fail;
filesize = streamFile->get_size(streamFile);

View File

@ -1,7 +1,6 @@
#include "../vgmstream.h"
#include "meta.h"
#include "../util.h"
#include "../streamfile.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../coding/acm_decoder.h"
#include <stdlib.h>
#include <string.h>
@ -13,11 +12,107 @@
#define DIRSEP '/'
#endif
#define NAME_LENGTH PATH_LIMIT
static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index);
static void clean_mus(char** mus_filenames, int file_count);
/* .MUS - playlist for InterPlay games [Planescape: Torment (PC), Baldur's Gate Enhanced Edition (PC)] */
VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
segmented_layout_data *data = NULL;
int channel_count, loop_flag = 0, loop_start_index = -1, loop_end_index = -1;
int32_t num_samples = 0, loop_start_samples = 0, loop_end_samples = 0;
char** mus_filenames = NULL;
int i, segment_count = 0;
/* checks */
if (!check_extensions(streamFile, "mus"))
goto fail;
/* get file paths from the .MUS text file */
mus_filenames = parse_mus(streamFile, &segment_count, &loop_flag, &loop_start_index, &loop_end_index);
if (!mus_filenames) goto fail;
/* 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 = streamFile->open(streamFile, mus_filenames[i], STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!temp_streamFile) goto fail;
/* find .ACM type */
switch(read_32bitBE(0x00,temp_streamFile)) {
case 0x97280301: /* ACM header id [Planescape: Torment (PC)] */
data->segments[i] = init_vgmstream_acm(temp_streamFile);
break;
case 0x4F676753: /* "OggS" [Planescape: Torment Enhanced Edition (PC)] */
data->segments[i] = init_vgmstream_ogg_vorbis(temp_streamFile);
break;
default:
data->segments[i] = NULL;
break;
}
close_streamfile(temp_streamFile);
if (!data->segments[i]) goto fail;
if (i==loop_start_index)
loop_start_samples = num_samples;
if (i==loop_end_index)
loop_end_samples = num_samples;
num_samples += data->segments[i]->num_samples;
}
if (i==loop_end_index)
loop_end_samples = num_samples;
/* setup segmented VGMSTREAMs */
if (!setup_layout_segmented(data))
goto fail;
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 = num_samples;
vgmstream->loop_start_sample = loop_start_samples;
vgmstream->loop_end_sample = loop_end_samples;
vgmstream->meta_type = meta_MUS_ACM;
vgmstream->coding_type = data->segments[0]->coding_type;
vgmstream->layout_type = layout_segmented;
vgmstream->layout_data = data;
data->loop_segment = loop_start_index;
clean_mus(mus_filenames, segment_count);
return vgmstream;
fail:
clean_mus(mus_filenames, segment_count);
free_layout_segmented(data);
close_vgmstream(vgmstream);
return NULL;
}
/* .mus text file parsing */
#define NAME_LENGTH PATH_LIMIT
static int exists(char *filename, STREAMFILE *streamfile) {
STREAMFILE * temp =
streamfile->open(streamfile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
STREAMFILE * temp = streamfile->open(streamfile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!temp) return 0;
close_streamfile(temp);
@ -91,57 +186,40 @@ fail:
return 1;
}
/* MUS playlist for InterPlay ACM */
VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
ACMStream *acm_stream = NULL;
mus_acm_codec_data *data = NULL;
static char** parse_mus(STREAMFILE *streamFile, int *out_file_count, int *out_loop_flag, int *out_loop_start_index, int *out_loop_end_index) {
char** names = NULL;
char filename[NAME_LENGTH];
char line_buffer[NAME_LENGTH];
char * end_ptr;
char name_base[NAME_LENGTH];
char (*names)[NAME_LENGTH] = NULL;
char dir_name[NAME_LENGTH];
char subdir_name[NAME_LENGTH];
int i;
int loop_flag = 0;
int channel_count;
int file_count;
size_t line_bytes;
int whole_line_read = 0;
off_t mus_offset = 0;
int loop_end_index = -1;
int loop_start_index = -1;
int32_t loop_start_samples = -1;
int32_t loop_end_samples = -1;
int i;
int loop_flag = 0, loop_start_index = -1, loop_end_index = -1;
int32_t total_samples = 0;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("mus",filename_extension(filename))) goto fail;
/* read file name base */
line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer,
mus_offset, streamFile, &whole_line_read);
line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail;
mus_offset += line_bytes;
memcpy(name_base,line_buffer,sizeof(name_base));
/* uppercase name_base */
{
int i;
for (i=0;name_base[i];i++) name_base[i]=toupper(name_base[i]);
int j;
for (j=0;name_base[j];j++)
name_base[j] = toupper(name_base[j]);
}
/*printf("name base: %s\n",name_base);*/
/* read track entry count */
line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer,
mus_offset, streamFile, &whole_line_read);
line_bytes = get_streamfile_text_line(sizeof(line_buffer),line_buffer, mus_offset, streamFile, &whole_line_read);
if (!whole_line_read) goto fail;
if (line_buffer[0] == '\0') goto fail;
mus_offset += line_bytes;
@ -149,24 +227,26 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
/* didn't parse whole line as an integer (optional opening whitespace) */
if (*end_ptr != '\0') goto fail;
/*printf("entries: %d\n",file_count);*/
names = calloc(file_count,sizeof(names[0]));
/* set names */
names = calloc(file_count,sizeof(char*)); /* array of strings (size NAME_LENGTH) */
if (!names) goto fail;
for (i = 0; i < file_count; i++) {
names[i] = calloc(1,sizeof(char)*NAME_LENGTH);
if (!names[i]) goto fail;
}
dir_name[0]='\0';
streamFile->get_name(streamFile,filename,sizeof(filename));
concatn(sizeof(dir_name),dir_name,filename);
/* find directory name for the directory contianing the MUS */
{
/* find directory name for the directory contianing the MUS */
char * last_slash;
last_slash = strrchr(dir_name,DIRSEP);
char * last_slash = strrchr(dir_name,DIRSEP);
if (last_slash != NULL) {
/* trim off the file name */
last_slash[1]='\0';
last_slash[1]='\0'; /* trim off the file name */
} else {
/* no dir name? annihilate! */
dir_name[0] = '\0';
dir_name[0] = '\0'; /* no dir name? annihilate! */
}
}
@ -180,7 +260,8 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
char loop_name_temp[NAME_LENGTH];
char loop_name_base[NAME_LENGTH];
char loop_name[NAME_LENGTH];
for (i=0;i<file_count;i++)
for (i = 0; i < file_count; i++)
{
int fields_matched;
line_bytes =
@ -192,7 +273,6 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
fields_matched = sscanf(line_buffer,"%s %s %s",name,
loop_name_base_temp,loop_name_temp);
if (fields_matched < 1) goto fail;
if (fields_matched == 3 && loop_name_base_temp[0] != '@' && loop_name_temp[0] != '@')
{
@ -222,14 +302,15 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
{
/* uppercase */
int j;
for (j=0;j<strlen(name);j++) name[j]=toupper(name[j]);
for (j=0;j<strlen(name);j++)
name[j]=toupper(name[j]);
}
/* try looking in the common directory */
names[i][0] = '\0';
concatn(sizeof(names[0]),names[i],dir_name);
concatn(sizeof(names[0]),names[i],name);
concatn(sizeof(names[0]),names[i],".ACM");
concatn(NAME_LENGTH,names[i],dir_name);
concatn(NAME_LENGTH,names[i],name);
concatn(NAME_LENGTH,names[i],".ACM");
if (!exists(names[i],streamFile)) {
@ -242,16 +323,14 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
}
names[i][0] = '\0';
concatn(sizeof(names[0]),names[i],dir_name);
concatn(sizeof(names[0]),names[i],subdir_name);
concatn(sizeof(names[0]),names[i],name_base);
concatn(sizeof(names[0]),names[i],name);
concatn(sizeof(names[0]),names[i],".ACM");
concatn(NAME_LENGTH,names[i],dir_name);
concatn(NAME_LENGTH,names[i],subdir_name);
concatn(NAME_LENGTH,names[i],name_base);
concatn(NAME_LENGTH,names[i],name);
concatn(NAME_LENGTH,names[i],".ACM");
if (!exists(names[i],streamFile)) goto fail;
}
/*printf("%2d %s\n",i,names[i]);*/
}
if (loop_end_index != -1) {
@ -263,18 +342,15 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
concatn(sizeof(target_name),target_name,loop_name_base);
concatn(sizeof(target_name),target_name,loop_name);
concatn(sizeof(target_name),target_name,".ACM");
/*printf("looking for loop %s\n",target_name);*/
for (i=0;i<file_count;i++) {
if (!strcmp(target_name,names[i]))
{
if (!strcmp(target_name,names[i])) {
loop_start_index = i;
break;
}
}
if (loop_start_index != -1) {
/*printf("loop from %d to %d\n",loop_end_index,loop_start_index);*/
/*if (loop_start_index < file_count-1) loop_start_index++;*/
loop_end_index++;
loop_flag = 1;
@ -283,78 +359,25 @@ VGMSTREAM * init_vgmstream_mus_acm(STREAMFILE *streamFile) {
}
}
/* set up the struct to track the files */
data = calloc(1,sizeof(mus_acm_codec_data));
if (!data) goto fail;
*out_loop_start_index = loop_start_index;
*out_loop_end_index = loop_end_index;
*out_loop_flag = loop_flag;
*out_file_count = file_count;
data->files = calloc(file_count,sizeof(ACMStream *));
if (!data->files) {
free(data); data = NULL;
goto fail;
}
/* open each file... */
for (i=0;i<file_count;i++) {
/* gonna do this a little backwards, open and parse the file
before creating the vgmstream */
if (acm_open_decoder(&acm_stream,streamFile,names[i]) != ACM_OK) {
goto fail;
}
data->files[i]=acm_stream;
if (i==loop_start_index) loop_start_samples = total_samples;
if (i==loop_end_index) loop_end_samples = total_samples;
total_samples += acm_stream->total_values / acm_stream->info.channels;
if (i>0) {
if (acm_stream->info.channels != data->files[0]->info.channels ||
acm_stream->info.rate != data->files[0]->info.rate) goto fail;
}
}
if (i==loop_end_index) loop_end_samples = total_samples;
channel_count = data->files[0]->info.channels;
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->channels = channel_count;
vgmstream->sample_rate = data->files[0]->info.rate;
vgmstream->coding_type = coding_ACM;
vgmstream->num_samples = total_samples;
vgmstream->loop_start_sample = loop_start_samples;
vgmstream->loop_end_sample = loop_end_samples;
vgmstream->layout_type = layout_mus_acm;
vgmstream->meta_type = meta_MUS_ACM;
data->file_count = file_count;
data->current_file = 0;
data->loop_start_file = loop_start_index;
data->loop_end_file = loop_end_index;
/*data->end_file = -1;*/
vgmstream->codec_data = data;
free(names);
return vgmstream;
/* clean up anything we may have opened */
return names;
fail:
if (data) {
int i;
for (i=0;i<data->file_count;i++) {
if (data->files[i]) {
acm_close(data->files[i]);
data->files[i] = NULL;
}
}
}
if (names) free(names);
if (vgmstream) close_vgmstream(vgmstream);
clean_mus(names, file_count);
return NULL;
}
static void clean_mus(char** mus_filenames, int file_count) {
int i;
if (!mus_filenames) return;
for (i = 0; i < file_count; i++) {
free(mus_filenames[i]);
}
free(mus_filenames);
}

View File

@ -88,7 +88,8 @@ VGMSTREAM * init_vgmstream_musx_v005(STREAMFILE *streamFile) {
/* checks */
if (!check_extensions(streamFile, "musx"))
/* .sfx: Batman Begins, .musx: header id */
if (!check_extensions(streamFile, "musx,sfx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
@ -158,27 +159,27 @@ fail:
}
/* MUSX (Version 006) */
/* MUSX (Version 006) [Batman Begins (GC)] */
VGMSTREAM * init_vgmstream_musx_v006(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 */
/* .sfx: Batman Begins, .musx: header id */
if (!check_extensions(streamFile, "sfx,musx"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4D555358) /* "MUSX" */
goto fail;
if (read_32bitBE(0x08,streamFile) != 0x06000000) /* "0x06000000" */
if (read_32bitBE(0x08,streamFile) != 0x06000000)
goto fail;
loop_flag = (read_32bitLE(0x840,streamFile)!=0xFFFFFFFF);
channel_count = 2;
//todo some files (ex. Batman Begins) have a subsong table at 0x800, not sure what signals it (flags at 0x04/0x14?)
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
@ -200,6 +201,8 @@ VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
break;
case 0x47435F5F: /* GC__ */
start_offset = read_32bitBE(0x28,streamFile);
if (start_offset == 0 || start_offset == 0xABABABAB) goto fail; /* some are empty */
vgmstream->channels = channel_count;
vgmstream->sample_rate = 32000;
vgmstream->coding_type = coding_DAT4_IMA;
@ -216,22 +219,9 @@ VGMSTREAM * init_vgmstream_musx_v006(STREAMFILE *streamFile) {
goto fail;
}
/* 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;
fail:

View File

@ -280,22 +280,12 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
switch (comp_level)
{
case 0:
vgmstream->coding_type = coding_NWA0;
break;
case 1:
vgmstream->coding_type = coding_NWA1;
break;
case 2:
vgmstream->coding_type = coding_NWA2;
break;
case 3:
vgmstream->coding_type = coding_NWA3;
break;
case 4:
vgmstream->coding_type = coding_NWA4;
break;
case 5:
vgmstream->coding_type = coding_NWA5;
vgmstream->coding_type = coding_NWA;
break;
default:
goto fail;

View File

@ -193,8 +193,11 @@ VGMSTREAM * init_vgmstream_ogg_vorbis(STREAMFILE *streamFile) {
/* check extension */
/* .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")) {
/* .ogg: standard/psychic, .logg: renamed for plugins,
* .adx: KID [Remember11 (PC)],
* .rof: The Rhythm of Fighters (Mobile)
* .acm: Planescape Torment Enhanced Edition (PC) */
if (check_extensions(streamFile,"ogg,logg,adx,rof,acm")) {
is_ogg = 1;
} else if (check_extensions(streamFile,"um3")) {
is_um3 = 1;

View File

@ -571,24 +571,10 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
#endif
if (vgmstream->coding_type==coding_ACM) {
mus_acm_codec_data *data = vgmstream->codec_data;
int i;
if (data) {
data->current_file = 0;
for (i=0;i<data->file_count;i++) {
acm_reset(data->files[i]);
}
}
reset_acm(vgmstream);
}
if (
vgmstream->coding_type == coding_NWA0 ||
vgmstream->coding_type == coding_NWA1 ||
vgmstream->coding_type == coding_NWA2 ||
vgmstream->coding_type == coding_NWA3 ||
vgmstream->coding_type == coding_NWA4 ||
vgmstream->coding_type == coding_NWA5
) {
if (vgmstream->coding_type == coding_NWA) {
nwa_codec_data *data = vgmstream->codec_data;
if (data)
reset_nwa(data->nwa);
@ -764,39 +750,14 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
#endif
if (vgmstream->coding_type==coding_ACM) {
mus_acm_codec_data *data = (mus_acm_codec_data *) vgmstream->codec_data;
if (data) {
if (data->files) {
int i;
for (i=0; i<data->file_count; i++) {
/* shouldn't be duplicates */
if (data->files[i]) {
acm_close(data->files[i]);
data->files[i] = NULL;
}
}
free(data->files);
data->files = NULL;
}
free(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
free_acm(vgmstream->codec_data);
vgmstream->codec_data = NULL;
}
if (
vgmstream->coding_type == coding_NWA0 ||
vgmstream->coding_type == coding_NWA1 ||
vgmstream->coding_type == coding_NWA2 ||
vgmstream->coding_type == coding_NWA3 ||
vgmstream->coding_type == coding_NWA4 ||
vgmstream->coding_type == coding_NWA5
) {
if (vgmstream->coding_type == coding_NWA) {
nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data;
close_nwa(data->nwa);
free(data);
vgmstream->codec_data = NULL;
}
@ -967,10 +928,6 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
case layout_blocked_xvag_subsong:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_acm:
case layout_mus_acm:
render_vgmstream_mus_acm(buffer,sample_count,vgmstream);
break;
case layout_aix:
render_vgmstream_aix(buffer,sample_count,vgmstream);
break;
@ -1034,12 +991,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_SDX2_int:
case coding_CBD2:
case coding_ACM:
case coding_NWA0:
case coding_NWA1:
case coding_NWA2:
case coding_NWA3:
case coding_NWA4:
case coding_NWA5:
case coding_NWA:
case coding_SASSC:
return 1;
@ -1194,12 +1146,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_SDX2:
case coding_SDX2_int:
case coding_CBD2:
case coding_NWA0:
case coding_NWA1:
case coding_NWA2:
case coding_NWA3:
case coding_NWA4:
case coding_NWA5:
case coding_NWA:
case coding_SASSC:
return 0x01;
@ -1820,14 +1767,11 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
break;
#endif
case coding_ACM:
/* handled in its own layout, here to quiet compiler */
decode_acm(vgmstream->codec_data,
buffer+samples_written*vgmstream->channels,
samples_to_do, vgmstream->channels);
break;
case coding_NWA0:
case coding_NWA1:
case coding_NWA2:
case coding_NWA3:
case coding_NWA4:
case coding_NWA5:
case coding_NWA:
decode_nwa(((nwa_codec_data*)vgmstream->codec_data)->nwa,
buffer+samples_written*vgmstream->channels,
samples_to_do
@ -2044,13 +1988,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
}
#endif
if (vgmstream->coding_type == coding_NWA0 ||
vgmstream->coding_type == coding_NWA1 ||
vgmstream->coding_type == coding_NWA2 ||
vgmstream->coding_type == coding_NWA3 ||
vgmstream->coding_type == coding_NWA4 ||
vgmstream->coding_type == coding_NWA5)
{
if (vgmstream->coding_type == coding_NWA) {
nwa_codec_data *data = vgmstream->codec_data;
if (data)
seek_nwa(data->nwa, vgmstream->loop_sample);
@ -2439,12 +2377,25 @@ static int get_vgmstream_average_bitrate_channel_count(VGMSTREAM * vgmstream)
/* average bitrate helper */
static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * vgmstream, int channel)
{
//AAX, AIX, ACM?
//AAX, AIX?
if (vgmstream->layout_type==layout_scd_int) {
scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data;
return data->intfiles[channel];
}
if (vgmstream->coding_type==coding_NWA) {
nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data;
if (data && data->nwa)
return data->nwa->file;
}
if (vgmstream->coding_type==coding_ACM) {
acm_codec_data *data = (acm_codec_data *) vgmstream->codec_data;
if (data && data->file)
return data->file->streamfile;
}
#ifdef VGM_USE_VORBIS
if (vgmstream->coding_type==coding_OGG_VORBIS) {
ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data;

View File

@ -160,12 +160,7 @@ typedef enum {
coding_CBD2, /* CBD2 2:1 Cuberoot-Delta-Exact compression DPCM */
coding_CBD2_int, /* CBD2 2:1 Cuberoot-Delta-Exact compression, with sample-level interleave */
coding_ACM, /* InterPlay ACM */
coding_NWA0, /* Visual Art's NWA (compressed at various levels) */
coding_NWA1,
coding_NWA2,
coding_NWA3,
coding_NWA4,
coding_NWA5,
coding_NWA, /* VisualArt's NWA */
coding_EA_MT, /* Electronic Arts MicroTalk (linear-predictive speech codec) */
@ -255,8 +250,6 @@ typedef enum {
layout_blocked_xvag_subsong, /* XVAG subsongs [God of War III (PS4)] */
/* otherwise odd */
layout_acm, /* libacm layout */
layout_mus_acm, /* mus has multi-files to deal with */
layout_aix, /* CRI AIX's wheels within wheels */
layout_segmented, /* song divided in segments, each a complete VGMSTREAM */
layout_scd_int, /* deinterleave done by the SCDINTSTREAMFILE */
@ -1043,20 +1036,10 @@ typedef struct {
} atrac9_codec_data;
#endif
/* with one file this is also used for just ACM */
/* libacm interface */
typedef struct {
int file_count;
int current_file;
/* the index we return to upon loop completion */
int loop_start_file;
/* one after the index of the last file, typically
* will be equal to file_count */
int loop_end_file;
/* Upon exit from a loop, which file to play. */
/* -1 if there is no such file */
/*int end_file;*/
ACMStream **files;
} mus_acm_codec_data;
ACMStream *file;
} acm_codec_data;
#define AIX_BUFFER_SIZE 0x1000
/* AIXery */