Updated vgmstream

CQTexperiment
Chris Moeller 2015-01-21 18:08:44 -08:00
parent 9c57fdb469
commit c5416111bd
8 changed files with 394 additions and 91 deletions

View File

@ -0,0 +1,69 @@
/*
Wii U boot sound file for each game/app.
*/
#include "meta.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
coding_t coding_type;
int channel_count = 2;
int loop_flag;
off_t start_offset = 0x8;
/* check extension, case insensitive */
streamFile->get_name(streamFile, filename, sizeof(filename));
if (strcasecmp("btsnd", filename_extension(filename)))
goto fail;
/* Checking for loop start */
if (read_32bitBE(0x4, streamFile) > 0)
loop_flag = 1;
else
loop_flag = 0;
if (channel_count < 1) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->sample_rate = 48000;
/* channels and loop flag are set by allocate_vgmstream */
// There's probably a better way to get the sample count...
vgmstream->num_samples = vgmstream->loop_end_sample = (get_streamfile_size(streamFile) - 8) / 4;
vgmstream->loop_start_sample = read_32bitBE(0x4, streamFile);
vgmstream->coding_type = coding_PCM16BE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x2; // Constant for this format
vgmstream->meta_type = meta_WIIU_BTSND;
/* 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;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset =
start_offset + i*vgmstream->interleave_block_size;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,6 +1,6 @@
#include "meta.h"
#include "../util.h"
// Koei Tecmo G1L, found in the Warriors games
VGMSTREAM * init_vgmstream_g1l(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
@ -26,7 +26,6 @@ VGMSTREAM * init_vgmstream_g1l(STREAMFILE *streamFile) {
goto fail;
/* check type details */
// loop_flag = read_8bit(head_offset + 0x21, streamFile);
if (read_32bitBE(0x30, streamFile) > 0)
loop_flag = 1;
else
@ -69,17 +68,21 @@ VGMSTREAM * init_vgmstream_g1l(STREAMFILE *streamFile) {
int i, j;
int coef_spacing = 0x60;
for (j = 0; j<vgmstream->channels; j++) {
for (i = 0; i<16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(coef_offset + j*coef_spacing + i * 2, streamFile);
}
}
start_offset = 0x81c;
}
if (vgmstream->coding_type == coding_NGC_DSP)
start_offset = 0x81c;
else // Will add AT3 G1L support later
#ifdef VGM_USE_MAIATRAC3PLUS
else if (vgmstream->coding_type == coding_AT3plus) {
start_offset = 0xc4;
}
#endif
else
goto fail;

View File

