2020-07-17 19:15:35 +02:00
|
|
|
|
/* 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:
|
|
|
|
|
*/
|
|
|
|
|
|
2008-08-03 16:58:03 +02:00
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
2017-03-13 06:19:22 +01:00
|
|
|
|
* このプログラムの作者は jagarl です。
|
2008-08-03 16:58:03 +02:00
|
|
|
|
*
|
2017-03-13 06:19:22 +01:00
|
|
|
|
* このプログラム、及びコンパイルによって生成したバイナリは
|
|
|
|
|
* プログラムを変更する、しないにかかわらず再配布可能です。
|
|
|
|
|
* その際、上記 Copyright 表示を保持するなどの条件は課しま
|
|
|
|
|
* せん。対応が面倒なのでバグ報告を除き、メールで連絡をする
|
|
|
|
|
* などの必要もありません。ソースの一部を流用することを含め、
|
|
|
|
|
* ご自由にお使いください。
|
2008-08-03 16:58:03 +02:00
|
|
|
|
*
|
|
|
|
|
* 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"
|
2023-05-14 21:20:29 +02:00
|
|
|
|
#include "../util/reader_sf.h"
|
2020-07-17 19:15:35 +02:00
|
|
|
|
|
|
|
|
|
//NWAInfo::UseRunLength
|
|
|
|
|
static int is_use_runlength(NWAData* nwa) {
|
|
|
|
|
if (nwa->channels == 2 && nwa->bps == 16 && nwa->complevel == 2) {
|
|
|
|
|
return 0; /* sw2 */
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
|
|
|
|
|
if (nwa->complevel == 5) {
|
|
|
|
|
if (nwa->channels == 2)
|
|
|
|
|
return 0; // BGM*.nwa in Little Busters!
|
|
|
|
|
return 1; // Tomoyo After (.nwk koe file)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
NWAData* nwalib_open(STREAMFILE* sf) {
|
|
|
|
|
uint8_t header[0x2c] = {0};
|
2008-08-03 16:58:03 +02:00
|
|
|
|
int i;
|
2020-07-17 19:15:35 +02:00
|
|
|
|
NWAData* const nwa = malloc(sizeof(NWAData));
|
2008-08-03 16:58:03 +02:00
|
|
|
|
if (!nwa) goto fail;
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
//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);
|
|
|
|
|
|
2008-08-03 16:58:03 +02:00
|
|
|
|
nwa->offsets = NULL;
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->outdata = NULL;
|
|
|
|
|
nwa->outdata_readpos = NULL;
|
|
|
|
|
nwa->tmpdata = NULL;
|
|
|
|
|
nwa->filesize = get_streamfile_size(sf);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (nwa->blocks <= 0 || nwa->blocks > 1000000)
|
|
|
|
|
/* 1時間を超える曲ってのはないでしょ*/ //surely there won't be songs over 1 hour
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
// NWAData::CheckHeader:
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (nwa->channels != 1 && nwa->channels != 2)
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (nwa->bps != 8 && nwa->bps != 16)
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
// (PCM not handled)
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (nwa->complevel < 0 || nwa->complevel > 5)
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
if (!nwa->offsets) goto fail;
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
for (i = 0; i < nwa->blocks; i++) {
|
|
|
|
|
int32_t o = read_s32le(0x2c + i*4, sf);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
if (o < 0) goto fail;
|
|
|
|
|
nwa->offsets[i] = o;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (nwa->offsets[nwa->blocks-1] >= nwa->compdatasize)
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->use_runlength = is_use_runlength(nwa);
|
|
|
|
|
nwa->curblock = 0;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
//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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
/* これ以上の大きさはないだろう、、、 */ //probably not over this size
|
|
|
|
|
nwa->tmpdata = malloc(sizeof(uint8_t) * nwa->blocksize * (nwa->bps / 8) * 2);
|
|
|
|
|
if (!nwa->tmpdata)
|
|
|
|
|
goto fail;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->outdata_readpos = nwa->outdata;
|
|
|
|
|
nwa->samples_in_buffer = 0;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
|
|
|
|
return nwa;
|
|
|
|
|
fail:
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwalib_close(nwa);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
void nwalib_close(NWAData * nwa) {
|
2008-08-03 16:58:03 +02:00
|
|
|
|
if (!nwa) return;
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
free(nwa->offsets);
|
|
|
|
|
free(nwa->outdata);
|
|
|
|
|
free(nwa->tmpdata);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
free(nwa);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
//NWAData::Rewind
|
|
|
|
|
void nwalib_reset(NWAData* nwa) {
|
2008-08-03 16:58:03 +02:00
|
|
|
|
nwa->curblock = 0;
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->outdata_readpos = nwa->outdata;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
nwa->samples_in_buffer = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
// 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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
|
|
|
|
|
ret = get_s16le(*p_data) >> *shift;
|
|
|
|
|
*shift += bits;
|
|
|
|
|
return ret & ((1 << bits) - 1); /* mask */
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
// NWADecode
|
|
|
|
|
static void decode_block(NWAData* nwa, const uint8_t* data, int outdatasize) {
|
|
|
|
|
sample d[2];
|
|
|
|
|
int i;
|
|
|
|
|
int shift = 0;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
}
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
else {
|
|
|
|
|
BITS = 8 - nwa->complevel;
|
|
|
|
|
SHIFT = 2 + 7 + nwa->complevel;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-03 16:58:03 +02:00
|
|
|
|
{
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
else
|
2020-07-17 19:15:35 +02:00
|
|
|
|
d[flip_flag] += (b & MASK2) << SHIFT;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
2008-08-03 16:58:03 +02:00
|
|
|
|
{
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
else
|
2020-07-17 19:15:35 +02:00
|
|
|
|
d[flip_flag] += (b & MASK2) << SHIFT;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
}
|
|
|
|
|
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);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
}
|
|
|
|
|
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
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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?
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
return 0;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
//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);
|
2008-08-03 17:21:05 +02:00
|
|
|
|
|
|
|
|
|
nwa->curblock = dest_block;
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwalib_decode(sf, nwa);
|
2008-08-03 17:21:05 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->outdata_readpos = nwa->outdata + remainder * nwa->channels;
|
2008-08-03 17:21:05 +02:00
|
|
|
|
nwa->samples_in_buffer -= remainder*nwa->channels;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
/* ****************************************************************** */
|
|
|
|
|
|
|
|
|
|
#include "coding.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct nwa_codec_data {
|
|
|
|
|
STREAMFILE* sf;
|
|
|
|
|
NWAData* nwa;
|
|
|
|
|
};
|
|
|
|
|
|
2008-08-03 16:58:03 +02:00
|
|
|
|
/* interface to vgmstream */
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
if (samples_to_read > samples_to_do)
|
|
|
|
|
samples_to_read = samples_to_do;
|
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
memcpy(outbuf, nwa->outdata_readpos, sizeof(sample_t) * samples_to_read * nwa->channels);
|
2008-08-03 16:58:03 +02:00
|
|
|
|
|
2020-07-17 19:15:35 +02:00
|
|
|
|
nwa->outdata_readpos += samples_to_read * nwa->channels;
|
|
|
|
|
nwa->samples_in_buffer -= samples_to_read * nwa->channels;
|
|
|
|
|
outbuf += samples_to_read * nwa->channels;
|
2008-08-03 16:58:03 +02:00
|
|
|
|
samples_to_do -= samples_to_read;
|
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
else {
|
|
|
|
|
int err = nwalib_decode(data->sf, nwa);
|
|
|
|
|
if (err < 0) {
|
|
|
|
|
VGM_LOG("NWA: decoding error\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-08-03 16:58:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-17 19:15:35 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
nwa_codec_data* init_nwa(STREAMFILE* sf) {
|
2020-07-18 00:27:53 +02:00
|
|
|
|
nwa_codec_data* data = NULL;
|
2020-07-17 19:15:35 +02:00
|
|
|
|
|
|
|
|
|
data = malloc(sizeof(nwa_codec_data));
|
|
|
|
|
if (!data) goto fail;
|
|
|
|
|
|
|
|
|
|
data->nwa = nwalib_open(sf);
|
|
|
|
|
if (!data->nwa) goto fail;
|
|
|
|
|
|
2020-07-18 00:27:53 +02:00
|
|
|
|
data->sf = reopen_streamfile(sf, 0);
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (!data->sf) goto fail;
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
free_nwa(data);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-18 00:27:53 +02:00
|
|
|
|
void seek_nwa(nwa_codec_data* data, int32_t sample) {
|
2020-07-17 19:15:35 +02:00
|
|
|
|
if (!data) return;
|
|
|
|
|
|
|
|
|
|
nwalib_seek(data->sf, data->nwa, sample);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-18 00:27:53 +02:00
|
|
|
|
void reset_nwa(nwa_codec_data* data) {
|
2020-07-17 19:15:35 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|