vgmstream/src/coding/nwa_decoder.c

334 lines
10 KiB
C
Raw Normal View History

/* originally from nwatowav.cc 2007.7.28 version, which read: */
/*
* Copyright 2001-2007 jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* <EFBFBD><EFBFBD><EFBFBD>Υץ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><EFBFBD>Ԥ<EFBFBD> jagarl <EFBFBD>Ǥ<EFBFBD><EFBFBD><EFBFBD>
*
* <EFBFBD><EFBFBD><EFBFBD>Υץ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڤӥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˤ<EFBFBD><EFBFBD>ä<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Х<EFBFBD><EFBFBD>ʥ<EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD>ץ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʤ<EFBFBD><EFBFBD>ˤ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>۲<EFBFBD>ǽ<EFBFBD>Ǥ<EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD>κݡ<EFBFBD><EFBFBD> Copyright ɽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʤɤξ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϲݤ<EFBFBD><EFBFBD><EFBFBD>
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݤʤΤǥХ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><EFBFBD><EFBFBD>򤹤<EFBFBD>
* <EFBFBD>ʤɤ<EFBFBD>ɬ<EFBFBD>פ<EFBFBD><EFBFBD><EFBFBD>ޤ<EFBFBD><EFBFBD>󡣥<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ΰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ή<EFBFBD>Ѥ<EFBFBD><EFBFBD><EFBFBD>Ȥ<EFBFBD><EFBFBD>ޤ
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͳ<EFBFBD>ˤ<EFBFBD><EFBFBD>Ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``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 KAZUNORI UENO 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.
*
*/
#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)
{
if (*shift > 8)
{
++*offset;
*shift -= 8;
}
int ret = read_16bitLE(*offset,file) >> *shift;
*shift += bits;
return ret & ((1 << bits) - 1); /* mask */
}
NWAData *
open_nwa (STREAMFILE * streamFile, const char *filename)
{
int i;
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);
nwa->offsets = NULL;
nwa->buffer = NULL;
nwa->buffer_readpos = NULL;
nwa->file = NULL;
/* PCM not handled here */
if (nwa->complevel < 0 || nwa->complevel > 5) goto fail;
if (nwa->channels != 1 && nwa->channels != 2) goto fail;
if (nwa->bps != 8 && nwa->bps != 16) goto fail;
if (nwa->blocks <= 0) goto fail;
if (nwa->compdatasize == 0
|| get_streamfile_size(streamFile) != 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;
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);
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;
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;
return nwa;
fail:
if (nwa)
{
close_nwa(nwa);
free(nwa);
}
return NULL;
}
void
close_nwa(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);
}
void
reset_nwa(NWAData *nwa)
{
nwa->curblock = 0;
nwa->buffer_readpos = nwa->buffer;
nwa->samples_in_buffer = 0;
}
static int use_runlength(NWAData *nwa)
{
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2)
{
/* sw2 */
return 0;
}
if (nwa->complevel == 5)
{
if (nwa->channels == 2) return 0; /* BGM*.nwa in Little Busters! */
return 1; /* Tomoyo After (.nwk koe file) */
}
return 0;
}
static void
nwa_decode_block(NWAData *nwa)
{
/* <20><><EFBFBD><EFBFBD><EFBFBD>ɤ߹<C9A4><DFB9><EFBFBD>ǥ<EFBFBD><C7A5><EFBFBD><EFBFBD>ɤ<EFBFBD><C9A4><EFBFBD><EFBFBD>ǡ<EFBFBD><C7A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E7A4AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
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];
}
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 <20><> */
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)
{ /* <20><><EFBFBD>ԡ<EFBFBD><D4A1><EFBFBD><EBA1BC><EFBFBD><EFBFBD><EFBFBD>Ǥʤ<C7A4><CAA4>ʤ<EFBFBD><CAA4>ǡ<EFBFBD><C7A1><EFBFBD><EFBFBD>ɤ߹<C9A4><DFB9><EFBFBD> */
int type = getbits(nwa->file, &offset, &shift, 3);
/* type <20>ˤ<EFBFBD><CBA4><EFBFBD>ʬ<EFBFBD><CAAC><EFBFBD><EFBFBD>0, 1-6, 7 */
if (type == 7)
{
/* 7 : <20><EFBFBD>ʺ<EFBFBD>ʬ */
/* RunLength() ͭ<><CDAD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>CompLevel==5, <20><><EFBFBD><EFBFBD><EFBFBD>ե<EFBFBD><D5A5><EFBFBD><EFBFBD><EFBFBD>) <20>Ǥ<EFBFBD>̵<EFBFBD><CCB5> */
if (getbits(nwa->file, &offset, &shift, 1) == 1)
{
d[flip_flag] = 0; /* ̤<><CCA4><EFBFBD><EFBFBD> */
}
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 : <20>̾<EFBFBD><CCBE>κ<EFBFBD>ʬ */
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 */
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󥰥<EFBFBD><F3A5B0A5><EFBFBD><EFBFBD>̤ʤ<CCA4><CAA4>ξ<EFBFBD><CEBE><EFBFBD><EFBFBD>Ϥʤˤ⤷<CBA4>ʤ<EFBFBD> */
if (use_runlength(nwa))
{
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>󥰥<EFBFBD><F3A5B0A5><EFBFBD><EFBFBD>̤<EFBFBD><CCA4><EFBFBD><EFBFBD>ξ<EFBFBD><CEBE><EFBFBD> */
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 <20>ڤ<EFBFBD><DAA4>ؤ<EFBFBD> */
}
}
nwa->curblock++;
return;
}
/* 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;
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);
nwa->buffer_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);
}
}
}