@ -0,0 +1,101 @@
/*
Capcom MADP format found in Capcom 3DS games.
*/
#include "meta.h"
#include "../util.h"
VGMSTREAM * init_vgmstream_mca(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
coding_t coding_type;
int channel_count;
int loop_flag;
off_t start_offset;
off_t coef_offset;
int i, j;
int coef_spacing;
/* check extension, case insensitive */
streamFile->get_name(streamFile, filename, sizeof(filename));
if (strcasecmp("mca", filename_extension(filename)))
goto fail;
/* check header */
if ((uint32_t)read_32bitBE(0, streamFile) != 0x4D414450) /* "MADP" */
goto fail;
start_offset = (get_streamfile_size(streamFile) - read_32bitLE(0x20, streamFile));
channel_count = read_8bit(0x8, streamFile);
if (read_32bitLE(0x18, streamFile) > 0)
loop_flag = 1;
else
loop_flag = 0;
coding_type = coding_NGC_DSP;
if (channel_count < 1) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = read_32bitLE(0xc, streamFile);
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x10, streamFile);
/* channels and loop flag are set by allocate_vgmstream */
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile);
vgmstream->loop_end_sample = read_32bitLE(0x18, streamFile);
vgmstream->coding_type = coding_type;
if (channel_count == 1)
vgmstream->layout_type = layout_none;
else
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x100; // Constant for this format
vgmstream->meta_type = meta_MCA;
coef_offset = start_offset - (vgmstream->channels * 0x30);
coef_spacing = 0x30;
for (j = 0; j<vgmstream->channels; j++) {
for (i = 0; i<16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bitLE(coef_offset + j*coef_spacing + i * 2, streamFile);
}
}
/* open the file for reading by each channel */
{
for (i = 0; i<channel_count; i++) {
if (vgmstream->layout_type == layout_interleave_shortblock)
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
vgmstream->interleave_block_size);
else if (vgmstream->layout_type == layout_interleave)
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
STREAMFILE_DEFAULT_BUFFER_SIZE);
else
vgmstream->ch[i].streamfile = streamFile->open(streamFile, filename,
0x1000);
if (!vgmstream->ch[i].streamfile) goto fail;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset =
start_offset + i*vgmstream->interleave_block_size;
}
}
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -642,4 +642,8 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_g1l(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_mca(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_btsnd(STREAMFILE* streamFile);
#endif

View File

@ -2,6 +2,7 @@
#include "../layout/layout.h"
#include "../coding/coding.h"
#include "../util.h"
#include "../stack_alloc.h"
/* If these variables are packed properly in the struct (one after another)
* then this is actually how they are laid out in the file, albeit big-endian */
@ -2366,117 +2367,132 @@ fail:
}
/* .dspw files, two DSP files stuck together */
/* .dspw files, multiple DSP files stuck together */
/* found in Sengoku Basara 3 Wii */
VGMSTREAM * init_vgmstream_dsp_dspw(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t channel_1_start, channel_2_start;
off_t streamSize, mrkrOffset, channelSpacing;
int channel_count, i, j;
int found_mrkr = 0;
VARDECL(struct dsp_header, ch_header);
VARDECL(off_t, channel_start);
struct dsp_header ch0_header,ch1_header;
channel_count = read_8bit(0x1B, streamFile);
ALLOC(ch_header, channel_count, struct dsp_header);
ALLOC(channel_start, channel_count, off_t);
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("dspw",filename_extension(filename))) goto fail;
if (strcasecmp("dspw",filename_extension(filename))) goto fail;
if (read_32bitBE(0x0,streamFile) != 0x44535057) // DSPW
goto fail;
goto fail;
streamSize = read_32bitBE(0x8, streamFile);
if (read_32bitBE(streamSize - 0x10, streamFile) == 0x74494D45) // tIME
streamSize -= 0x10;
mrkrOffset = streamSize - 4;
while ((mrkrOffset > streamSize - 0x1000) && !(found_mrkr)) { // some files have a mrkr section with multiple loop regions at the end
if (read_32bitBE(mrkrOffset, streamFile) != 0x6D726B72) // mrkr
mrkrOffset -= 4;
else {
streamSize = mrkrOffset;
found_mrkr++;
}
}
streamSize -= 0x20; // minus the main header
channelSpacing = streamSize / channel_count;
/* read .dspw header */
channel_1_start = 0x20;
channel_2_start = (get_streamfile_size(streamFile)/2)+0x10;
for (i = 0; i < channel_count; i++) {
channel_start[i] = 0x20 + i*channelSpacing;
/* get DSP headers */
if (read_dsp_header(&ch0_header, channel_1_start, streamFile)) goto fail;
if (read_dsp_header(&ch1_header, channel_2_start, streamFile)) goto fail;
/* get DSP headers */
if (read_dsp_header(&ch_header[i], channel_start[i], streamFile)) goto fail;
/* check initial predictor/scale */
if (ch0_header.initial_ps !=
(uint8_t)read_8bit(channel_1_start + 0x60, streamFile))
goto fail;
/* check initial predictor/scale */
if (ch_header[i].initial_ps !=
(uint8_t)read_8bit(channel_start[i] + 0x60, streamFile))
goto fail;
if (ch1_header.initial_ps !=
(uint8_t)read_8bit(channel_2_start + 0x60, streamFile))
goto fail;
/* check type==0 and gain==0 */
if (ch0_header.format || ch0_header.gain ||
ch1_header.format || ch1_header.gain)
goto fail;
/* check for agreement */
if (
ch0_header.sample_count != ch1_header.sample_count ||
ch0_header.nibble_count != ch1_header.nibble_count ||
ch0_header.sample_rate != ch1_header.sample_rate ||
ch0_header.loop_flag != ch1_header.loop_flag ||
ch0_header.loop_start_offset != ch1_header.loop_start_offset ||
ch0_header.loop_end_offset != ch1_header.loop_end_offset
) goto fail;
if (ch0_header.loop_flag) {
off_t loop_off;
/* check loop predictor/scale */
loop_off = ch0_header.loop_start_offset/16*8;
if (ch0_header.loop_ps !=
(uint8_t)read_8bit(channel_1_start+0x60+loop_off,streamFile))
goto fail;
if (ch1_header.loop_ps !=
(uint8_t)read_8bit(channel_2_start+0x60+loop_off,streamFile))
goto fail;
}
/* check type==0 and gain==0 */
if (ch_header[i].format || ch_header[i].gain)
goto fail;
/* check for agreement */
if (i > 0) {
if (
ch_header[i].sample_count != ch_header[i-1].sample_count ||
ch_header[i].nibble_count != ch_header[i-1].nibble_count ||
ch_header[i].sample_rate != ch_header[i-1].sample_rate ||
ch_header[i].loop_flag != ch_header[i-1].loop_flag ||
ch_header[i].loop_start_offset != ch_header[i-1].loop_start_offset ||
ch_header[i].loop_end_offset != ch_header[i-1].loop_end_offset
) goto fail;
}
if (ch_header[0].loop_flag) {
off_t loop_off;
/* check loop predictor/scale */
loop_off = ch_header[0].loop_start_offset/16*8;
if (ch_header[i].loop_ps !=
(uint8_t)read_8bit(channel_start[i]+0x60+loop_off,streamFile))
goto fail;
}
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(2,ch0_header.loop_flag);
vgmstream = allocate_vgmstream(channel_count,ch_header[0].loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
vgmstream->num_samples = ch0_header.sample_count;
vgmstream->sample_rate = ch0_header.sample_rate;
vgmstream->num_samples = ch_header[0].sample_count;
vgmstream->sample_rate = ch_header[0].sample_rate;
vgmstream->loop_start_sample = dsp_nibbles_to_samples(
ch0_header.loop_start_offset);
ch_header[0].loop_start_offset);
vgmstream->loop_end_sample = dsp_nibbles_to_samples(
ch0_header.loop_end_offset)+1;
ch_header[0].loop_end_offset)+1;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_none;
// vgmstream->layout_type = layout_interleave;
// vgmstream->interleave_block_size = channelSpacing;
vgmstream->meta_type = meta_DSP_DSPW;
/* coeffs */
{
int i;
for (i=0;i<16;i++) {
vgmstream->ch[0].adpcm_coef[i] = ch0_header.coef[i];
vgmstream->ch[1].adpcm_coef[i] = ch1_header.coef[i];
for (i=0;i<channel_count;i++){
for (j=0;j<16;j++) {
vgmstream->ch[i].adpcm_coef[j] = ch_header[i].coef[j];
}
/* initial history */
/* always 0 that I've ever seen, but for completeness... */
vgmstream->ch[i].adpcm_history1_16 = ch_header[i].initial_hist1;
vgmstream->ch[i].adpcm_history2_16 = ch_header[i].initial_hist2;
}
/* initial history */
/* always 0 that I've ever seen, but for completeness... */
vgmstream->ch[0].adpcm_history1_16 = ch0_header.initial_hist1;
vgmstream->ch[0].adpcm_history2_16 = ch0_header.initial_hist2;
vgmstream->ch[1].adpcm_history1_16 = ch1_header.initial_hist1;
vgmstream->ch[1].adpcm_history2_16 = ch1_header.initial_hist2;
/* open the file for reading */
vgmstream->ch[0].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[0].streamfile) goto fail;
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[1].streamfile = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[1].streamfile) goto fail;
vgmstream->ch[0].channel_start_offset =
vgmstream->ch[0].offset=channel_1_start+0x60;
vgmstream->ch[1].channel_start_offset =
vgmstream->ch[1].offset=channel_2_start+0x60;
vgmstream->ch[i].channel_start_offset =
vgmstream->ch[i].offset=channel_start[i]+0x60;
}
return vgmstream;
fail:
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
return NULL;
}

