root/music2/nwatowav.cc

Revision 65:4416cfac86ae, 27.0 KB (checked in by Thibaut Girka <thib@…>, 18 months ago)
Convert EUC-JP files to UTF8
Line 
1/* nwatowav : Visual Arts 系のゲヌムのデモで䜿われる nwa 圢匏の
2**            ファむルを wav 圢匏に倉換する
3**
4**     compile : gcc -O2 -o nwatowav nwatowav.cc
5**     usage : nwatowav [nwa-file [outfile]]
6**             nwatowav [nwk-file [outfile]]
7**     example : nwatowav HM06.nwa HM06.wav     # BGMファむル。HM06.wav に展開される
8**               nwatowav z2813.nwk z2813       # 音声ファむル。 z2813-100.wav などのファむル名で展開される
9**               nwatowav z0513.ovk z0513       # 音声ファむル。 z0513-100.ogg などのファむル名で展開される
10**
11**
12** 2004.5.19 小束さん<s1100089@u-aizu.ac.jp> から CLANNAD の無圧瞮nwa圢匏に察応する
13**           ãƒ‘ッチをいただいたので、適甚したした。ありがずうございたす。
14** 2006.9.10 「智代アフタヌ」の音声ファむル圢匏 (complevel = 5) をサポヌト
15**           .nwk ずいう拡匵子を持぀ファむルを受け取るず音声ファむルずしお
16**           è§£é‡ˆã€åˆ†å‰²ã—お展開するようにする
17** 2007.7.28 「リトルバスタヌズ」の音声ファむル圢匏 (*.ovk; ogg 連結型)
18**              をサポヌト。.ovk ずいう拡匵子をも぀ファむルを受け取るず
19**              音声ファむルずしお解釈、分割しお展開するようにする
20**           ã€Œãƒªãƒˆãƒ«ãƒã‚¹ã‚¿ãƒŒã‚ºïŒã€ã®BGMファむルに倚量のノむズが乗る問題も
21**           ã€€è§£æ±ºïŒˆãƒ©ãƒ³ãƒ¬ãƒ³ã‚°ã‚¹åœ§çž®ã®å‡Šç†ãŒäžå¿…芁だった
22*/
23
24/*
25 * Copyright 2001-2007  jagarl / Kazunori Ueno <jagarl@creator.club.ne.jp>
26 * All Rights Reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted.
30 *
31 * このプログラムの䜜者は jagarl です。
32 *
33 * このプログラム、及びコンパむルによっお生成したバむナリは
34 * プログラムを倉曎する、しないにかかわらず再配垃可胜です。
35 * その際、䞊蚘 Copyright 衚瀺を保持するなどの条件は課した
36 * せん。察応が面倒なのでバグ報告を陀き、メヌルで連絡をする
37 * などの必芁もありたせん。゜ヌスの䞀郚を流甚するこずを含め、
38 * ご自由にお䜿いください。
39 *
40 * THIS SOFTWARE IS PROVIDED BY KAZUNORI 'jagarl' UENO ``AS IS'' AND ANY
41 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL KAZUNORI UENO BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
45 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
46 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
47 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
50 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
51 * DAMAGE.
52 *
53 */
54
55/********************************************
56**
57**      nwa フォヌマットに぀いお
58**
59**              党䜓ずしおは以䞋の構造を持぀
60**              NWA Header
61**              data offset index
62**              data block<0>
63**              data block<1>
64**              ...
65**              data block<N>
66**
67**      NWA Header: ファむル先頭から 44 bytes
68**              magic number などはないのでnwa ファむルかは
69**              デヌタの敎合性から刀断する必芁がある
70**              デヌタは党お little endian で、
71**              short(signed 2byte)たたは int(signed 4byte) である。
72**
73**              +00 short   channel 数(1/2)
74**              +02 short   sample 䞀぀あたりの bit 数(16)
75**              +04 int     å‘šæ³¢æ•°(䞀秒あたりのデヌタ数)
76**              +08 int     åœ§çž®ãƒ¬ãƒ™ãƒ«ïŒš-1~5.2で最小のデヌタ、0で最倧の埩元床(-1は無圧瞮rawデヌタずみなされる)
77**              +12 int     ?
78**              +16 int     ãƒ–ロック数
79**              +20 int     å±•開埌のデヌタの倧きさ(バむト単䜍)
80**              +24 int     åœ§çž®æ™‚のデヌタの倧きさ(nwa ファむルの倧きさ。バむト単䜍)
81**              +28 int     ã‚µãƒ³ãƒ—ル数展開埌のデヌタ数(16bit dataなら short 単䜍==サンプル単䜍のデヌタの倧きさ)
82**              +32 int     ãƒ‡ãƒŒã‚¿ïŒ‘ブロックを展開した時のサンプル単䜍のデヌタ数
83**              +36 int     æœ€çµ‚ブロックを展開した時のサンプル単䜍のデヌタ数
84**              +40 int     ?
85**             
86**      data offset index
87**              党ブロック数 x 4 byte のデヌタ
88**              それぞれ int のデヌタが党ブロック数続いおいる
89**
90**              デヌタブロックの先頭を指すファむル先頭からの䜍眮(オフセット)
91**              が栌玍されおいる
92**
93**      data block
94**              長さは可倉。展開するこずで䞀定の倧きさをも぀デヌタに展開される。
95**              デヌタはDPCM圢匏。元 PCM デヌタが a,b,c ならば (a),b-a, c-b ず
96**              いった差分デヌタが、仮数3-5bit,指数3bitの圢匏で保存されおいる。
97**              結果的に、16bit のデヌタが倚くの堎合 6-8bit で栌玍される。
98**              仮数のビット数は圧瞮レベル0で5bit、圧瞮レベル2で3bitずなる。
99**              以䞋、圧瞮レベル2の堎合に぀いお話を進める。
100**              モノラルの堎合
101**                      +00 short  ブロック内の最初のデヌタ
102**                      +02- bit stream
103**              ステレオの堎合
104**                      +00 short  å·Š(?)チャンネルの最初のデヌタ
105**                      +02 short  右(?)チャンネルの最初のデヌタ
106**                      +04- bit stream
107**
108**              差分デヌタの粟床が高くないので各ブロックの先頭で
109**              正確なデヌタにより補正される()
110**
111**      bit stream
112**              little endian
113**              +0 - +2 : 指数
114**              +3 - +5 : 仮数
115**              の圢匏。䟋えば a,b,c ずいう8bitデヌタがあれば、
116**              a&0x07 : デヌタの指数
117**              (a>>3)&0x07 : デヌタの仮数(signed ;
118**              ((b<<2)|(a>>6))&0x07 : デヌタの指数
119**              (b>>1)&0x07 : デヌタの仮数
120**              ずなる。
121**              ただし、指数の倀により仮数のbit数が倉化するこずがある。
122**              指数 = 1 - 6 の堎合
123**                      a=指数、b=仮数、p=前のデヌタずしお、今回のデヌタd は
124**                      bの2bit目が立っおいる堎合
125**                              d = p - (b&3)<<(4+a)
126**                      立っおない堎合
127**                              d = p + (b&3)<<(4+a)
128**              指数 = 0 の堎合仮数は存圚しない(デヌタは3bitずなる)
129**                      d = p
130**                      「智代アフタヌ」の音声ファむル (complevel == 5) ではランレングス圧瞮甚に䜿われおいる。
131**              指数 = 7
132**                      次の bit が立っおいる堎合
133**                              d = 0 (珟圚未䜿甚)
134**                              (デヌタは4bitずなる)
135**                      次の bit が立っおない堎合
136**                              complevel = 0,1,2:
137**                                 ä»®æ•° b = 6bit
138**                                 b の 5bit 目が立っおいる堎合
139**                                      d = p - (b&0x1f)<<(4+7)
140**                                 ç«‹ã£ãŠãªã„堎合
141**                                      d = p + (b&0x1f)<<(4+7)
142**                                 (デヌタは10bitずなる)
143**                              complevel = 3,4,5:
144**                                 ä»®æ•° b = 8bit
145**                                 b の 7bit 目が立っおいる堎合
146**                                      d = p - (b&0x7f)<<9
147**                                 ç«‹ã£ãŠãªã„堎合
148**                                      d = p + (b&0x1f)<<9
149**                                 (デヌタは10bitずなる)
150**
151**              圧瞮レベルが異なる堎合、たずえば圧瞮レベル==0で
152**                      指数==1~6でdの最䞊䜍bitが立っおいる堎合
153**                              d = p - (b&0x0f)<<(2+a)
154**                      指数==7でdの最䞊䜍bitが立っおいる堎合
155**                              d = p - (b&0x7f)<<(2+7)
156**                              (b : 8bitなのでデヌタは12bitずなる)
157**              のように、粟床だけが倉化するようになっおいる。
158**
159**      ヘッダ読み蟌みに぀いおはNWAData::ReadHeader()参照
160**      bit stream からのデヌタ展開に぀いおは NWADecode()参照
161**************************************************************
162*/
163
164// #define NDEBUG /* なぜか assertが入った方が速い、、、 */
165
166#include <stdio.h>
167#include <stdlib.h>
168#include <unistd.h>     // for isatty() function
169#include <sys/stat.h>
170#include <string.h>
171
172
173#ifdef WORDS_BIGENDIAN
174#error Sorry, This program does not support BIG-ENDIAN system yet.
175/* もし big endian のシステムに察応させる堎合
176** 以䞋の *_little_endian_* 及び
177** getbits() 関数を倉曎する必芁がある
178*/
179#endif
180
181inline int read_little_endian_int(const char* buf) {
182        return *(int*)buf;
183}
184
185inline int read_little_endian_short(const char* buf) {
186        return *(short*)buf;
187}
188
189inline int write_little_endian_int(char* buf, int number) {
190        int c = *(int*)buf; *(int*)buf = number; return c;
191}
192
193inline int write_little_endian_short(char* buf, int number) {
194        int c = *(short*)buf; *(short*)buf = number; return c;
195}
196inline int getbits(const char*& data, int& shift, int bits) {
197        if (shift > 8) { data++; shift-=8;}
198        int ret = read_little_endian_short(data)>>shift;
199        shift += bits;
200        return ret & ((1<<bits)-1); /* mask */
201}
202
203/* 指定された圢匏のヘッダを぀くる */
204const char* make_wavheader(int size, int channels, int bps, int freq) {
205        static char wavheader[0x2c] = {
206                'R','I','F','F',
207                0,0,0,0, /* +0x04: riff size*/
208                'W','A','V','E',
209                'f','m','t',' ',
210                16,0,0,0, /* +0x10 : fmt size=0x10 */
211                1, 0,    /* +0x14 : tag : pcm = 1 */
212                2, 0,    /* +0x16 : channels */
213                0,0,0,0, /* +0x18 : samples per second */
214                0,0,0,0, /* +0x1c : average bytes per second */
215                0,0,     /* +0x20 : block alignment */
216                0,0,     /* +0x22 : bits per sample */
217                'd','a','t','a',
218                0,0,0,0};/* +0x28 : data size */
219        write_little_endian_int(wavheader+0x04, size+0x24);
220        write_little_endian_int(wavheader+0x28, size);
221        write_little_endian_short(wavheader+0x16, channels);
222        write_little_endian_short(wavheader+0x22, bps);
223        write_little_endian_int(wavheader+0x18, freq);
224        int byps = (bps+7)>>3;
225        write_little_endian_int(wavheader+0x1c, freq*byps*channels);
226        write_little_endian_short(wavheader+0x20, byps*channels);
227        return wavheader;
228}
229
230/* NWA の bitstream展開に必芁ずなる情報 */
231class NWAInfo {
232        private:
233                int channels;
234                int bps;
235                int complevel;
236                bool use_runlength;
237        public:
238                NWAInfo(int c,int b,int cl) {
239                        channels=c;
240                        bps=b;
241                        complevel=cl;
242                        use_runlength = false;
243                        if (cl == 5) {
244                                use_runlength = true; // Tomoyo After (.nwk koe file)
245                                if (channels == 2) use_runlength = false; // BGM*.nwa in Little Busters!
246                        }
247                }
248                int Channels(void) const{return channels;}
249                int Bps(void) const { return bps;}
250                int CompLevel(void) const { return complevel;}
251                int UseRunLength(void) const { return use_runlength; }
252};
253
254template<class NWAI> void NWADecode(const NWAI& info,const char* data, char* outdata, int datasize, int outdatasize) {
255        int d[2];
256        int i;
257        int shift = 0;
258        const char* dataend = data+datasize;
259        /* 最初のデヌタを読み蟌む */
260        if (info.Bps() == 8) {d[0] = *data++; datasize--;}
261        else /* info.Bps() == 16 */ {d[0] = read_little_endian_short(data); data+=2; datasize-=2;}
262        if (info.Channels() == 2) {
263                if (info.Bps() == 8) {d[1] = *data++; datasize--;}
264                else /* info.Bps() == 16 */ {d[1] = read_little_endian_short(data); data+=2; datasize-=2;}
265        }
266        int dsize = outdatasize / (info.Bps()/8);
267        int flip_flag = 0; /* stereo 甹 */
268        int runlength = 0;
269        for (i=0; i<dsize; i++) {
270                if (data >= dataend) break;
271                if (runlength == 0) { // コピヌルヌプ䞭でないならデヌタ読み蟌み
272                        int type = getbits(data, shift, 3);
273                        /* type により分岐0, 1-6, 7 */
274                        if (type == 7) {
275                                /* 7 : 倧きな差分 */
276                                /* RunLength() 有効時CompLevel==5, 音声ファむル) では無効 */
277                                if (getbits(data, shift, 1) == 1) {
278                                        d[flip_flag] = 0; /* 未䜿甚 */
279                                } else {
280                                        int BITS, SHIFT;
281                                        if (info.CompLevel() >= 3) {
282                                                BITS = 8;
283                                                SHIFT = 9;
284                                        } else {
285                                                BITS = 8-info.CompLevel();
286                                                SHIFT = 2+7+info.CompLevel();
287                                        }
288                                        const int MASK1 = (1<<(BITS-1));
289                                        const int MASK2 = (1<<(BITS-1))-1;
290                                        int b = getbits(data, shift, BITS);
291                                        if (b&MASK1)
292                                                d[flip_flag] -= (b&MASK2)<<SHIFT;
293                                        else
294                                                d[flip_flag] += (b&MASK2)<<SHIFT;
295                                }
296                        } else if (type != 0) {
297                                /* 1-6 : 通垞の差分 */
298                                int BITS, SHIFT;
299                                if (info.CompLevel() >= 3) {
300                                        BITS = info.CompLevel()+3;
301                                        SHIFT = 1+type;
302                                } else {
303                                        BITS = 5-info.CompLevel();
304                                        SHIFT = 2+type+info.CompLevel();
305                                }
306                                const int MASK1 = (1<<(BITS-1));
307                                const int MASK2 = (1<<(BITS-1))-1;
308                                int b = getbits(data, shift, BITS);
309                                if (b&MASK1)
310                                        d[flip_flag] -= (b&MASK2)<<SHIFT;
311                                else
312                                        d[flip_flag] += (b&MASK2)<<SHIFT;
313                        } else { /* type == 0 */
314                                /* ランレングス圧瞮なしの堎合はなにもしない */
315                                if (info.UseRunLength() == true) {
316                                        /* ランレングス圧瞮ありの堎合 */
317                                        runlength = getbits(data,shift,1);
318                                        if (runlength==1) {
319                                                runlength = getbits(data,shift,2);
320                                                if (runlength == 3) {
321                                                        runlength = getbits(data, shift, 8);
322                                                }
323                                        }
324                                }
325                        }
326                } else {
327                        runlength--;
328                }
329                if (info.Bps() == 8) {
330                        *outdata++ = d[flip_flag];
331                } else {
332                        write_little_endian_short(outdata, d[flip_flag]);
333                        outdata += 2;
334                }
335                if (info.Channels() == 2) flip_flag ^= 1; /* channel 切り替え */
336        }
337        return;
338}
339
340class NWAData {
341        public:
342                int channels;
343                int bps; /* bits per sample */
344                int freq; /* samples per second */
345        private:
346                int complevel; /* compression level */
347                int dummy; /* ? : 0x00 */
348        public:
349                int blocks; /* block count */
350                int datasize; /* all data size */
351        private:
352                int compdatasize; /* compressed data size */
353                int samplecount; /* all samples */
354                int blocksize; /* samples per block */
355                int restsize; /* samples of the last block */
356                int dummy2; /* ? : 0x89 */
357                int curblock;
358                int* offsets;
359                int offset_start;
360                int filesize;
361                char* tmpdata;
362        public:
363                void ReadHeader(FILE* in, int file_size=-1);
364                int CheckHeader(void); /* false: invalid true: valid */
365                NWAData(void) {
366                        offsets = NULL;
367                        tmpdata = NULL;
368                }
369                ~NWAData(void) {
370                        if (offsets) delete[] offsets;
371                        if (tmpdata) delete[] tmpdata;
372                }
373                int BlockLength(void) {
374                        if (complevel != -1) {
375                                if (offsets == NULL) return false;
376                                if (tmpdata == NULL) return false;
377                        }
378                        return blocksize * (bps/8);
379                }
380                /* data は BlockLength 以䞊の長さを持぀こず
381                ** 返り倀は䜜成したデヌタの長さ。終了時は 0。
382                ** ゚ラヌ時は -1
383                */
384                int Decode(FILE* in, char* data, int& skip_count);
385                void Rewind(FILE* in);
386};
387
388void NWAData::ReadHeader(FILE* in, int _file_size) {
389        char header[0x2c];
390        struct stat sb;
391        int i;
392        if (offsets) delete[] offsets;
393        if (tmpdata) delete[] tmpdata;
394        offsets = NULL;
395        tmpdata = NULL;
396        filesize = 0;
397        offset_start = ftell(in);
398        if (offset_start == -1) offset_start = 0;
399        if (_file_size != -1) filesize = _file_size;
400        curblock = -1;
401        /* header 読み蟌み */
402        if (in == NULL || feof(in) || ferror(in)) {
403                fprintf(stderr,"invalid stream\n");
404                return;
405        }
406        fread(header, 0x2c, 1, in);
407        if (feof(in) || ferror(in)) {
408                fprintf(stderr,"invalid stream\n");
409                return;
410        }
411        channels = read_little_endian_short(header+0x00);
412        bps = read_little_endian_short(header+0x02);
413        freq = read_little_endian_int(header+0x04);
414        complevel = read_little_endian_int(header+0x08);
415        dummy = read_little_endian_int(header+0x0c);
416        blocks = read_little_endian_int(header+0x10);
417        datasize = read_little_endian_int(header+0x14);
418        compdatasize = read_little_endian_int(header+0x18);
419        samplecount = read_little_endian_int(header+0x1c);
420        blocksize = read_little_endian_int(header+0x20);
421        restsize = read_little_endian_int(header+0x24);
422        dummy2 = read_little_endian_int(header+0x28);
423        if (complevel == -1) {  /* 無圧瞮rawデヌタ */
424                /* 適圓に決め打ちする */
425                blocksize = 65536;
426                restsize = (datasize % (blocksize * (bps/8))) / (bps/8);
427                blocks = datasize / (blocksize * (bps/8)) + (restsize > 0 ? 1 : 0);
428        }
429        if (blocks <= 0 || blocks > 1000000) {
430                /* 時間を超える曲っおのはないでしょ*/
431                fprintf(stderr,"too large blocks : %d\n",blocks);
432                return;
433        }
434        /* regular file なら filesize 読み蟌み */
435        if (filesize == 0 && fstat(fileno(in), &sb)==0 && (sb.st_mode&S_IFMT) == S_IFREG) {
436                int pos = ftell(in);
437                fseek(in, 0, SEEK_END);
438                filesize = ftell(in);
439                fseek(in, pos, SEEK_SET);
440                if (pos+blocks*4 >= filesize) {
441                        fprintf(stderr,"offset block is not exist\n");
442                        return;
443                }
444        }
445        if (complevel == -1) return;
446        /* offset index 読み蟌み */
447        offsets = new int[blocks];
448        fread(offsets, blocks, 4, in);
449        for (i=0; i<blocks; i++) {
450                offsets[i] = read_little_endian_int((char*)(offsets+i));
451        }
452        if (feof(in) || ferror(in)) {
453                fprintf(stderr,"invalid stream\n");
454                delete[] offsets;
455                offsets = NULL;
456                return;
457        }
458}
459
460void NWAData::Rewind(FILE* in) {
461        curblock = -1;
462        fseek(in, 0x2c, SEEK_SET);
463        if (offsets) fseek(in, blocks*4, SEEK_CUR);
464}
465
466int NWAData::CheckHeader(void) {
467        if (complevel != -1 && offsets == NULL) return false;
468        /* デヌタそのもののチェック */
469        if (channels != 1 && channels != 2) {
470                fprintf(stderr,"This program only supports mono / stereo data : data have %d channels.\n",channels);
471                return false;
472        }
473        if (bps != 8 && bps != 16) {
474                fprintf(stderr,"This program only supports 8 / 16bit data : data is %d bits\n",bps);
475                return false;
476        }
477        if (complevel == -1) {
478                int byps = bps/8; /* bytes per sample */
479                if (datasize != samplecount*byps) {
480                        fprintf(stderr,"invalid datasize : datasize %d != samplecount %d * samplesize %d\n",datasize,samplecount,byps);
481                        return false;
482                }
483                if (samplecount != (blocks-1)*blocksize+restsize ) {
484                        fprintf(stderr,"total sample count is invalid : samplecount %d != %d*%d+%d(block*blocksize+lastblocksize).\n",samplecount,blocks-1,blocksize,restsize);
485                        return false;
486                }
487                else
488                        return true;
489        }
490        //if (complevel < 0 || complevel > 2) {
491        if (complevel < 0 || complevel > 5) {
492                fprintf(stderr,"This program only supports -1,0,1,2 compression level : the level of data is %d\n",complevel);
493                return false;
494        }
495        /* 敎合性チェック */
496        if (filesize != 0 && filesize != compdatasize) {
497                fprintf(stderr,"file size is invalid : %d != %d\n",filesize,compdatasize);
498                return false;
499        }
500        if (offsets[blocks-1] >= compdatasize) {
501                fprintf(stderr,"the last offset overruns the file.\n");
502                return false;
503        }
504        int byps = bps/8; /* bytes per sample */
505        if (datasize != samplecount*byps) {
506                fprintf(stderr,"invalid datasize : datasize %d != samplecount %d * samplesize %d\n",datasize,samplecount,byps);
507                return false;
508        }
509        if (samplecount != (blocks-1)*blocksize+restsize ) {
510                fprintf(stderr,"total sample count is invalid : samplecount %d != %d*%d+%d(block*blocksize+lastblocksize).\n",samplecount,blocks-1,blocksize,restsize);
511                return false;
512        }
513        tmpdata = new char[blocksize*byps*2]; /* これ以䞊の倧きさはないだろう、、、 */
514        return true;
515}
516
517class NWAInfo_sw2 {
518        public:
519                int Channels(void) const{return 2;}
520                int Bps(void) const { return 16;}
521                int CompLevel(void) const { return 2;}
522                int UseRunLength(void) const { return false; }
523};
524
525int NWAData::Decode(FILE* in, char* data, int& skip_count) {
526        if (complevel == -1) {          /* 無圧瞮時の凊理 */
527                if (feof(in) || ferror(in)) return -1;
528                if (curblock == -1) {
529                        /* 最初のブロックなら、wave header 出力 */
530                        memcpy(data, make_wavheader(datasize, channels, bps, freq), 0x2c);
531                        curblock++;
532                        fseek(in, offset_start + 0x2c, SEEK_SET);
533                        return 0x2c;
534                }
535                if (skip_count > blocksize/channels) {
536                        skip_count -= blocksize/channels;
537                        fseek(in, blocksize*(bps/8), SEEK_CUR);
538                        curblock++;
539                        return -2;
540                }
541                if (curblock < blocks) {
542                        int readsize = blocksize;
543                        if (skip_count) {
544                                fseek(in, skip_count*channels*(bps/8), SEEK_CUR);
545                                readsize -= skip_count * channels;
546                                skip_count = 0;
547                        }
548                        int err = fread(data, 1, readsize * (bps/8), in);
549                        curblock++;
550                        return err;
551                }
552                return -1;
553        }
554        if (offsets == NULL || tmpdata == NULL) return -1;
555        if (blocks == curblock) return 0;
556        if (feof(in) || ferror(in)) return -1;
557        if (curblock == -1) {
558                /* 最初のブロックなら、wave header 出力 */
559                memcpy(data, make_wavheader(datasize, channels, bps, freq), 0x2c);
560                curblock++;
561                return 0x2c;
562        }
563        /* 今回読み蟌むデコヌドするデヌタの倧きさを埗る */
564        int curblocksize, curcompsize;
565        if (curblock != blocks-1) {
566                curblocksize = blocksize * (bps/8);
567                curcompsize = offsets[curblock+1] - offsets[curblock];
568                if (curblocksize >= blocksize*(bps/8)*2) return -1; // Fatal error
569        } else {
570                curblocksize = restsize * (bps/8);
571                curcompsize = blocksize*(bps/8)*2;
572        }
573        if (skip_count > blocksize/channels) {
574                skip_count -= blocksize/channels;
575                fseek(in, curcompsize, SEEK_CUR);
576                curblock++;
577                return -2;
578        }
579        /* デヌタ読み蟌み */
580        fread(tmpdata, 1, curcompsize, in);
581        /* 展開 */
582        if (channels == 2 && bps == 16 && complevel == 2) {
583                NWAInfo_sw2 info;
584                NWADecode(info, tmpdata, data, curcompsize, curblocksize);
585        } else {
586                NWAInfo info(channels, bps, complevel);
587                NWADecode(info, tmpdata, data, curcompsize, curblocksize);
588        }
589        int retsize = curblocksize;
590        if (skip_count) {
591                int skip_c = skip_count * channels * (bps/8);
592                retsize -= skip_c;
593                memmove(data, data+skip_c, skip_c);
594                skip_count = 0;
595        }
596        curblock++;
597        return retsize;
598}
599
600#ifdef USE_MAIN
601
602void conv(FILE* in, FILE* out, int skip_count, int in_size = -1) {
603        NWAData h;
604        h.ReadHeader(in, in_size);
605        h.CheckHeader();
606        int bs = h.BlockLength();
607        char* d = new char[bs];
608        int err;
609        while( (err=h.Decode(in, d, skip_count)) != 0) {
610                if (err == -1) break;
611                if (err == -2) continue;
612                fwrite(d, err, 1, out);
613        }
614        return;
615}
616
617int main(int argc, char** argv) {
618        int skip_count = 0;
619
620        if (argc > 2 && strcmp(argv[1], "--skip") == 0) {
621                skip_count = atoi(argv[2]);
622                argc -= 2;
623                argv[1] = argv[3];
624                argv[2] = argv[4];
625        }
626        if (argc != 2 && argc != 3) {
627                fprintf(stderr,"usage : nwatowav [inputfile [outputfile]]\n");
628                return -1;
629        }
630        if (strstr(argv[1], ".nwk") != NULL || strstr(argv[1], ".ovk") != NULL) {
631                bool is_ovk;
632                int headblk_sz;
633                const char* out_ext;
634
635                char* outpath = new char[strlen(argv[1])+10];
636                char buf[1024];
637                memset(buf, 0, 1024);
638                FILE* in = fopen(argv[1], "rb");
639                if (in == NULL) {
640                        fprintf(stderr,"Cannot open file : %s\n",argv[1]);
641                        return -1;
642                }
643                if (strstr(argv[1], ".ovk") != NULL) {
644                        is_ovk = true;
645                        headblk_sz = 16; 
646                        out_ext = "ogg";
647                } else {
648                        is_ovk = false;
649                        headblk_sz = 12;
650                        out_ext = "wav";
651                }
652                fread(buf, 1, 4, in);
653                int index = read_little_endian_int(buf);
654                if (index <= 0) { 
655                        if (is_ovk)
656                                fprintf(stderr,"Invalid Ogg-ovk file : %s : index = %d\n",argv[1],index);
657                        else
658                                fprintf(stderr,"Invalid Koe-nwk file : %s : index = %d\n",argv[1],index);
659                        return -1;
660                }
661                int* tbl_off = new int[index];
662                int* tbl_siz = new int[index];
663                int* tbl_cnt = new int[index];
664                int* tbl_origsiz = new int[index];
665                int i;
666                for (i=0; i<index; i++) {
667                        fread(buf, 1, headblk_sz, in);
668                        tbl_siz[i] = read_little_endian_int(buf);
669                        tbl_off[i] = read_little_endian_int(buf+4);
670                        tbl_cnt[i] = read_little_endian_int(buf+8);
671                        tbl_origsiz[i] = read_little_endian_int(buf+12);
672                }
673                fseek(in, 0, SEEK_END);
674                int fsize = ftell(in);
675                for (i=0; i<index; i++) {
676                        if (tbl_off[i] <= 0 || tbl_siz[i] <= 0 || tbl_off[i]+tbl_siz[i] > fsize) {
677                                fprintf(stderr,"Invalid table[%d] : cnt %d off %d size %d / %d\n",i,tbl_cnt[i],tbl_off[i],tbl_siz[i],fsize);
678                                continue;
679                        }
680                        if (argc == 2)
681                                sprintf(outpath, "%s-%d.%s", argv[1], tbl_cnt[i],out_ext);
682                        else
683                                sprintf(outpath, "%s-%d.%s", argv[2], tbl_cnt[i],out_ext);
684                        FILE* out = fopen(outpath, "wb");
685                        if (out == NULL) {
686                                fprintf(stderr,"Cannot open output file %s\n",outpath);
687                                continue;
688                        }
689                        fprintf(stderr,"Writing file %s...\n",outpath);
690                        fseek(in, tbl_off[i], SEEK_SET);
691                        if (is_ovk) { // copy file
692                                int sz = tbl_siz[i];
693                                char buf[32*1024];
694                                while(sz > 32*1024) {
695                                        fread(buf, 32*1024, 1, in);
696                                        fwrite(buf, 32*1024, 1, out);
697                                        sz -= 1024*32;
698                                }
699                                if (sz > 0) {
700                                        fread(buf, sz, 1, in);
701                                        fwrite(buf, sz, 1, out);
702                                }
703                        } else { // .nwk
704                                conv(in, out, 0, tbl_siz[i]);
705                        }
706                        fclose(out);
707                }
708                fclose(in);
709                return 0;
710        }
711        FILE* in = fopen(argv[1],"rb");
712        if (in == NULL) {
713                fprintf(stderr,"Cannot open file : %s\n",argv[1]);
714                return -1;
715        }
716        FILE* out;
717        if (argc != 3 && (!isatty(fileno(stdout)))) {   // wave file is written to stdout if stdout is redirected to a file
718                out = stdout;
719        } else {                                        // make a new file or use argv[2] for output file name
720                char* outpath = new char[strlen(argv[1])+10];
721                sprintf(outpath, "%s.wav",argv[1]);
722                if (argc == 3) outpath = argv[2];
723                out = fopen(outpath, "wb");
724                if (out == NULL) {
725                        fprintf(stderr,"Cannot open file : %s\n",outpath);
726                        return -1;
727                }
728        }
729        conv(in, out, skip_count);
730        fclose(in);
731        if (out != stdout) fclose(out);
732        return 0;
733}
734#else
735
736#include"wavfile.h"
737
738void NWAFILE::Seek(int count) {
739        if (data == NULL) data = new char[block_size];
740        nwa->Rewind(stream);
741        int dmy = 0;
742        nwa->Decode(stream, data, dmy); // skip wav header
743        data_len = 0;
744        skip_count = count;
745}
746NWAFILE::NWAFILE(FILE* _stream) {
747        skip_count = 0;
748        data = NULL;
749        stream = _stream;
750        nwa = new NWAData;
751        nwa->ReadHeader(stream);
752        if (!nwa->CheckHeader()) {
753                return;
754        }
755        block_size = nwa->BlockLength();
756        data = new char[block_size];
757        data_len = 0;
758
759        wavinfo.SamplingRate = nwa->freq;
760        wavinfo.Channels = nwa->channels;
761        wavinfo.DataBits = nwa->bps;
762
763        int dmy = 0;
764        data_len = nwa->Decode(stream, data, dmy); // skip wav header
765
766        return;
767}
768NWAFILE::~NWAFILE() {
769        if (stream) fclose(stream);
770        if (data) delete[] data;
771        if (nwa) delete nwa;
772}
773
774int NWAFILE::Read(char* buf, int blksize, int blklen) {
775        if (data == NULL) return -1; // end of file
776
777        if (data_len > blksize * blklen) {
778                int len = blksize * blklen;
779                memcpy(buf, data, len);
780                memmove(data, data+len, data_len-len);
781                data_len -= len;
782                return blklen;
783        }
784        memcpy(buf, data, data_len);
785        int copied_length = data_len;
786        data_len = 0;
787
788        if (stream == NULL) {
789                delete[] data;
790                data = NULL;
791                return copied_length / blksize;
792        }
793
794        //TODO: Rewrite this joke
795        // read
796        do {
797                int err;
798retry:
799                err = nwa->Decode(stream, data, skip_count);
800                if (err == 0 || err == -1) { // eof or error
801                        delete[] data;
802                        data = NULL;
803                        return copied_length / blksize;
804                }
805                if (err == -2) goto retry; // EAGAIN
806                data_len = err;
807                if (copied_length + data_len < blklen*blksize) {
808                        memcpy(buf+copied_length, data, data_len);
809                        copied_length += data_len;
810                        goto retry;
811                }
812        } while(0);
813
814        // determine return length
815        int datablks = (data_len+copied_length)/blksize;
816        if (datablks <= 0) return 0;
817        if (datablks > blklen) datablks = blklen;
818        int rest_len = datablks * blksize - copied_length;
819        if (rest_len) {
820                memcpy(buf+copied_length, data, rest_len);
821                memmove(data, data+rest_len, data_len-rest_len);
822                data_len -= rest_len;
823        }
824        return datablks;
825}
826
827char* NWAFILE::ReadAll(FILE* in, int& total_size) {
828        NWAData h;
829        if (in == NULL) return NULL;
830        h.ReadHeader(in);
831        h.CheckHeader();
832        int bs = h.BlockLength();
833        total_size = h.datasize+0x2c;
834        char* d = new char[total_size + bs*2];
835        int dcur = 0;
836        int err;
837        int skip = 0;
838        while(dcur < total_size+bs && (err=h.Decode(in, d+dcur, skip)) != 0) {
839                if (err == -1) break;
840                if (err == -2) continue;
841                dcur += err;
842        }
843        return d;
844}
845
846#include "music.h"
847
848char* decode_koe_nwa(AvgKoeInfo info, int* data_len) {
849        NWAData h;
850        if (info.stream == NULL) return NULL;
851        fseek(info.stream, info.offset, SEEK_SET);
852        h.ReadHeader(info.stream, info.length);
853        if (h.CheckHeader() == false) return NULL;
854        int bs = h.BlockLength();
855        int total = h.datasize + 0x2c;
856        char* d = new char[total + bs*2];
857        int dcur = 0;
858        int err;
859        int skip = 0;
860        while(dcur < total+bs && (err=h.Decode(info.stream, d+dcur, skip)) != 0) {
861                if (err == -1) break;
862                if (err == -2) continue;
863                dcur += err;
864        }
865        if (data_len) {
866                *data_len = dcur;
867                if (*data_len > total) *data_len = total;
868        }
869        return d;
870}
871
872#endif
Note: See TracBrowser for help on using the browser.