CWAV for 3DS, added as a modification to Wii RWAV/RWAR/RWSD

git-svn-id: https://vgmstream.svn.sourceforge.net/svnroot/vgmstream@993 51a99a44-fe44-0410-b1ba-c3e57ba2b86b
This commit is contained in:
halleyscometsw 2012-08-28 05:08:46 +00:00
parent a4bb71f17d
commit bed971faf8
6 changed files with 225 additions and 82 deletions

View File

@ -294,10 +294,12 @@ bool input_vgmstream::g_is_our_path(const char * p_path,const char * p_extension
if(!stricmp_utf8(p_extension,"baka")) return 1;
if(!stricmp_utf8(p_extension,"baf")) return 1;
if(!stricmp_utf8(p_extension,"bar")) return 1;
if(!stricmp_utf8(p_extension,"bcwav")) return 1;
if(!stricmp_utf8(p_extension,"bg00")) return 1;
if(!stricmp_utf8(p_extension,"bgw")) return 1;
if(!stricmp_utf8(p_extension,"bh2pcm")) return 1;
if(!stricmp_utf8(p_extension,"bmdx")) return 1;
if(!stricmp_utf8(p_extension,"bms")) return 1;
if(!stricmp_utf8(p_extension,"bnk")) return 1;
if(!stricmp_utf8(p_extension,"bns")) return 1;
if(!stricmp_utf8(p_extension,"bnsf")) return 1;
@ -610,10 +612,12 @@ DECLARE_MULTIPLE_FILE_TYPE("AUS Audio File (*.AUS)", aus);
DECLARE_MULTIPLE_FILE_TYPE("BAKA Audio File (*.BAKA)", baka);
DECLARE_MULTIPLE_FILE_TYPE("BAF Audio File (*.BAF)", baf);
DECLARE_MULTIPLE_FILE_TYPE("BAR Audio File (*.BAR)", bar);
DECLARE_MULTIPLE_FILE_TYPE("BCWAV Audio File (*.BCWAV)", bcwav);
DECLARE_MULTIPLE_FILE_TYPE("BG00 Audio File (*.BG00)", bg00);
DECLARE_MULTIPLE_FILE_TYPE("BGW Audio File (*.BGW)", bgw);
DECLARE_MULTIPLE_FILE_TYPE("BH2PCM Audio File (*.BH2PCM)", bh2pcm);
DECLARE_MULTIPLE_FILE_TYPE("BMDX Audio File (*.BMDX)", bmdx);
DECLARE_MULTIPLE_FILE_TYPE("BMS Audio File (*.BMS)", bms);
DECLARE_MULTIPLE_FILE_TYPE("KLBS Audio File (*.BNK)", bnk);
DECLARE_MULTIPLE_FILE_TYPE("BNS Audio File (*.BNS)", bns);
DECLARE_MULTIPLE_FILE_TYPE("BNSF Audio File (*.BNSF)", bnsf);

View File

@ -2,48 +2,86 @@
#include "../coding/coding.h"
#include "../util.h"
static off_t read_rwav(off_t offset, int *version, off_t *start_offset, off_t *info_chunkp, STREAMFILE *streamFile)
/* Wii RWAV, 3DS CWAV */
struct rwav_data {
// in
off_t offset;
STREAMFILE *streamFile;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*);
// out
int version;
off_t start_offset;
off_t info_chunk;
off_t wave_offset;
};
static void read_rwav(struct rwav_data * rd)
{
off_t chunk_table_offset;
off_t chunk_table_step;
off_t info_chunk;
off_t data_chunk;
off_t wave_offset;
if ((uint32_t)read_32bitBE(offset,streamFile)!=0x52574156) /* "RWAV" */
goto fail;
if ((uint32_t)read_32bitBE(offset+4,streamFile)!=0xFEFF0102) /* version 2 */
goto fail;
if (rd->big_endian)
{
/* "RWAV" */
if ((uint32_t)read_32bitBE(rd->offset,rd->streamFile)!=0x52574156)
return;
info_chunk = offset+read_32bitBE(offset+0x10,streamFile);
if ((uint32_t)read_32bitBE(info_chunk,streamFile)!=0x494e464f) /* "INFO" */
goto fail;
data_chunk = offset+read_32bitBE(offset+0x18,streamFile);
if ((uint32_t)read_32bitBE(data_chunk,streamFile)!=0x44415441) /* "DATA" */
goto fail;
/* big endian, version 2 */
if ((uint32_t)read_32bitBE(rd->offset+4,rd->streamFile)!=0xFEFF0102)
return;
*start_offset = data_chunk + 8;
*info_chunkp = info_chunk + 8;
*version = 2;
wave_offset = info_chunk - 8;
chunk_table_offset = rd->offset+0x10;
chunk_table_step = 8;
}
else
{
/* "CWAV" */
if ((uint32_t)read_32bitBE(rd->offset,rd->streamFile)!=0x43574156)
return;
return wave_offset;
fail:
return -1;
/* little endian, version 2 */
if ((uint32_t)read_32bitBE(rd->offset+4,rd->streamFile)!=0xFFFE4000 ||
(uint32_t)read_32bitBE(rd->offset+8,rd->streamFile)!=0x00000102)
return;
chunk_table_offset = rd->offset+0x18;
chunk_table_step = 0xc;
}
info_chunk = rd->offset+rd->read_32bit(chunk_table_offset,rd->streamFile);
/* "INFO" */
if ((uint32_t)read_32bitBE(info_chunk,rd->streamFile)!=0x494e464f)
return;
data_chunk = rd->offset+rd->read_32bit(chunk_table_offset+chunk_table_step,rd->streamFile);
/* "DATA" */
if ((uint32_t)read_32bitBE(data_chunk,rd->streamFile)!=0x44415441)
return;
rd->start_offset = data_chunk + 8;
rd->info_chunk = info_chunk + 8;
rd->version = 2;
rd->wave_offset = info_chunk - 8; // pretend to have a WAVE
return;
}
static off_t read_rwar(off_t offset, int *version, off_t *start_offset, off_t *info_chunk, STREAMFILE *streamFile)
static void read_rwar(struct rwav_data * rd)
{
off_t wave_offset;
if ((uint32_t)read_32bitBE(offset,streamFile)!=0x52574152) /* "RWAR" */
goto fail;
if ((uint32_t)read_32bitBE(offset+4,streamFile)!=0xFEFF0100) /* version 0 */
goto fail;
if ((uint32_t)read_32bitBE(rd->offset,rd->streamFile)!=0x52574152) /* "RWAR" */
return;
if ((uint32_t)read_32bitBE(rd->offset+4,rd->streamFile)!=0xFEFF0100) /* version 0 */
return;
wave_offset = read_rwav(offset+0x60,version,start_offset,info_chunk,streamFile);
*version = 0;
return wave_offset;
fail:
return -1;
rd->offset += 0x60;
read_rwav(rd);
rd->version = 0;
return;
}
/* RWSD is quite similar to BRSTM, but can contain several streams.
@ -55,50 +93,88 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
coding_t coding_type;
off_t info_chunk;
off_t wave_offset;
size_t wave_length;
int codec_number;
int channel_count;
int loop_flag;
int rwar = 0;
int rwav = 0;
int version = -1;
struct rwav_data rwav_data;
off_t start_offset = 0;
size_t stream_size;
int big_endian = 1;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
const char *ext;
rwav_data.version = -1;
rwav_data.start_offset = 0;
rwav_data.info_chunk = -1;
rwav_data.wave_offset = -1;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("rwsd",filename_extension(filename)))
ext = filename_extension(filename);
if (strcasecmp("rwsd",ext))
{
if (strcasecmp("rwar",filename_extension(filename)))
if (strcasecmp("rwar",ext))
{
if (strcasecmp("rwav",filename_extension(filename)))
if (strcasecmp("rwav",ext))
{
goto fail;
if (strcasecmp("bcwav",ext) && strcasecmp("bms",ext))
{
goto fail;
}
else
{
// cwav, similar to little endian rwav
rwav = 1;
big_endian = 0;
}
}
else
{
// matched rwav
rwav = 1;
}
}
else
{
// matched rwar
rwar = 1;
}
}
else
{
// match rwsd
}
if (big_endian)
{
read_16bit = read_16bitBE;
read_32bit = read_32bitBE;
}
else
{
read_16bit = read_16bitLE;
read_32bit = read_32bitLE;
}
/* check header */
if (rwar)
if (rwar || rwav)
{
wave_offset = read_rwar(0,&version,&start_offset,&info_chunk,streamFile);
if (wave_offset < 0) goto fail;
}
else if (rwav)
{
wave_offset = read_rwav(0,&version,&start_offset,&info_chunk,streamFile);
if (wave_offset < 0) goto fail;
rwav_data.offset = 0;
rwav_data.streamFile = streamFile;
rwav_data.big_endian = big_endian;
rwav_data.read_32bit = read_32bit;
if (rwar) read_rwar(&rwav_data);
if (rwav) read_rwav(&rwav_data);
if (rwav_data.wave_offset < 0) goto fail;
}
else
{
@ -111,24 +187,29 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
/* ideally we would look through the chunk list for a WAVE chunk,
* but it's always in the same order */
/* get WAVE offset, check */
wave_offset = read_32bitBE(0x18,streamFile);
if ((uint32_t)read_32bitBE(wave_offset,streamFile)!=0x57415645) /* "WAVE" */
rwav_data.wave_offset = read_32bit(0x18,streamFile);
if ((uint32_t)read_32bitBE(rwav_data.wave_offset,streamFile)!=0x57415645) /* "WAVE" */
goto fail;
/* get WAVE size, check */
wave_length = read_32bitBE(0x1c,streamFile);
if (read_32bitBE(wave_offset+4,streamFile)!=wave_length)
wave_length = read_32bit(0x1c,streamFile);
if (read_32bit(rwav_data.wave_offset+4,streamFile)!=wave_length)
goto fail;
/* check wave count */
if (read_32bitBE(wave_offset+8,streamFile) != 1)
if (read_32bit(rwav_data.wave_offset+8,streamFile) != 1)
goto fail; /* only support 1 */
version = 2;
rwav_data.version = 2;
break;
case 0xFEFF0103:
wave_offset = read_rwar(0xe0,&version,&start_offset,&info_chunk,streamFile);
if (wave_offset < 0) goto fail;
rwav_data.offset = 0xe0;
rwav_data.streamFile = streamFile;
rwav_data.big_endian = big_endian;
rwav_data.read_32bit = read_32bit;
read_rwar(&rwav_data);
if (rwav_data.wave_offset < 0) goto fail;
rwar = 1;
break;
@ -139,20 +220,29 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
}
/* get type details */
codec_number = read_8bit(wave_offset+0x10,streamFile);
loop_flag = read_8bit(wave_offset+0x11,streamFile);
channel_count = read_8bit(wave_offset+0x12,streamFile);
codec_number = read_8bit(rwav_data.wave_offset+0x10,streamFile);
loop_flag = read_8bit(rwav_data.wave_offset+0x11,streamFile);
if (big_endian)
channel_count = read_8bit(rwav_data.wave_offset+0x12,streamFile);
else
channel_count = read_32bit(rwav_data.wave_offset+0x24,streamFile);
switch (codec_number) {
case 0:
coding_type = coding_PCM8;
break;
case 1:
coding_type = coding_PCM16BE;
if (big_endian)
coding_type = coding_PCM16BE;
else
coding_type = coding_PCM16LE;
break;
case 2:
coding_type = coding_NGC_DSP;
break;
case 3:
coding_type = coding_IMA;
break;
default:
goto fail;
}
@ -165,10 +255,10 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x1c,streamFile));
vgmstream->sample_rate = (uint16_t)read_16bitBE(wave_offset+0x14,streamFile);
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x1c,streamFile));
vgmstream->sample_rate = (uint16_t)read_16bit(rwav_data.wave_offset+0x14,streamFile);
/* channels and loop flag are set by allocate_vgmstream */
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x18,streamFile));
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x18,streamFile));
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->coding_type = coding_type;
@ -177,35 +267,73 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
if (rwar)
vgmstream->meta_type = meta_RWAR;
else if (rwav)
vgmstream->meta_type = meta_RWAV;
{
if (big_endian)
vgmstream->meta_type = meta_RWAV;
else
vgmstream->meta_type = meta_CWAV;
}
else
vgmstream->meta_type = meta_RWSD;
if (vgmstream->coding_type == coding_NGC_DSP) {
off_t coef_offset;
{
off_t data_start_offset;
off_t codec_info_offset;
int i,j;
for (j=0;j<vgmstream->channels;j++) {
if (rwar || rwav)
{
if (big_endian)
{
/* This is pretty nasty, so an explaination is in order.
* At 0x10 in the info_chunk is the offset of a table with
* one entry per channel. Each entry in this table is itself
* an offset to a set of information for the channel. The
* first element in the set is the offset into DATA of the
* channel. The stream_size read far below just happens to
* hit on this properly for stereo. The second element is the
* offset of the coefficient table for the channel. */
coef_offset = info_chunk +
read_32bitBE(info_chunk +
read_32bitBE(info_chunk+
read_32bitBE(info_chunk+0x10,streamFile)+j*4,
streamFile) + 4, streamFile);
* channel.
* The second element is the
* offset of the codec-specific setup for the channel. */
off_t channel_info_offset;
channel_info_offset = rwav_data.info_chunk +
read_32bit(rwav_data.info_chunk+
read_32bit(rwav_data.info_chunk+0x10,streamFile)+j*4,
streamFile);
data_start_offset = rwav_data.start_offset +
read_32bit(channel_info_offset+0, streamFile);
codec_info_offset = rwav_data.info_chunk +
read_32bit(channel_info_offset+4, streamFile);
}
else
{
// CWAV uses some relative offsets
off_t cur_pos = rwav_data.info_chunk + 0x14; // channel count
cur_pos = cur_pos + read_32bit(cur_pos + 4 + j*8 + 4,streamFile);
// size is at cur_pos + 4
data_start_offset = rwav_data.start_offset + read_32bit(cur_pos + 4, streamFile);
// codec-specific info is at cur_pos + 0xC
codec_info_offset = cur_pos + read_32bit(cur_pos + 0xC,streamFile);
}
vgmstream->ch[j].channel_start_offset=
vgmstream->ch[j].offset=data_start_offset;
} else {
coef_offset=wave_offset+0x6c+j*0x30;
// dummy for RWSD, must be a proper way to work this out
codec_info_offset=rwav_data.wave_offset+0x6c+j*0x30;
}
for (i=0;i<16;i++) {
vgmstream->ch[j].adpcm_coef[i]=read_16bitBE(coef_offset+i*2,streamFile);
if (vgmstream->coding_type == coding_NGC_DSP) {
for (i=0;i<16;i++) {
vgmstream->ch[j].adpcm_coef[i]=read_16bit(codec_info_offset+i*2,streamFile);
}
}
if (vgmstream->coding_type == coding_IMA) {
vgmstream->ch[j].adpcm_history1_16 = read_16bit(codec_info_offset,streamFile);
vgmstream->ch[j].adpcm_step_index = read_16bit(codec_info_offset+2,streamFile);
}
}
}
@ -216,10 +344,10 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
}
else
{
if (version == 2)
start_offset = read_32bitBE(8,streamFile);
if (rwav_data.version == 2)
rwav_data.start_offset = read_32bit(8,streamFile);
}
stream_size = read_32bitBE(wave_offset+0x50,streamFile);
stream_size = read_32bit(rwav_data.wave_offset+0x50,streamFile);
/* open the file for reading by each channel */
{
@ -230,9 +358,12 @@ VGMSTREAM * init_vgmstream_rwsd(STREAMFILE *streamFile) {
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
start_offset + i*stream_size;
if (!(rwar || rwav))
{
vgmstream->ch[i].channel_start_offset=
vgmstream->ch[i].offset=
rwav_data.start_offset + i*stream_size;
}
}
}

View File

@ -2076,6 +2076,9 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_RWAV:
snprintf(temp,TEMPSIZE,"Nintendo RWAV header");
break;
case meta_CWAV:
snprintf(temp,TEMPSIZE,"Nintendo CWAV header");
break;
case meta_PSX_XA:
snprintf(temp,TEMPSIZE,"RIFF/CDXA header");
break;

View File

@ -216,6 +216,7 @@ typedef enum {
meta_RWSD, /* single-stream RWSD */
meta_RWAR, /* single-stream RWAR */
meta_RWAV, /* contents of RWAR */
meta_CWAV, /* */
meta_RSTM_SPM, /* RSTM with 44->22khz hack */
meta_THP,
meta_RSTM_shrunken, /* Atlus' mutant shortened RSTM */

View File

@ -42,10 +42,12 @@ gchar *vgmstream_exts [] = {
"baka",
"baf",
"bar",
"bcwav",
"bg00",
"bgw",
"bh2pcm",
"bmdx",
"bms",
"bns",
"bnsf",
"bo2",

View File

@ -106,11 +106,13 @@ char * extension_list[] = {
"baka\0BAKA Audio File (*.BAKA)\0",
"baf\0BAF Audio File (*.BAF)\0",
"bar\0BAR Audio File (*.BAR)\0",
"bcwav\0BCWAV (*.BCWAV)\0",
"bdsp\0BDSP Audio File (*.BDSP)\0",
"bg00\0BG00 Audio File (*.BG00)\0",
"bgw\0BGW Audio File (*.BGW)\0",
"bh2pcm\0BH2PCM Audio File (*.BH2PCM)\0",
"bmdx\0BMDX Audio File (*.BMDX)\0",
"bms\0BMS (*.BMS)\0",
"bnk\0BNK Audio File (*.BNK)\0",
"bns\0BNS Audio File (*.BNS)\0",
"bnsf\0BNSF Audio File (*.BNSF)\0",