View File

@ -0,0 +1,112 @@
/* Copyright (C) 2002-2003 Jean-Marc Valin
Copyright (C) 2007-2009 Xiph.Org Foundation */
/**
@file stack_alloc.h
@brief Temporary memory allocation on stack
*/
/*
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STACK_ALLOC_H
#define STACK_ALLOC_H
#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA))
#error "Vgmstream requires one of VAR_ARRAYS or USE_ALLOCA be defined to select the temporary allocation mode."
#endif
#ifdef USE_ALLOCA
# ifdef WIN32
# include <malloc.h>
# else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# include <stdlib.h>
# endif
# endif
#endif
/**
* @def ALIGN(stack, size)
*
* Aligns the stack to a 'size' boundary
*
* @param stack Stack
* @param size New size boundary
*/
/**
* @def PUSH(stack, size, type)
*
* Allocates 'size' elements of type 'type' on the stack
*
* @param stack Stack
* @param size Number of elements
* @param type Type of element
*/
/**
* @def VARDECL(var)
*
* Declare variable on stack
*
* @param var Variable to declare
*/
/**
* @def ALLOC(var, size, type)
*
* Allocate 'size' elements of 'type' on stack
*
* @param var Name of variable to allocate
* @param size Number of elements
* @param type Type of element
*/
#if defined(VAR_ARRAYS)
#define VARDECL(type, var)
#define ALLOC(var, size, type) type var[size]
#define SAVE_STACK
#define RESTORE_STACK
#define ALLOC_STACK
#elif defined(USE_ALLOCA)
#define VARDECL(type, var) type *var
# ifdef WIN32
# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size)))
# else
# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size)))
# endif
#define SAVE_STACK
#define RESTORE_STACK
#define ALLOC_STACK
#endif /* VAR_ARRAYS */
#endif /* STACK_ALLOC_H */

