diff --git a/readme.txt b/readme.txt index a21ed045..660c3f40 100644 --- a/readme.txt +++ b/readme.txt @@ -105,7 +105,7 @@ File types supported by this version of vgmstream: - .wav (8/16 bit PCM) - .lwav (8/16 bit PCM) - .pos (loop info for .wav) -- .nwa (16 bit PCM) +- .nwa (16 bit PCM, NWA DPCM) - .xss (16 bit PCM) - .sl3 (PS2 ADPCM) - .hgc1 (PS2 ADPCM) diff --git a/src/Makefile b/src/Makefile index 36072942..f95c5230 100644 --- a/src/Makefile +++ b/src/Makefile @@ -12,7 +12,8 @@ CODING_OBJS=coding/adx_decoder.o \ coding/sdx2_decoder.o \ coding/ws_decoder.o \ coding/mpeg_decoder.o \ - coding/acm_decoder.o + coding/acm_decoder.o \ + coding/nwa_decoder.o LAYOUT_OBJS=layout/ast_blocked.o \ layout/blocked.o \ diff --git a/src/coding/Makefile.unix.am b/src/coding/Makefile.unix.am index e373b14f..2860fbdf 100644 --- a/src/coding/Makefile.unix.am +++ b/src/coding/Makefile.unix.am @@ -20,5 +20,6 @@ libcoding_la_SOURCES += sdx2_decoder.c libcoding_la_SOURCES += ws_decoder.c libcoding_la_SOURCES += mpeg_decoder.c libcoding_la_SOURCES += acm_decoder.c +libcoding_la_SOURCES += nwa_decoder.c EXTRA_DIST = coding.h g72x_state.h diff --git a/src/coding/coding.h b/src/coding/coding.h index 8b6bdce9..12ae8db3 100644 --- a/src/coding/coding.h +++ b/src/coding/coding.h @@ -64,4 +64,6 @@ void decode_mpeg(VGMSTREAMCHANNEL * stream, void decode_acm(ACMStream * acm, sample * outbuf, int32_t samples_to_do, int channelspacing); +void decode_nwa(NWAData *nwa, sample *outbuf, int32_t samples_to_do); + #endif diff --git a/src/coding/nwa_decoder.c b/src/coding/nwa_decoder.c new file mode 100644 index 00000000..1a77a627 --- /dev/null +++ b/src/coding/nwa_decoder.c @@ -0,0 +1,333 @@ +/* originally from nwatowav.cc 2007.7.28 version, which read: */ +/* + * Copyright 2001-2007 jagarl / Kazunori Ueno + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * このプログラムの作者は jagarl です。 + * + * このプログラム、及びコンパイルによって生成したバイナリは + * プログラムを変更する、しないにかかわらず再配布可能です。 + * その際、上記 Copyright 表示を保持するなどの条件は課しま + * せん。対応が面倒なのでバグ報告を除き、メールで連絡をする + * などの必要もありません。ソースの一部を流用することを含め、 + * ご自由にお使いください。 + * + * 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 +#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) +{ + /* 今回読み込む/デコードするデータの大きさを得る */ + 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 用 */ + int runlength = 0; + + /* read initial sample value */ + for (i=0;ichannels;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; +} + +/* 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); + } + } +} diff --git a/src/coding/nwa_decoder.h b/src/coding/nwa_decoder.h new file mode 100644 index 00000000..1763df25 --- /dev/null +++ b/src/coding/nwa_decoder.h @@ -0,0 +1,66 @@ +/* originally from nwatowav.cc 2007.7.28 version, which read: */ +/* + * Copyright 2001-2007 jagarl / Kazunori Ueno + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * このプログラムの作者は jagarl です。 + * + * このプログラム、及びコンパイルによって生成したバイナリは + * プログラムを変更する、しないにかかわらず再配布可能です。 + * その際、上記 Copyright 表示を保持するなどの条件は課しま + * せん。対応が面倒なのでバグ報告を除き、メールで連絡をする + * などの必要もありません。ソースの一部を流用することを含め、 + * ご自由にお使いください。 + * + * 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. + * + */ + +#ifndef _NWA_DECODER_H +#define _NWA_DECODER_H + +#include "../streamfile.h" + +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 curblock; + off_t *offsets; + + STREAMFILE *file; + + /* temporarily store samples */ + sample *buffer; + sample *buffer_readpos; + int samples_in_buffer; +} NWAData; + +NWAData *open_nwa(STREAMFILE *streamFile, const char *filename); +void close_nwa(NWAData *nwa); +void reset_nwa(NWAData *nwa); + +#endif diff --git a/src/libvgmstream.vcproj b/src/libvgmstream.vcproj index 474581f8..b265b8a8 100644 --- a/src/libvgmstream.vcproj +++ b/src/libvgmstream.vcproj @@ -546,6 +546,10 @@ RelativePath=".\coding\g72x_state.h" > + + + + diff --git a/src/meta/nwa.c b/src/meta/nwa.c index e6a3ccad..57794f0d 100644 --- a/src/meta/nwa.c +++ b/src/meta/nwa.c @@ -1,5 +1,6 @@ #include "meta.h" #include "../util.h" +#include "../coding/nwa_decoder.h" #include #include @@ -9,14 +10,7 @@ #define DIRSEP '/' #endif -/* NWA - Visual Arts streams - * - * This can apparently get a lot more complicated, I'm only handling the - * raw PCM case at the moment (until I see something else). - * - * Kazunori "jagarl" Ueno's nwatowav was helpful, and will probably be used - * to write coding support if it comes to that. - */ +/* NWA - Visual Art's streams */ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; @@ -28,19 +22,38 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { int32_t loop_end_sample = 0; int nwainfo_ini_found = 0; int gameexe_ini_found = 0; + int just_pcm = 0; + int comp_level = -2; + nwa_codec_data *data = NULL; /* check extension, case insensitive */ streamFile->get_name(streamFile,filename,sizeof(filename)); if (strcasecmp("nwa",filename_extension(filename))) goto fail; - /* check that we're using raw pcm */ + channel_count = read_16bitLE(0x00,streamFile); + 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 */ - ) goto fail; + 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 */ + ) + { + just_pcm = 1; + } + else + { + comp_level = read_32bitLE(0x08,streamFile); + + data = malloc(sizeof(nwa_codec_data)); + if (!data) goto fail; + + data->nwa = open_nwa(streamFile,filename); + if (!data->nwa) goto fail; + } /* try to locate NWAINFO.INI in the same directory */ { @@ -132,8 +145,6 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { streamFile->get_realname(streamFile,namebase_array,sizeof(namebase_array)); - channel_count = read_16bitLE(0x00,streamFile); - ini_lastslash = strrchr(ininame,DIRSEP); if (!ini_lastslash) { strncpy(ininame,"Gameexe.ini",sizeof(ininame)); @@ -238,22 +249,54 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { /* fill in the vital statistics */ vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x04,streamFile); - switch (read_16bitLE(0x02,streamFile)) { - case 16: - vgmstream->coding_type = coding_PCM16LE; - vgmstream->interleave_block_size = 2; - break; - case 8: - vgmstream->coding_type = coding_PCM8; - vgmstream->interleave_block_size = 1; - break; - default: - goto fail; - } + vgmstream->num_samples = read_32bitLE(0x1c,streamFile)/channel_count; - if (channel_count > 1) { - vgmstream->layout_type = layout_interleave; - } else { + + if (just_pcm) { + switch (read_16bitLE(0x02,streamFile)) { + case 8: + vgmstream->coding_type = coding_PCM8; + vgmstream->interleave_block_size = 1; + break; + case 16: + vgmstream->coding_type = coding_PCM16LE; + vgmstream->interleave_block_size = 2; + break; + default: + goto fail; + } + if (channel_count > 1) { + vgmstream->layout_type = layout_interleave; + } else { + vgmstream->layout_type = layout_none; + } + } + else + { + switch (comp_level) + { + case 0: + vgmstream->coding_type = coding_NWA0; + break; + case 1: + vgmstream->coding_type = coding_NWA1; + break; + case 2: + vgmstream->coding_type = coding_NWA2; + break; + case 3: + vgmstream->coding_type = coding_NWA3; + break; + case 4: + vgmstream->coding_type = coding_NWA4; + break; + case 5: + vgmstream->coding_type = coding_NWA5; + break; + default: + goto fail; + break; + } vgmstream->layout_type = layout_none; } @@ -274,8 +317,8 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { } - /* open the file for reading by each channel */ - { + if (just_pcm) { + /* open the file for reading by each channel */ STREAMFILE *chstreamfile; /* have both channels use the same buffer, as interleave is so small */ @@ -290,11 +333,22 @@ VGMSTREAM * init_vgmstream_nwa(STREAMFILE *streamFile) { vgmstream->ch[i].offset=0x2c+(off_t)(i*vgmstream->interleave_block_size); } } + else + { + vgmstream->codec_data = data; + } return vgmstream; /* clean up anything we may have opened */ fail: if (vgmstream) close_vgmstream(vgmstream); + if (data) { + if (data->nwa) + { + close_nwa(data->nwa); + } + free(data); + } return NULL; } diff --git a/src/vgmstream.c b/src/vgmstream.c index a75cc75e..9a4918ea 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -222,6 +222,18 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { reset_vgmstream(data->adxs[i]); } } + + if ( + vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5 + ) { + nwa_codec_data *data = vgmstream->codec_data; + reset_nwa(data->nwa); + } } /* simply allocate memory for the VGMSTREAM and its channels */ @@ -236,6 +248,12 @@ VGMSTREAM * allocate_vgmstream(int channel_count, int looped) { vgmstream = calloc(1,sizeof(VGMSTREAM)); if (!vgmstream) return NULL; + + vgmstream->ch = NULL; + vgmstream->start_ch = NULL; + vgmstream->loop_ch = NULL; + vgmstream->start_vgmstream = NULL; + vgmstream->codec_data = NULL; start_vgmstream = calloc(1,sizeof(VGMSTREAM)); if (!start_vgmstream) { @@ -360,6 +378,24 @@ void close_vgmstream(VGMSTREAM * vgmstream) { free(data); } + vgmstream->codec_data = NULL; + } + + if ( + vgmstream->coding_type == coding_NWA0 || + vgmstream->coding_type == coding_NWA1 || + vgmstream->coding_type == coding_NWA2 || + vgmstream->coding_type == coding_NWA3 || + vgmstream->coding_type == coding_NWA4 || + vgmstream->coding_type == coding_NWA5 + ) { + nwa_codec_data *data = vgmstream->codec_data; + + close_nwa(data->nwa); + + free(data); + + vgmstream->codec_data = NULL; } /* now that the special cases have had their chance, clean up the standard items */ @@ -465,6 +501,12 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_SDX2: case coding_SDX2_int: case coding_ACM: + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: return 1; case coding_NDS_IMA: return (vgmstream->interleave_block_size-4)*2; @@ -523,6 +565,12 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) { case coding_PCM8_SB_int: case coding_SDX2: case coding_SDX2_int: + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: return 1; case coding_NDS_IMA: return vgmstream->interleave_block_size; @@ -794,6 +842,17 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to case coding_ACM: /* handled in its own layout, here to quiet compiler */ break; + case coding_NWA0: + case coding_NWA1: + case coding_NWA2: + case coding_NWA3: + case coding_NWA4: + case coding_NWA5: + decode_nwa(((nwa_codec_data*)vgmstream->codec_data)->nwa, + buffer+samples_written*vgmstream->channels, + samples_to_do + ); + break; } } @@ -1065,6 +1124,24 @@ void describe_vgmstream(VGMSTREAM * vgmstream, char * desc, int length) { case coding_ACM: snprintf(temp,TEMPSIZE,"InterPlay ACM"); break; + case coding_NWA0: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 0"); + break; + case coding_NWA1: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 1"); + break; + case coding_NWA2: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 2"); + break; + case coding_NWA3: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 3"); + break; + case coding_NWA4: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 4"); + break; + case coding_NWA5: + snprintf(temp,TEMPSIZE,"NWA DPCM Level 5"); + break; default: snprintf(temp,TEMPSIZE,"CANNOT DECODE"); } diff --git a/src/vgmstream.h b/src/vgmstream.h index b6d3daef..551c585a 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -21,6 +21,7 @@ #include #endif #include "coding/acm_decoder.h" +#include "coding/nwa_decoder.h" /* The encoding type specifies the format the sound data itself takes */ typedef enum { @@ -79,6 +80,13 @@ typedef enum { #endif coding_ACM, /* InterPlay ACM */ + /* compressed NWA at various levels */ + coding_NWA0, + coding_NWA1, + coding_NWA2, + coding_NWA3, + coding_NWA4, + coding_NWA5, } coding_t; /* The layout type specifies how the sound data is laid out in the file */ @@ -407,6 +415,11 @@ typedef struct { VGMSTREAM **adxs; } aix_codec_data; +/* for compressed NWA */ +typedef struct { + NWAData *nwa; +} nwa_codec_data; + /* do format detection, return pointer to a usable VGMSTREAM, or NULL on failure */ VGMSTREAM * init_vgmstream(const char * const filename);