mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 01:27:20 +01:00
NWA cleanup and improve performance
This commit is contained in:
parent
7592e72bae
commit
73db56f327
@ -146,8 +146,14 @@ STREAMFILE* acm_get_streamfile(acm_codec_data* data);
|
||||
|
||||
|
||||
/* nwa_decoder */
|
||||
void decode_nwa(NWAData* nwa, sample *outbuf, int32_t samples_to_do);
|
||||
typedef struct nwa_codec_data nwa_codec_data;
|
||||
|
||||
nwa_codec_data* init_nwa(STREAMFILE* sf);
|
||||
void decode_nwa(nwa_codec_data* data, sample_t* outbuf, int32_t samples_to_do);
|
||||
void seek_nwa(nwa_codec_data *data, int32_t sample);
|
||||
void reset_nwa(nwa_codec_data *data);
|
||||
void free_nwa(nwa_codec_data* data);
|
||||
STREAMFILE* nwa_get_streamfile(nwa_codec_data* data);
|
||||
|
||||
/* msadpcm_decoder */
|
||||
void decode_msadpcm_stereo(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t first_sample, int32_t samples_to_do);
|
||||
|
@ -1,4 +1,33 @@
|
||||
/* originally from nwatowav.cc 2007.7.28 version, which read: */
|
||||
/* Originally from nwatowav.cc (2007.7.28 version) by jagarl.
|
||||
* - http://www.creator.club.ne.jp/~jagarl/
|
||||
*
|
||||
* Converted to .c by hcs (redone as a lib without RIFF/main handling), some cleanup by bnnm.
|
||||
*
|
||||
* nwa format (abridged from the original)
|
||||
* NWA Header
|
||||
* data offset index
|
||||
* data block<0>
|
||||
* data block<1>
|
||||
* ...
|
||||
* data block<N>
|
||||
*
|
||||
* - NWA header: 0x2c with nwa info (channels, compression level, etc), no magic number
|
||||
* - data offset index: pointers to data blocks
|
||||
* - data block: variable sized DPCM blocks to fixed size PCM (a,b,c compresses to (a),b-a,c-b),
|
||||
* DPCM codes use variable bits. Usually for 16-bit PCM ends ups using 6-8 bits.
|
||||
* - Block format:
|
||||
* - mono: initial PCM (8 or 16-bit) then bitstream
|
||||
* - stereo: initial PCM for left + right channel then bitstream
|
||||
* Differential accuracy isn't high so initial PCM is used to correct data in each block (?)
|
||||
* - bitstream: Roughly each code has an 'exponent' (2 bits) + 'mantissa' (variable bits).
|
||||
* Depending on compression level + type it configures final shift value and matissa bits.
|
||||
* There is a run length encoding mode in some cases (Tomoyo After voice files).
|
||||
* Bitstream bytes follow little endian.
|
||||
* (some examples here in the original, see decoder).
|
||||
*
|
||||
* Original copyright:
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
|
||||
* All Rights Reserved.
|
||||
@ -33,319 +62,382 @@
|
||||
#include <stdlib.h>
|
||||
#include "nwa_decoder.h"
|
||||
|
||||
/* can serve up 8 bits at a time */
|
||||
static int
|
||||
getbits (STREAMFILE *file, off_t *offset, int *shift, int bits)
|
||||
{
|
||||
int ret;
|
||||
if (*shift > 8)
|
||||
{
|
||||
++*offset;
|
||||
*shift -= 8;
|
||||
|
||||
//NWAInfo::UseRunLength
|
||||
static int is_use_runlength(NWAData* nwa) {
|
||||
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2) {
|
||||
return 0; /* sw2 */
|
||||
}
|
||||
ret = read_16bitLE(*offset,file) >> *shift;
|
||||
*shift += bits;
|
||||
return ret & ((1 << bits) - 1); /* mask */
|
||||
|
||||
if (nwa->complevel == 5) {
|
||||
if (nwa->channels == 2)
|
||||
return 0; // BGM*.nwa in Little Busters!
|
||||
return 1; // Tomoyo After (.nwk koe file)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NWAData *
|
||||
open_nwa (STREAMFILE * streamFile, const char *filename)
|
||||
{
|
||||
NWAData* nwalib_open(STREAMFILE* sf) {
|
||||
uint8_t header[0x2c] = {0};
|
||||
int i;
|
||||
NWAData * const nwa = malloc(sizeof(NWAData));
|
||||
NWAData* const nwa = malloc(sizeof(NWAData));
|
||||
if (!nwa) goto fail;
|
||||
|
||||
nwa->channels = read_16bitLE(0x00,streamFile);
|
||||
nwa->bps = read_16bitLE(0x02,streamFile);
|
||||
nwa->freq = read_32bitLE(0x04,streamFile);
|
||||
nwa->complevel = read_32bitLE(0x08,streamFile);
|
||||
nwa->blocks = read_32bitLE(0x10,streamFile);
|
||||
nwa->datasize = read_32bitLE(0x14,streamFile);
|
||||
nwa->compdatasize = read_32bitLE(0x18,streamFile);
|
||||
nwa->samplecount = read_32bitLE(0x1c,streamFile);
|
||||
nwa->blocksize = read_32bitLE(0x20,streamFile);
|
||||
nwa->restsize = read_32bitLE(0x24,streamFile);
|
||||
//NWAData::ReadHeader
|
||||
|
||||
read_streamfile(header, 0x00, sizeof(header), sf);
|
||||
nwa->channels = get_s16le(header+0x00);
|
||||
nwa->bps = get_s16le(header+0x02);
|
||||
nwa->freq = get_s32le(header+0x04);
|
||||
nwa->complevel = get_s32le(header+0x08);
|
||||
nwa->dummy = get_s32le(header+0x0c);
|
||||
nwa->blocks = get_s32le(header+0x10);
|
||||
nwa->datasize = get_s32le(header+0x14);
|
||||
nwa->compdatasize = get_s32le(header+0x18);
|
||||
nwa->samplecount = get_s32le(header+0x1c);
|
||||
nwa->blocksize = get_s32le(header+0x20);
|
||||
nwa->restsize = get_s32le(header+0x24);
|
||||
nwa->dummy2 = get_s32le(header+0x28);
|
||||
|
||||
nwa->offsets = NULL;
|
||||
nwa->buffer = NULL;
|
||||
nwa->buffer_readpos = NULL;
|
||||
nwa->file = NULL;
|
||||
nwa->outdata = NULL;
|
||||
nwa->outdata_readpos = NULL;
|
||||
nwa->tmpdata = NULL;
|
||||
nwa->filesize = get_streamfile_size(sf);
|
||||
|
||||
/* PCM not handled here */
|
||||
if (nwa->complevel < 0 || nwa->complevel > 5) goto fail;
|
||||
|
||||
if (nwa->channels != 1 && nwa->channels != 2) goto fail;
|
||||
if (nwa->blocks <= 0 || nwa->blocks > 1000000)
|
||||
/* 1時間を超える曲ってのはないでしょ*/ //surely there won't be songs over 1 hour
|
||||
goto fail;
|
||||
|
||||
if (nwa->bps != 8 && nwa->bps != 16) goto fail;
|
||||
// NWAData::CheckHeader:
|
||||
|
||||
if (nwa->blocks <= 0) goto fail;
|
||||
if (nwa->channels != 1 && nwa->channels != 2)
|
||||
goto fail;
|
||||
|
||||
if (nwa->compdatasize == 0
|
||||
|| get_streamfile_size(streamFile) != nwa->compdatasize) goto fail;
|
||||
if (nwa->bps != 8 && nwa->bps != 16)
|
||||
goto fail;
|
||||
|
||||
if (nwa->datasize != nwa->samplecount * (nwa->bps/8)) goto fail;
|
||||
// (PCM not handled)
|
||||
|
||||
if (nwa->samplecount !=
|
||||
(nwa->blocks-1) * nwa->blocksize + nwa->restsize) goto fail;
|
||||
if (nwa->complevel < 0 || nwa->complevel > 5)
|
||||
goto fail;
|
||||
|
||||
nwa->offsets = malloc(sizeof(off_t)*nwa->blocks);
|
||||
if (nwa->filesize != nwa->compdatasize)
|
||||
goto fail;
|
||||
|
||||
|
||||
if (nwa->datasize != nwa->samplecount * (nwa->bps / 8))
|
||||
goto fail;
|
||||
|
||||
if (nwa->samplecount != (nwa->blocks - 1) * nwa->blocksize + nwa->restsize)
|
||||
goto fail;
|
||||
|
||||
/* offset index 読み込み */ //read offset index
|
||||
nwa->offsets = malloc(sizeof(off_t) * nwa->blocks);
|
||||
if (!nwa->offsets) goto fail;
|
||||
|
||||
for (i = 0; i < nwa->blocks; i++)
|
||||
{
|
||||
int32_t o = read_32bitLE(0x2c+i*4,streamFile);
|
||||
for (i = 0; i < nwa->blocks; i++) {
|
||||
int32_t o = read_s32le(0x2c + i*4, sf);
|
||||
if (o < 0) goto fail;
|
||||
nwa->offsets[i] = o;
|
||||
}
|
||||
|
||||
if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize) goto fail;
|
||||
|
||||
if (nwa->restsize > nwa->blocksize) nwa->buffer =
|
||||
malloc(sizeof(sample)*nwa->restsize);
|
||||
else nwa->buffer =
|
||||
malloc(sizeof(sample)*nwa->blocksize);
|
||||
if (nwa->buffer == NULL) goto fail;
|
||||
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
|
||||
nwa->samples_in_buffer = 0;
|
||||
if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize)
|
||||
goto fail;
|
||||
|
||||
nwa->use_runlength = is_use_runlength(nwa);
|
||||
nwa->curblock = 0;
|
||||
|
||||
/* if we got this far, it's probably safe */
|
||||
nwa->file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!nwa->file) goto fail;
|
||||
|
||||
//extra
|
||||
if (nwa->restsize > nwa->blocksize) {
|
||||
nwa->outdata = malloc(sizeof(int16_t) * nwa->restsize);
|
||||
}
|
||||
else {
|
||||
nwa->outdata = malloc(sizeof(int16_t) * nwa->blocksize);
|
||||
}
|
||||
if (!nwa->outdata)
|
||||
goto fail;
|
||||
|
||||
/* これ以上の大きさはないだろう、、、 */ //probably not over this size
|
||||
nwa->tmpdata = malloc(sizeof(uint8_t) * nwa->blocksize * (nwa->bps / 8) * 2);
|
||||
if (!nwa->tmpdata)
|
||||
goto fail;
|
||||
|
||||
nwa->outdata_readpos = nwa->outdata;
|
||||
nwa->samples_in_buffer = 0;
|
||||
|
||||
return nwa;
|
||||
fail:
|
||||
if (nwa)
|
||||
{
|
||||
close_nwa(nwa);
|
||||
}
|
||||
|
||||
nwalib_close(nwa);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
close_nwa(NWAData * nwa)
|
||||
{
|
||||
void nwalib_close(NWAData * nwa) {
|
||||
if (!nwa) return;
|
||||
|
||||
if (nwa->offsets)
|
||||
free (nwa->offsets);
|
||||
nwa->offsets = NULL;
|
||||
if (nwa->buffer)
|
||||
free (nwa->buffer);
|
||||
nwa->buffer = NULL;
|
||||
if (nwa->file)
|
||||
close_streamfile (nwa->file);
|
||||
nwa->file = NULL;
|
||||
free(nwa->offsets);
|
||||
free(nwa->outdata);
|
||||
free(nwa->tmpdata);
|
||||
free(nwa);
|
||||
}
|
||||
|
||||
void
|
||||
reset_nwa(NWAData *nwa)
|
||||
{
|
||||
//NWAData::Rewind
|
||||
void nwalib_reset(NWAData* nwa) {
|
||||
nwa->curblock = 0;
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
nwa->outdata_readpos = nwa->outdata;
|
||||
nwa->samples_in_buffer = 0;
|
||||
}
|
||||
|
||||
static int use_runlength(NWAData *nwa)
|
||||
{
|
||||
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2)
|
||||
{
|
||||
/* sw2 */
|
||||
return 0;
|
||||
// can serve up 8 bits at a time
|
||||
static int getbits(const uint8_t** p_data, int* shift, int bits) {
|
||||
int ret;
|
||||
if (*shift > 8) {
|
||||
(*p_data)++;
|
||||
*shift -= 8;
|
||||
}
|
||||
if (nwa->complevel == 5)
|
||||
{
|
||||
if (nwa->channels == 2) return 0; /* BGM*.nwa in Little Busters! */
|
||||
return 1; /* Tomoyo After (.nwk koe file) */
|
||||
|
||||
ret = get_s16le(*p_data) >> *shift;
|
||||
*shift += bits;
|
||||
return ret & ((1 << bits) - 1); /* mask */
|
||||
}
|
||||
|
||||
// NWADecode
|
||||
static void decode_block(NWAData* nwa, const uint8_t* data, int outdatasize) {
|
||||
sample d[2];
|
||||
int i;
|
||||
int shift = 0;
|
||||
|
||||
int dsize = outdatasize / (nwa->bps / 8);
|
||||
int flip_flag = 0; /* stereo 用 */ //for stereo
|
||||
int runlength = 0;
|
||||
|
||||
/* 最初のデータを読み込む */ //read initial data
|
||||
for (i = 0; i < nwa->channels; i++) {
|
||||
if (nwa->bps == 8) {
|
||||
d[i] = get_s8(data);
|
||||
data += 1;
|
||||
}
|
||||
else { /* nwa->bps == 16 */
|
||||
d[i] = get_s16le(data);
|
||||
data += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dsize; i++) {
|
||||
if (runlength == 0) { /* コピーループ中でないならデータ読み込み */ //read data if not in the copy loop
|
||||
int type = getbits(&data, &shift, 3);
|
||||
|
||||
/* type により分岐:0, 1-6, 7 */ //fork depending on type
|
||||
if (type == 7) {
|
||||
/* 7 : 大きな差分 */ //big diff
|
||||
/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */ //invalid when using RLE (comp=5, voice file)
|
||||
if (getbits(&data, &shift, 1) == 1) {
|
||||
d[flip_flag] = 0; /* 未使用 */ //unused
|
||||
}
|
||||
else {
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3) {
|
||||
BITS = 8;
|
||||
SHIFT = 9;
|
||||
}
|
||||
else {
|
||||
BITS = 8 - nwa->complevel;
|
||||
SHIFT = 2 + 7 + nwa->complevel;
|
||||
}
|
||||
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(&data, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type != 0) {
|
||||
/* 1-6 : 通常の差分 */ //normal diff
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3) {
|
||||
BITS = nwa->complevel + 3;
|
||||
SHIFT = 1 + type;
|
||||
}
|
||||
else {
|
||||
BITS = 5 - nwa->complevel;
|
||||
SHIFT = 2 + type + nwa->complevel;
|
||||
}
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(&data, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
else { /* type == 0 */
|
||||
/* ランレングス圧縮なしの場合はなにもしない */ //does nothing in case of no RLE compression
|
||||
if (nwa->use_runlength) {
|
||||
/* ランレングス圧縮ありの場合 */ //in case of RLE compression
|
||||
runlength = getbits(&data, &shift, 1);
|
||||
if (runlength == 1) {
|
||||
runlength = getbits(&data, &shift, 2);
|
||||
if (runlength == 3) {
|
||||
runlength = getbits(&data, &shift, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
runlength--;
|
||||
}
|
||||
|
||||
if (nwa->bps == 8) {
|
||||
nwa->outdata[i] = d[flip_flag] * 256; //extra (original outputs 8-bit)
|
||||
}
|
||||
else {
|
||||
nwa->outdata[i] = d[flip_flag];
|
||||
}
|
||||
|
||||
if (nwa->channels == 2)
|
||||
flip_flag ^= 1; /* channel 切り替え */ //channel swap
|
||||
}
|
||||
|
||||
nwa->samples_in_buffer = dsize;
|
||||
}
|
||||
|
||||
//NWAData::Decode
|
||||
int nwalib_decode(STREAMFILE* sf, NWAData* nwa) {
|
||||
/* some wav/pcm handling skipped here */
|
||||
|
||||
/* 今回読み込む/デコードするデータの大きさを得る */ //get current read/decode data size
|
||||
int curblocksize, curcompsize;
|
||||
if (nwa->curblock != nwa->blocks - 1) {
|
||||
curblocksize = nwa->blocksize * (nwa->bps / 8);
|
||||
curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock];
|
||||
if (curblocksize >= nwa->blocksize * (nwa->bps / 8) * 2) {
|
||||
return -1; // Fatal error
|
||||
}
|
||||
}
|
||||
else { //last block
|
||||
curblocksize = nwa->restsize * (nwa->bps / 8);
|
||||
curcompsize = nwa->blocksize * (nwa->bps / 8) * 2;
|
||||
}
|
||||
// (in practice compsize is ~200-400 and blocksize ~0x800, but last block can be different)
|
||||
|
||||
/* データ読み込み */ //data read (may read less on last block?)
|
||||
read_streamfile(nwa->tmpdata, nwa->offsets[nwa->curblock], curcompsize, sf);
|
||||
|
||||
nwa->samples_in_buffer = 0;
|
||||
nwa->outdata_readpos = nwa->outdata;
|
||||
|
||||
decode_block(nwa, nwa->tmpdata, curblocksize);
|
||||
|
||||
nwa->curblock++; //todo check not over max blocks?
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nwa_decode_block(NWAData *nwa)
|
||||
{
|
||||
/* 今回読み込む/デコードするデータの大きさを得る */
|
||||
int curblocksize;
|
||||
if (nwa->curblock != nwa->blocks - 1)
|
||||
{
|
||||
curblocksize = nwa->blocksize * (nwa->bps / 8);
|
||||
//curcompsize = nwa->offsets[nwa->curblock + 1] - nwa->offsets[nwa->curblock];
|
||||
}
|
||||
else
|
||||
{
|
||||
curblocksize = nwa->restsize * (nwa->bps / 8);
|
||||
//curcompsize = nwa->blocksize * (nwa->bps / 8) * 2;
|
||||
}
|
||||
|
||||
nwa->samples_in_buffer = 0;
|
||||
nwa->buffer_readpos = nwa->buffer;
|
||||
|
||||
{
|
||||
sample d[2];
|
||||
int i;
|
||||
int shift = 0;
|
||||
off_t offset = nwa->offsets[nwa->curblock];
|
||||
int dsize = curblocksize / (nwa->bps / 8);
|
||||
int flip_flag = 0; /* stereo 用 */
|
||||
int runlength = 0;
|
||||
|
||||
/* read initial sample value */
|
||||
for (i=0;i<nwa->channels;i++)
|
||||
{
|
||||
if (nwa->bps == 8) { d[i] = read_8bit(offset,nwa->file); }
|
||||
else /* bps == 16 */
|
||||
{
|
||||
d[i] = read_16bitLE(offset,nwa->file);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < dsize; i++)
|
||||
{
|
||||
if (runlength == 0)
|
||||
{ /* コピーループ中でないならデータ読み込み */
|
||||
int type = getbits(nwa->file, &offset, &shift, 3);
|
||||
/* type により分岐:0, 1-6, 7 */
|
||||
if (type == 7)
|
||||
{
|
||||
/* 7 : 大きな差分 */
|
||||
/* RunLength() 有効時(CompLevel==5, 音声ファイル) では無効 */
|
||||
if (getbits(nwa->file, &offset, &shift, 1) == 1)
|
||||
{
|
||||
d[flip_flag] = 0; /* 未使用 */
|
||||
}
|
||||
else
|
||||
{
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3)
|
||||
{
|
||||
BITS = 8;
|
||||
SHIFT = 9;
|
||||
}
|
||||
else
|
||||
{
|
||||
BITS = 8 - nwa->complevel;
|
||||
SHIFT = 2 + 7 + nwa->complevel;
|
||||
}
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (type != 0)
|
||||
{
|
||||
/* 1-6 : 通常の差分 */
|
||||
int BITS, SHIFT;
|
||||
if (nwa->complevel >= 3)
|
||||
{
|
||||
BITS = nwa->complevel + 3;
|
||||
SHIFT = 1 + type;
|
||||
}
|
||||
else
|
||||
{
|
||||
BITS = 5 - nwa->complevel;
|
||||
SHIFT = 2 + type + nwa->complevel;
|
||||
}
|
||||
{
|
||||
const int MASK1 = (1 << (BITS - 1));
|
||||
const int MASK2 = (1 << (BITS - 1)) - 1;
|
||||
int b = getbits(nwa->file, &offset, &shift, BITS);
|
||||
if (b & MASK1)
|
||||
d[flip_flag] -= (b & MASK2) << SHIFT;
|
||||
else
|
||||
d[flip_flag] += (b & MASK2) << SHIFT;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* type == 0 */
|
||||
/* ランレングス圧縮なしの場合はなにもしない */
|
||||
if (use_runlength(nwa))
|
||||
{
|
||||
/* ランレングス圧縮ありの場合 */
|
||||
runlength = getbits(nwa->file, &offset, &shift, 1);
|
||||
if (runlength == 1)
|
||||
{
|
||||
runlength = getbits(nwa->file, &offset, &shift, 2);
|
||||
if (runlength == 3)
|
||||
{
|
||||
runlength = getbits(nwa->file, &offset, &shift, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
runlength--;
|
||||
}
|
||||
if (nwa->bps == 8)
|
||||
{
|
||||
nwa->buffer[i] = d[flip_flag]*0x100;
|
||||
}
|
||||
else
|
||||
{
|
||||
nwa->buffer[i] = d[flip_flag];
|
||||
}
|
||||
nwa->samples_in_buffer++;
|
||||
if (nwa->channels == 2)
|
||||
flip_flag ^= 1; /* channel 切り替え */
|
||||
}
|
||||
}
|
||||
|
||||
nwa->curblock++;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
seek_nwa(NWAData *nwa, int32_t seekpos)
|
||||
{
|
||||
int dest_block = seekpos/(nwa->blocksize/nwa->channels);
|
||||
int32_t remainder = seekpos%(nwa->blocksize/nwa->channels);
|
||||
//NWAFILE::Seek (not too similar)
|
||||
void nwalib_seek(STREAMFILE* sf, NWAData* nwa, int32_t seekpos) {
|
||||
int dest_block = seekpos / (nwa->blocksize / nwa->channels);
|
||||
int32_t remainder = seekpos % (nwa->blocksize / nwa->channels);
|
||||
|
||||
nwa->curblock = dest_block;
|
||||
|
||||
nwa_decode_block(nwa);
|
||||
nwalib_decode(sf, nwa);
|
||||
|
||||
nwa->buffer_readpos = nwa->buffer + remainder*nwa->channels;
|
||||
nwa->outdata_readpos = nwa->outdata + remainder * nwa->channels;
|
||||
nwa->samples_in_buffer -= remainder*nwa->channels;
|
||||
}
|
||||
|
||||
/* interface to vgmstream */
|
||||
void
|
||||
decode_nwa(NWAData *nwa, sample *outbuf,
|
||||
int32_t samples_to_do)
|
||||
{
|
||||
while (samples_to_do > 0)
|
||||
{
|
||||
int32_t samples_to_read;
|
||||
/* ****************************************************************** */
|
||||
|
||||
if (nwa->samples_in_buffer > 0)
|
||||
{
|
||||
samples_to_read = nwa->samples_in_buffer/nwa->channels;
|
||||
#include "coding.h"
|
||||
|
||||
|
||||
struct nwa_codec_data {
|
||||
STREAMFILE* sf;
|
||||
NWAData* nwa;
|
||||
};
|
||||
|
||||
/* interface to vgmstream */
|
||||
void decode_nwa(nwa_codec_data* data, sample_t* outbuf, int32_t samples_to_do) {
|
||||
NWAData* nwa = data->nwa;
|
||||
|
||||
while (samples_to_do > 0) {
|
||||
if (nwa->samples_in_buffer > 0) {
|
||||
int32_t samples_to_read = nwa->samples_in_buffer / nwa->channels;
|
||||
if (samples_to_read > samples_to_do)
|
||||
samples_to_read = samples_to_do;
|
||||
|
||||
memcpy(outbuf,nwa->buffer_readpos,
|
||||
sizeof(sample)*samples_to_read*nwa->channels);
|
||||
memcpy(outbuf, nwa->outdata_readpos, sizeof(sample_t) * samples_to_read * nwa->channels);
|
||||
|
||||
nwa->buffer_readpos += samples_to_read*nwa->channels;
|
||||
nwa->samples_in_buffer -= samples_to_read*nwa->channels;
|
||||
outbuf += samples_to_read*nwa->channels;
|
||||
nwa->outdata_readpos += samples_to_read * nwa->channels;
|
||||
nwa->samples_in_buffer -= samples_to_read * nwa->channels;
|
||||
outbuf += samples_to_read * nwa->channels;
|
||||
samples_to_do -= samples_to_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
nwa_decode_block(nwa);
|
||||
else {
|
||||
int err = nwalib_decode(data->sf, nwa);
|
||||
if (err < 0) {
|
||||
VGM_LOG("NWA: decoding error\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nwa_codec_data* init_nwa(STREAMFILE* sf) {
|
||||
nwa_codec_data *data = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
data = malloc(sizeof(nwa_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->nwa = nwalib_open(sf);
|
||||
if (!data->nwa) goto fail;
|
||||
|
||||
get_streamfile_name(sf,filename,sizeof(filename));
|
||||
data->sf = open_streamfile(sf, filename);
|
||||
if (!data->sf) goto fail;
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
free_nwa(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void seek_nwa(nwa_codec_data *data, int32_t sample) {
|
||||
if (!data) return;
|
||||
|
||||
nwalib_seek(data->sf, data->nwa, sample);
|
||||
}
|
||||
|
||||
void reset_nwa(nwa_codec_data *data) {
|
||||
if (!data) return;
|
||||
|
||||
nwalib_reset(data->nwa);
|
||||
}
|
||||
|
||||
void free_nwa(nwa_codec_data* data) {
|
||||
if (!data) return;
|
||||
|
||||
close_streamfile(data->sf);
|
||||
nwalib_close(data->nwa);
|
||||
free(data);
|
||||
}
|
||||
|
||||
STREAMFILE* nwa_get_streamfile(nwa_codec_data* data) {
|
||||
if (!data) return NULL;
|
||||
|
||||
return data->sf;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* originally from nwatowav.cc 2007.7.28 version, which read: */
|
||||
/* derived from nwatowav.cc 2007.7.28 version, which read: */
|
||||
/*
|
||||
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
|
||||
* All Rights Reserved.
|
||||
@ -35,33 +35,39 @@
|
||||
|
||||
#include "../streamfile.h"
|
||||
|
||||
typedef struct NWAData_s
|
||||
{
|
||||
typedef struct NWAData_s {
|
||||
int channels;
|
||||
int bps; /* bits per sample */
|
||||
int freq; /* samples per second */
|
||||
int complevel; /* compression level */
|
||||
int blocks; /* block count */
|
||||
int datasize; /* all data size */
|
||||
int compdatasize; /* compressed data size */
|
||||
int samplecount; /* all samples */
|
||||
int blocksize; /* samples per block */
|
||||
int restsize; /* samples of the last block */
|
||||
int bps; /* bits per sample */
|
||||
int freq; /* samples per second */
|
||||
|
||||
int complevel; /* compression level */
|
||||
int dummy; /* ? : 0x00 */
|
||||
|
||||
int blocks; /* block count */
|
||||
int datasize; /* all data size */
|
||||
|
||||
int compdatasize; /* compressed data size */
|
||||
int samplecount; /* all samples */
|
||||
int blocksize; /* samples per block */
|
||||
int restsize; /* samples of the last block */
|
||||
int dummy2; /* ? : 0x89 */
|
||||
|
||||
int curblock;
|
||||
off_t *offsets;
|
||||
off_t* offsets;
|
||||
int filesize;
|
||||
|
||||
STREAMFILE *file;
|
||||
int use_runlength; //extra
|
||||
|
||||
/* temporarily store samples */
|
||||
sample *buffer;
|
||||
sample *buffer_readpos;
|
||||
uint8_t *tmpdata;
|
||||
int16_t *outdata;
|
||||
int16_t *outdata_readpos;
|
||||
int samples_in_buffer;
|
||||
} NWAData;
|
||||
|
||||
NWAData *open_nwa(STREAMFILE *streamFile, const char *filename);
|
||||
void close_nwa(NWAData *nwa);
|
||||
void reset_nwa(NWAData *nwa);
|
||||
void seek_nwa(NWAData *nwa, int32_t seekpos);
|
||||
NWAData* nwalib_open(STREAMFILE* sf);
|
||||
void nwalib_close(NWAData* nwa);
|
||||
int nwalib_decode(STREAMFILE* sf, NWAData* nwa);
|
||||
void nwalib_seek(STREAMFILE* sf, NWAData* nwa, int32_t seekpos);
|
||||
void nwalib_reset(NWAData* nwa);
|
||||
|
||||
#endif
|
||||
|
138
src/meta/nwa.c
138
src/meta/nwa.c
@ -1,18 +1,15 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/nwa_decoder.h"
|
||||
#include "../coding/coding.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start);
|
||||
static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end);
|
||||
static nwa_codec_data *open_nwa_vgmstream(STREAMFILE *streamFile);
|
||||
static void free_nwa_vgmstream(nwa_codec_data *data);
|
||||
static int get_loops_nwainfo_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start);
|
||||
static int get_loops_gameexe_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start, int32_t *p_loop_end);
|
||||
|
||||
/* NWA - Visual Art's streams [Air (PC), Clannad (PC)] */
|
||||
VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
VGMSTREAM* init_vgmstream_nwa(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count, loop_flag = 0;
|
||||
int32_t loop_start_sample = 0, loop_end_sample = 0;
|
||||
@ -21,26 +18,26 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "nwa"))
|
||||
if (!check_extensions(sf, "nwa"))
|
||||
goto fail;
|
||||
|
||||
channel_count = read_16bitLE(0x00,streamFile);
|
||||
channel_count = read_16bitLE(0x00,sf);
|
||||
if (channel_count != 1 && channel_count != 2) goto fail;
|
||||
|
||||
/* check if we're using raw pcm */
|
||||
if ( read_32bitLE(0x08,streamFile)==-1 || /* compression level */
|
||||
read_32bitLE(0x10,streamFile)==0 || /* block count */
|
||||
read_32bitLE(0x18,streamFile)==0 || /* compressed data size */
|
||||
read_32bitLE(0x20,streamFile)==0 || /* block size */
|
||||
read_32bitLE(0x24,streamFile)==0 ) { /* restsize */
|
||||
if ( read_32bitLE(0x08,sf)==-1 || /* compression level */
|
||||
read_32bitLE(0x10,sf)==0 || /* block count */
|
||||
read_32bitLE(0x18,sf)==0 || /* compressed data size */
|
||||
read_32bitLE(0x20,sf)==0 || /* block size */
|
||||
read_32bitLE(0x24,sf)==0 ) { /* restsize */
|
||||
compression_level = -1;
|
||||
} else {
|
||||
compression_level = read_32bitLE(0x08,streamFile);
|
||||
compression_level = read_32bitLE(0x08,sf);
|
||||
}
|
||||
|
||||
/* loop points come from external files */
|
||||
nwainfo_ini_found = get_loops_nwainfo_ini(streamFile, &loop_flag, &loop_start_sample);
|
||||
gameexe_ini_found = !nwainfo_ini_found && get_loops_gameexe_ini(streamFile, &loop_flag, &loop_start_sample, &loop_end_sample);
|
||||
nwainfo_ini_found = get_loops_nwainfo_ini(sf, &loop_flag, &loop_start_sample);
|
||||
gameexe_ini_found = !nwainfo_ini_found && get_loops_gameexe_ini(sf, &loop_flag, &loop_start_sample, &loop_end_sample);
|
||||
|
||||
start_offset = 0x2c;
|
||||
|
||||
@ -48,12 +45,12 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x1c,streamFile) / channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x04,sf);
|
||||
vgmstream->num_samples = read_32bitLE(0x1c,sf) / channel_count;
|
||||
|
||||
switch(compression_level) {
|
||||
case -1:
|
||||
switch (read_16bitLE(0x02,streamFile)) {
|
||||
switch (read_16bitLE(0x02,sf)) {
|
||||
case 8:
|
||||
vgmstream->coding_type = coding_PCM8;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
@ -76,7 +73,7 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
|
||||
case 5:
|
||||
vgmstream->coding_type = coding_NWA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->codec_data = open_nwa_vgmstream(streamFile);
|
||||
vgmstream->codec_data = init_nwa(sf);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
break;
|
||||
|
||||
@ -103,7 +100,7 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
@ -114,8 +111,8 @@ fail:
|
||||
|
||||
|
||||
/* try to locate NWAINFO.INI in the same directory */
|
||||
static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start) {
|
||||
STREAMFILE *streamLoops;
|
||||
static int get_loops_nwainfo_ini(STREAMFILE *sf, int *p_loop_flag, int32_t *p_loop_start) {
|
||||
STREAMFILE *sf_loop;
|
||||
char namebase[PATH_LIMIT];
|
||||
const char * ext;
|
||||
int length;
|
||||
@ -127,15 +124,15 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
int32_t loop_start_sample = 0;
|
||||
|
||||
|
||||
streamLoops = open_streamfile_by_filename(streamFile, "NWAINFO.INI");
|
||||
if (!streamLoops) goto fail;
|
||||
sf_loop = open_streamfile_by_filename(sf, "NWAINFO.INI");
|
||||
if (!sf_loop) goto fail;
|
||||
|
||||
get_streamfile_filename(streamFile,namebase,PATH_LIMIT);
|
||||
get_streamfile_filename(sf,namebase,PATH_LIMIT);
|
||||
|
||||
/* ini found, try to find our name */
|
||||
ext = filename_extension(namebase);
|
||||
length = ext - 1 - namebase;
|
||||
file_size = get_streamfile_size(streamLoops);
|
||||
file_size = get_streamfile_size(sf_loop);
|
||||
|
||||
for (found = 0, offset = 0; !found && offset < file_size; offset++) {
|
||||
off_t suboffset;
|
||||
@ -145,12 +142,12 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
for (suboffset = offset;
|
||||
suboffset < file_size &&
|
||||
suboffset-offset < length &&
|
||||
read_8bit(suboffset,streamLoops) == namebase[suboffset-offset];
|
||||
read_8bit(suboffset,sf_loop) == namebase[suboffset-offset];
|
||||
suboffset++) {
|
||||
/* skip */
|
||||
}
|
||||
|
||||
if (suboffset-offset==length && read_8bit(suboffset,streamLoops)==0x09) { /* tab */
|
||||
if (suboffset-offset==length && read_8bit(suboffset,sf_loop)==0x09) { /* tab */
|
||||
found = 1;
|
||||
found_off = suboffset+1;
|
||||
}
|
||||
@ -160,7 +157,7 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
if (found) {
|
||||
char loopstring[9] = {0};
|
||||
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off,8,streamLoops) == 8) {
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off,8,sf_loop) == 8) {
|
||||
loop_start_sample = atol(loopstring);
|
||||
if (loop_start_sample > 0)
|
||||
loop_flag = 1;
|
||||
@ -168,22 +165,22 @@ static int get_loops_nwainfo_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
}
|
||||
|
||||
|
||||
*out_loop_flag = loop_flag;
|
||||
*out_loop_start = loop_start_sample;
|
||||
*p_loop_flag = loop_flag;
|
||||
*p_loop_start = loop_start_sample;
|
||||
|
||||
close_streamfile(streamLoops);
|
||||
close_streamfile(sf_loop);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamLoops);
|
||||
close_streamfile(sf_loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try to locate Gameexe.ini in the same directory */
|
||||
static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int32_t *out_loop_start, int32_t *out_loop_end) {
|
||||
STREAMFILE *streamLoops;
|
||||
static int get_loops_gameexe_ini(STREAMFILE* sf, int* p_loop_flag, int32_t* p_loop_start, int32_t* p_loop_end) {
|
||||
STREAMFILE*sf_loop;
|
||||
char namebase[PATH_LIMIT];
|
||||
const char * ext;
|
||||
const char* ext;
|
||||
int length;
|
||||
int found;
|
||||
off_t offset;
|
||||
@ -193,15 +190,15 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
int32_t loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
|
||||
streamLoops = open_streamfile_by_filename(streamFile, "Gameexe.ini");
|
||||
if (!streamLoops) goto fail;
|
||||
sf_loop = open_streamfile_by_filename(sf, "Gameexe.ini");
|
||||
if (!sf_loop) goto fail;
|
||||
|
||||
get_streamfile_filename(streamFile,namebase,PATH_LIMIT);
|
||||
get_streamfile_filename(sf,namebase,PATH_LIMIT);
|
||||
|
||||
/* ini found, try to find our name */
|
||||
ext = filename_extension(namebase);
|
||||
length = ext-1-namebase;
|
||||
file_size = get_streamfile_size(streamLoops);
|
||||
file_size = get_streamfile_size(sf_loop);
|
||||
|
||||
/* format of line is:
|
||||
* #DSTRACK = 00000000 - eeeeeeee - ssssssss = "name" = "name2?"
|
||||
@ -212,20 +209,20 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
off_t suboffset;
|
||||
uint8_t buf[10];
|
||||
|
||||
if (read_8bit(offset,streamLoops)!='#') continue;
|
||||
if (read_streamfile(buf,offset+1,10,streamLoops)!=10) break;
|
||||
if (read_8bit(offset,sf_loop)!='#') continue;
|
||||
if (read_streamfile(buf,offset+1,10,sf_loop)!=10) break;
|
||||
if (memcmp("DSTRACK = ",buf,10)) continue;
|
||||
if (read_8bit(offset+44,streamLoops)!='\"') continue;
|
||||
if (read_8bit(offset+44,sf_loop)!='\"') continue;
|
||||
|
||||
for (suboffset = offset+45;
|
||||
suboffset < file_size &&
|
||||
suboffset-offset-45 < length &&
|
||||
tolower(read_8bit(suboffset,streamLoops)) == tolower(namebase[suboffset-offset-45]);
|
||||
tolower(read_8bit(suboffset,sf_loop)) == tolower(namebase[suboffset-offset-45]);
|
||||
suboffset++) {
|
||||
/* skip */
|
||||
}
|
||||
|
||||
if (suboffset-offset-45==length && read_8bit(suboffset,streamLoops)=='\"') { /* tab */
|
||||
if (suboffset-offset-45==length && read_8bit(suboffset,sf_loop)=='\"') { /* tab */
|
||||
found = 1;
|
||||
found_off = offset+22; /* loop end */
|
||||
}
|
||||
@ -234,9 +231,9 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
if (found) {
|
||||
char loopstring[9] = {0};
|
||||
int start_ok = 0, end_ok = 0;
|
||||
int32_t total_samples = read_32bitLE(0x1c,streamFile) / read_16bitLE(0x00,streamFile);
|
||||
int32_t total_samples = read_32bitLE(0x1c,sf) / read_16bitLE(0x00,sf);
|
||||
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off,8,streamLoops)==8)
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off,8,sf_loop)==8)
|
||||
{
|
||||
if (!memcmp("99999999",loopstring,8)) {
|
||||
loop_end_sample = total_samples;
|
||||
@ -246,7 +243,7 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
}
|
||||
end_ok = 1;
|
||||
}
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off+11,8,streamLoops)==8)
|
||||
if (read_streamfile((uint8_t*)loopstring,found_off+11,8,sf_loop)==8)
|
||||
{
|
||||
if (!memcmp("99999999",loopstring,8)) {
|
||||
/* not ok to start at last sample,
|
||||
@ -265,43 +262,14 @@ static int get_loops_gameexe_ini(STREAMFILE *streamFile, int *out_loop_flag, int
|
||||
} /* if found file name in INI */
|
||||
|
||||
|
||||
*out_loop_flag = loop_flag;
|
||||
*out_loop_start = loop_start_sample;
|
||||
*out_loop_end = loop_end_sample;
|
||||
*p_loop_flag = loop_flag;
|
||||
*p_loop_start = loop_start_sample;
|
||||
*p_loop_end = loop_end_sample;
|
||||
|
||||
close_streamfile(streamLoops);
|
||||
close_streamfile(sf_loop);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
close_streamfile(streamLoops);
|
||||
close_streamfile(sf_loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static nwa_codec_data *open_nwa_vgmstream(STREAMFILE *streamFile) {
|
||||
nwa_codec_data *data = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
|
||||
data = malloc(sizeof(nwa_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
data->nwa = open_nwa(streamFile,filename);
|
||||
if (!data->nwa) goto fail;
|
||||
|
||||
return data;
|
||||
|
||||
fail:
|
||||
free_nwa_vgmstream(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_nwa_vgmstream(nwa_codec_data *data) {
|
||||
if (data) {
|
||||
if (data->nwa) {
|
||||
close_nwa(data->nwa);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
@ -756,8 +756,7 @@ void reset_vgmstream(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
|
||||
if (vgmstream->coding_type == coding_NWA) {
|
||||
nwa_codec_data *data = vgmstream->codec_data;
|
||||
if (data) reset_nwa(data->nwa);
|
||||
reset_nwa(vgmstream->codec_data);
|
||||
}
|
||||
|
||||
/* reset custom layouts */
|
||||
@ -950,13 +949,8 @@ void close_vgmstream(VGMSTREAM * vgmstream) {
|
||||
}
|
||||
|
||||
if (vgmstream->coding_type == coding_NWA) {
|
||||
if (vgmstream->codec_data) {
|
||||
nwa_codec_data *data = (nwa_codec_data *) vgmstream->codec_data;
|
||||
if (data->nwa)
|
||||
close_nwa(data->nwa);
|
||||
free(data);
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
free_nwa(vgmstream->codec_data);
|
||||
vgmstream->codec_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -2062,8 +2056,8 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do, vgmstream->channels);
|
||||
break;
|
||||
case coding_NWA:
|
||||
decode_nwa(((nwa_codec_data*)vgmstream->codec_data)->nwa,
|
||||
buffer+samples_written*vgmstream->channels, samples_to_do);
|
||||
decode_nwa(vgmstream->codec_data, buffer+samples_written*vgmstream->channels,
|
||||
samples_to_do);
|
||||
break;
|
||||
case coding_MSADPCM:
|
||||
case coding_MSADPCM_int:
|
||||
@ -2367,9 +2361,7 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
||||
#endif
|
||||
|
||||
if (vgmstream->coding_type == coding_NWA) {
|
||||
nwa_codec_data *data = vgmstream->codec_data;
|
||||
if (data)
|
||||
seek_nwa(data->nwa, vgmstream->loop_sample);
|
||||
seek_nwa(vgmstream->codec_data, vgmstream->loop_sample);
|
||||
}
|
||||
|
||||
/* restore! */
|
||||
@ -2744,8 +2736,7 @@ fail:
|
||||
static STREAMFILE * get_vgmstream_average_bitrate_channel_streamfile(VGMSTREAM * vgmstream, int channel) {
|
||||
|
||||
if (vgmstream->coding_type == coding_NWA) {
|
||||
nwa_codec_data *data = vgmstream->codec_data;
|
||||
return (data && data->nwa) ? data->nwa->file : NULL;
|
||||
return nwa_get_streamfile(vgmstream->codec_data);
|
||||
}
|
||||
|
||||
if (vgmstream->coding_type == coding_ACM) {
|
||||
|
@ -1046,12 +1046,6 @@ typedef struct {
|
||||
} layered_layout_data;
|
||||
|
||||
|
||||
/* for compressed NWA */
|
||||
typedef struct {
|
||||
NWAData *nwa;
|
||||
} nwa_codec_data;
|
||||
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
typedef struct {
|
||||
/*** IO internals ***/
|
||||
|
Loading…
Reference in New Issue
Block a user