View File

@ -19,6 +19,8 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_brstm,
init_vgmstream_bfwav,
init_vgmstream_bfstm,
init_vgmstream_mca,
init_vgmstream_btsnd,
init_vgmstream_nds_strm,
init_vgmstream_agsc,
init_vgmstream_ngc_adpdtk,
@ -3083,9 +3085,15 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) {
case meta_G1L:
snprintf(temp,TEMPSIZE,"Tecmo Koei G1L Header");
break;
case meta_3DS_IDSP:
case meta_3DS_IDSP:
snprintf(temp,TEMPSIZE,"Nintendo 3DS IDSP Header");
break;
case meta_WIIU_BTSND:
snprintf(temp,TEMPSIZE,"Wii U Menu Boot Sound");
break;
case meta_MCA:
snprintf(temp,TEMPSIZE,"Capcom MCA Header");
break;
default:
snprintf(temp,TEMPSIZE,"THEY SHOULD HAVE SENT A POET");
}

View File

@ -18,19 +18,12 @@ enum { PATH_LIMIT = 32768 };
//#define VGM_USE_G7221
#include "streamfile.h"
#ifdef BUILD_VGMSTREAM
#include "coding/g72x_state.h"
#else
#include "g72x_state.h"
#endif
#ifdef VGM_USE_VORBIS
#ifdef __APPLE__
#define __MACOSX__
#endif
#include <vorbis/vorbisfile.h>
#endif
#ifdef VGM_USE_MPEG
#include <mpg123/mpg123.h>
#include <mpg123.h>
#endif
#ifdef VGM_USE_G7221
#include "g7221.h"
@ -46,16 +39,11 @@ enum { PATH_LIMIT = 32768 };
#endif
#ifdef VGM_USE_MAIATRAC3PLUS
#include <maiatrac3plus.h>
#include "maiatrac3plus.h"
#endif
#ifdef BUILD_VGMSTREAM
#include "coding/acm_decoder.h"
#include "coding/nwa_decoder.h"
#else
#include "acm_decoder.h"
#include "nwa_decoder.h"
#endif
/* The encoding type specifies the format the sound data itself takes */
typedef enum {
@ -262,6 +250,7 @@ typedef enum {
meta_NDS_RRDS, /* Ridge Racer DS */
meta_WII_BNS, /* Wii BNS Banner Sound (similar to RSTM) */
meta_STX, /* Pikmin .stx */
meta_WIIU_BTSND, /* Wii U Boot Sound */
/* CRI ADX */
meta_ADX_03, /* ADX "type 03" */
@ -583,6 +572,7 @@ typedef enum {
meta_FSTM, // Nintendo Wii U FSTM
meta_3DS_IDSP, // Nintendo 3DS IDSP
meta_G1L, // Tecmo Koei G1L
meta_MCA, // Capcom MCA "MADP"
#ifdef VGM_USE_MP4V2
meta_MP4,
#endif