| 1 | /* |
|---|
| 2 | * Copyright (c) 2004-2006 Kazunori "jagarl" Ueno |
|---|
| 3 | * All rights reserved. |
|---|
| 4 | * |
|---|
| 5 | * Redistribution and use in source and binary forms, with or without |
|---|
| 6 | * modification, are permitted provided that the following conditions |
|---|
| 7 | * are met: |
|---|
| 8 | * 1. Redistributions of source code must retain the above copyright |
|---|
| 9 | * notice, this list of conditions and the following disclaimer. |
|---|
| 10 | * 2. Redistributions in binary form must reproduce the above copyright |
|---|
| 11 | * notice, this list of conditions and the following disclaimer in the |
|---|
| 12 | * documentation and/or other materials provided with the distribution. |
|---|
| 13 | * 3. The name of the author may not be used to endorse or promote products |
|---|
| 14 | * derived from this software without specific prior written permission. |
|---|
| 15 | * |
|---|
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|---|
| 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|---|
| 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|---|
| 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|---|
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|---|
| 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|---|
| 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|---|
| 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|---|
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|---|
| 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|---|
| 26 | */ |
|---|
| 27 | |
|---|
| 28 | #include <stdio.h> |
|---|
| 29 | #include <stdlib.h> |
|---|
| 30 | #include <string.h> |
|---|
| 31 | #include <vector> |
|---|
| 32 | #include <list> |
|---|
| 33 | #include <algorithm> |
|---|
| 34 | #include "music.h" |
|---|
| 35 | #include "system/file.h" |
|---|
| 36 | #include "system/file_impl.h" |
|---|
| 37 | |
|---|
| 38 | using namespace std; |
|---|
| 39 | |
|---|
| 40 | /********************************************* |
|---|
| 41 | ** |
|---|
| 42 | ** FindKoe -- RealLiveã®é³å£°ã¢ãŒã«ã€ãåŠç |
|---|
| 43 | ** |
|---|
| 44 | */ |
|---|
| 45 | |
|---|
| 46 | /* 声ãã¡ã€ã«ã®ã¢ãŒã«ã€ãçšã®ãã£ãã·ã¥ */ |
|---|
| 47 | #define koe_cache_size 7 |
|---|
| 48 | struct AvgKoeTable { |
|---|
| 49 | int koe_num; |
|---|
| 50 | int length; |
|---|
| 51 | int offset; |
|---|
| 52 | AvgKoeTable(int _num, int _len, int _off) : |
|---|
| 53 | koe_num(_num), length(_len), offset(_off) {} |
|---|
| 54 | bool operator <(int number) const { |
|---|
| 55 | return koe_num < number; |
|---|
| 56 | } |
|---|
| 57 | bool operator <(const AvgKoeTable& to) const { |
|---|
| 58 | return koe_num < to.koe_num; |
|---|
| 59 | } |
|---|
| 60 | bool operator ==(const AvgKoeTable& to) const { |
|---|
| 61 | return koe_num == to.koe_num; |
|---|
| 62 | } |
|---|
| 63 | bool operator ==(const int to) const { |
|---|
| 64 | return koe_num == to; |
|---|
| 65 | } |
|---|
| 66 | }; |
|---|
| 67 | |
|---|
| 68 | struct AvgKoeHead { |
|---|
| 69 | FILE* stream; |
|---|
| 70 | int file_number; |
|---|
| 71 | int rate; |
|---|
| 72 | KoeType type; |
|---|
| 73 | vector<AvgKoeTable> table; |
|---|
| 74 | AvgKoeHead(FILE* stream, int file_number, KoeType type); |
|---|
| 75 | AvgKoeHead(const AvgKoeHead& from); |
|---|
| 76 | ~AvgKoeHead(); |
|---|
| 77 | AvgKoeTable* Find(int koe_num); |
|---|
| 78 | bool operator !=(int num) const { return file_number != num; } |
|---|
| 79 | bool operator ==(int num) const { return file_number == num; } |
|---|
| 80 | }; |
|---|
| 81 | |
|---|
| 82 | struct AvgKoeCache { |
|---|
| 83 | list<AvgKoeHead> cache; |
|---|
| 84 | AvgKoeInfo Find(int file_number, int index); |
|---|
| 85 | }; |
|---|
| 86 | |
|---|
| 87 | static AvgKoeCache koe_cache; |
|---|
| 88 | |
|---|
| 89 | AvgKoeInfo FindKoe(int file_number, int index) { |
|---|
| 90 | return koe_cache.Find(file_number, index); |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | AvgKoeInfo AvgKoeCache::Find(int file_number, int index) { |
|---|
| 94 | AvgKoeInfo info; |
|---|
| 95 | info.stream = NULL; |
|---|
| 96 | info.length = 0; |
|---|
| 97 | info.offset = 0; |
|---|
| 98 | |
|---|
| 99 | FileSearcher* file_searcher = FileSearcher::GetInstance(); |
|---|
| 100 | |
|---|
| 101 | list<AvgKoeHead>::iterator it; |
|---|
| 102 | it = find(cache.begin(), cache.end(), file_number); |
|---|
| 103 | if (it == cache.end()) { |
|---|
| 104 | /* æ°ãã« head ãäœã */ |
|---|
| 105 | char fname[100]; |
|---|
| 106 | KoeType type = koe_unknown; |
|---|
| 107 | sprintf(fname, "z%03d.koe", file_number); |
|---|
| 108 | ARCINFO* arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".koe"); |
|---|
| 109 | if (arcinfo == NULL) { |
|---|
| 110 | type = koe_nwk; |
|---|
| 111 | sprintf(fname, "z%04d.nwk", file_number); |
|---|
| 112 | arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".nwk"); |
|---|
| 113 | } |
|---|
| 114 | if (arcinfo == NULL) { |
|---|
| 115 | type = koe_ovk; |
|---|
| 116 | sprintf(fname, "z%04d.ovk", file_number); |
|---|
| 117 | arcinfo = file_searcher->Find(FileSearcher::KOE,fname,".ovk"); |
|---|
| 118 | } |
|---|
| 119 | #if HAVE_LIBVORBISFILE || HAVE_LIBVORBISIDEC |
|---|
| 120 | if (arcinfo == NULL) { |
|---|
| 121 | //FIXME: OMG that's ugly, improve it as soon as you can! |
|---|
| 122 | DIRFILE* koedir = (DIRFILE*) file_searcher->MakeARCFILE((FileSearcher::ARCTYPE)0, "koe"); |
|---|
| 123 | sprintf(fname, "%04d", file_number); |
|---|
| 124 | char* dirname = koedir->SearchFile(fname); |
|---|
| 125 | delete koedir; |
|---|
| 126 | koedir = new DIRFILE(dirname); |
|---|
| 127 | delete[] dirname; |
|---|
| 128 | sprintf(fname, "z%04d%05d.ogg", file_number, index); |
|---|
| 129 | arcinfo = koedir->Find(fname, ".ogg"); |
|---|
| 130 | delete koedir; |
|---|
| 131 | |
|---|
| 132 | if (arcinfo == NULL) return info; |
|---|
| 133 | FILE* stream = arcinfo->OpenFile(&info.length); |
|---|
| 134 | delete arcinfo; |
|---|
| 135 | info.type = koe_ogg; |
|---|
| 136 | info.stream = stream; |
|---|
| 137 | return info; |
|---|
| 138 | } |
|---|
| 139 | #endif |
|---|
| 140 | if (arcinfo == NULL) return info; |
|---|
| 141 | FILE* stream = arcinfo->OpenFile(); |
|---|
| 142 | delete arcinfo; |
|---|
| 143 | if (stream == NULL) return info; |
|---|
| 144 | cache.push_front(AvgKoeHead(stream, file_number, type)); |
|---|
| 145 | if (cache.size() >= koe_cache_size) cache.pop_back(); |
|---|
| 146 | it = cache.begin(); |
|---|
| 147 | } |
|---|
| 148 | if (it->file_number != file_number) return info; // çªå·ããããã |
|---|
| 149 | AvgKoeTable* table = it->Find(index); |
|---|
| 150 | //FIXME: table == NULL ? |
|---|
| 151 | if (table == 0) return info; // index ãèŠä»ãããªã |
|---|
| 152 | // info ãäœæãã |
|---|
| 153 | info.length = table->length; |
|---|
| 154 | info.offset = table->offset; |
|---|
| 155 | info.rate = it->rate; |
|---|
| 156 | info.type = it->type; |
|---|
| 157 | int new_fd = dup(fileno(it->stream)); |
|---|
| 158 | if (new_fd == -1) info.stream = NULL; |
|---|
| 159 | else info.stream = fdopen(new_fd, "rb"); |
|---|
| 160 | return info; |
|---|
| 161 | } |
|---|
| 162 | |
|---|
| 163 | AvgKoeHead::AvgKoeHead(const AvgKoeHead& from) { |
|---|
| 164 | if (from.stream) { |
|---|
| 165 | int new_fd = dup(fileno(from.stream)); |
|---|
| 166 | if (new_fd == -1) stream = NULL; |
|---|
| 167 | else stream = fdopen(new_fd, "rb"); |
|---|
| 168 | } |
|---|
| 169 | file_number = from.file_number; |
|---|
| 170 | rate = from.rate; |
|---|
| 171 | table = from.table; |
|---|
| 172 | type = from.type; |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | AvgKoeHead::AvgKoeHead(FILE* _s, int _file_number, KoeType _type) { |
|---|
| 176 | char head[0x20]; |
|---|
| 177 | stream = _s; file_number = _file_number; |
|---|
| 178 | //int offset = ftell(stream); |
|---|
| 179 | rate = 22050; |
|---|
| 180 | type = _type; |
|---|
| 181 | if (stream == NULL) return; |
|---|
| 182 | /* header èªã¿èŸŒã¿ */ |
|---|
| 183 | if (type == koe_nwk) { // æ°ããåœ¢åŒ : .nwk file |
|---|
| 184 | rate = 44100; |
|---|
| 185 | fread(head, 4, 1, stream); |
|---|
| 186 | int table_len = read_little_endian_int(head); |
|---|
| 187 | table.reserve(table_len); |
|---|
| 188 | int i; |
|---|
| 189 | for (i=0; i<table_len; i++) { |
|---|
| 190 | fread(head, 12, 1, stream); |
|---|
| 191 | int sz = read_little_endian_int(head); |
|---|
| 192 | int off = read_little_endian_int(head+4); |
|---|
| 193 | int cnt = read_little_endian_int(head+8); |
|---|
| 194 | table.push_back(AvgKoeTable(cnt, sz, off)); |
|---|
| 195 | } |
|---|
| 196 | } else if (type == koe_ovk) { // Little Busters! : .ovk file |
|---|
| 197 | rate = 44100; |
|---|
| 198 | fread(head, 4, 1, stream); |
|---|
| 199 | int table_len = read_little_endian_int(head); |
|---|
| 200 | table.reserve(table_len); |
|---|
| 201 | int i; |
|---|
| 202 | for (i=0; i<table_len; i++) { |
|---|
| 203 | fread(head, 16, 1, stream); |
|---|
| 204 | int sz = read_little_endian_int(head); |
|---|
| 205 | int off = read_little_endian_int(head+4); |
|---|
| 206 | int cnt = read_little_endian_int(head+8); |
|---|
| 207 | table.push_back(AvgKoeTable(cnt, sz, off)); |
|---|
| 208 | } |
|---|
| 209 | } else { // .koe file |
|---|
| 210 | fread(head, 0x20, 1, stream); |
|---|
| 211 | if (strncmp(head, "KOEPAC", 7) != 0) { // invalid header |
|---|
| 212 | stream = NULL; |
|---|
| 213 | return; |
|---|
| 214 | } |
|---|
| 215 | int table_len = read_little_endian_int(head+0x10); |
|---|
| 216 | rate = read_little_endian_int(head+0x18); |
|---|
| 217 | if (rate == 0) rate = 22050; |
|---|
| 218 | /* table èªã¿èŸŒã¿ */ |
|---|
| 219 | table.reserve(table_len); |
|---|
| 220 | char* buf = new char[table_len*8]; |
|---|
| 221 | fread(buf, table_len, 8, stream); |
|---|
| 222 | int i; for (i=0; i<table_len; i++) { |
|---|
| 223 | int cnt = read_little_endian_short(buf+i*8); |
|---|
| 224 | int sz = read_little_endian_short(buf+i*8+2); |
|---|
| 225 | int off = read_little_endian_int(buf+i*8+4); |
|---|
| 226 | table.push_back(AvgKoeTable(cnt, sz, off)); |
|---|
| 227 | } |
|---|
| 228 | } |
|---|
| 229 | sort(table.begin(), table.end()); |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | AvgKoeHead::~AvgKoeHead(void) { |
|---|
| 233 | if (stream) fclose(stream); |
|---|
| 234 | stream = NULL; |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | AvgKoeTable* AvgKoeHead::Find(int koe_num) { |
|---|
| 238 | if (table.empty()) return NULL; |
|---|
| 239 | vector<AvgKoeTable>::iterator it; |
|---|
| 240 | it = lower_bound(table.begin(), table.end(), koe_num); |
|---|
| 241 | if (it == table.end() || it->koe_num != koe_num) return NULL; |
|---|
| 242 | return &table[it-table.begin()]; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | /********************************************* |
|---|
| 246 | ** |
|---|
| 247 | ** MakeWavHeader : koe ãã¡ã€ã«ã« wave header ãä»ãã |
|---|
| 248 | ** |
|---|
| 249 | */ |
|---|
| 250 | |
|---|
| 251 | static unsigned char orig_header[0x2c] = { |
|---|
| 252 | 0x52, 0x49, 0x46, 0x46, /* +00 "RIFF" */ |
|---|
| 253 | 0x00, 0x00, 0x00, 0x00, /* +04 file size - 8 */ |
|---|
| 254 | 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20, /* +08 "WAVEfmt " */ |
|---|
| 255 | 0x10, 0x00, 0x00, 0x00, /* +10 fmt size */ |
|---|
| 256 | 0x01, 0x00, /* +14 wFormatTag */ |
|---|
| 257 | 0x02, 0x00, /* +16 Channels */ |
|---|
| 258 | 0x44, 0xac, 0x00, 0x00, /* +18 rate */ |
|---|
| 259 | 0x10, 0xb1, 0x02, 0x00, /* +1c BytesPerSec = rate * BlockAlign */ |
|---|
| 260 | 0x04, 0x00, /* +20 BlockAlign = channels*BytesPerSample */ |
|---|
| 261 | 0x10, 0x00, /* +22 BitsPerSample */ |
|---|
| 262 | 0x64, 0x61, 0x74, 0x61, /* +24 "data" */ |
|---|
| 263 | 0x00, 0x00, 0x00, 0x00 /* +28 filesize - 0x2c */ |
|---|
| 264 | }; |
|---|
| 265 | |
|---|
| 266 | const char* MakeWavHeader(int rate, int ch, int bps, int size) { |
|---|
| 267 | static char header[0x2c]; |
|---|
| 268 | memcpy(header, (const char*)orig_header, 0x2c); |
|---|
| 269 | write_little_endian_int(header+0x04, size-8); |
|---|
| 270 | write_little_endian_int(header+0x28, size-0x2c); |
|---|
| 271 | write_little_endian_int(header+0x18, rate); |
|---|
| 272 | write_little_endian_int(header+0x1c, rate*ch*bps); |
|---|
| 273 | header[0x16] = ch; |
|---|
| 274 | header[0x20] = ch*bps; |
|---|
| 275 | header[0x22] = bps*8; |
|---|
| 276 | return header; |
|---|
| 277 | } |
|---|
| 278 | |
|---|
| 279 | /********************************************* |
|---|
| 280 | ** |
|---|
| 281 | ** decode_koe -- é³å£°ããŒã¿å±é |
|---|
| 282 | ** |
|---|
| 283 | */ |
|---|
| 284 | |
|---|
| 285 | extern char* decode_koe(AvgKoeInfo info, int* len); |
|---|
| 286 | |
|---|
| 287 | /* 8bit -> 16bit ãžã®å€æããŒãã«ãæ¬æ¥ã¯ signed short ã ã |
|---|
| 288 | ** ãšãããã unsigned ã§æ±ã£ãŠãã |
|---|
| 289 | */ |
|---|
| 290 | |
|---|
| 291 | unsigned short koe_8bit_trans_tbl[256] = { |
|---|
| 292 | 0x8000,0x81ff,0x83f9,0x85ef,0x87e1,0x89cf,0x8bb9,0x8d9f, |
|---|
| 293 | 0x8f81,0x915f,0x9339,0x950f,0x96e1,0x98af,0x9a79,0x9c3f, |
|---|
| 294 | 0x9e01,0x9fbf,0xa179,0xa32f,0xa4e1,0xa68f,0xa839,0xa9df, |
|---|
| 295 | 0xab81,0xad1f,0xaeb9,0xb04f,0xb1e1,0xb36f,0xb4f9,0xb67f, |
|---|
| 296 | 0xb801,0xb97f,0xbaf9,0xbc6f,0xbde1,0xbf4f,0xc0b9,0xc21f, |
|---|
| 297 | 0xc381,0xc4df,0xc639,0xc78f,0xc8e1,0xca2f,0xcb79,0xccbf, |
|---|
| 298 | 0xce01,0xcf3f,0xd079,0xd1af,0xd2e1,0xd40f,0xd539,0xd65f, |
|---|
| 299 | 0xd781,0xd89f,0xd9b9,0xdacf,0xdbe1,0xdcef,0xddf9,0xdeff, |
|---|
| 300 | 0xe001,0xe0ff,0xe1f9,0xe2ef,0xe3e1,0xe4cf,0xe5b9,0xe69f, |
|---|
| 301 | 0xe781,0xe85f,0xe939,0xea0f,0xeae1,0xebaf,0xec79,0xed3f, |
|---|
| 302 | 0xee01,0xeebf,0xef79,0xf02f,0xf0e1,0xf18f,0xf239,0xf2df, |
|---|
| 303 | 0xf381,0xf41f,0xf4b9,0xf54f,0xf5e1,0xf66f,0xf6f9,0xf77f, |
|---|
| 304 | 0xf801,0xf87f,0xf8f9,0xf96f,0xf9e1,0xfa4f,0xfab9,0xfb1f, |
|---|
| 305 | 0xfb81,0xfbdf,0xfc39,0xfc8f,0xfce1,0xfd2f,0xfd79,0xfdbf, |
|---|
| 306 | 0xfe01,0xfe3f,0xfe79,0xfeaf,0xfee1,0xff0f,0xff39,0xff5f, |
|---|
| 307 | 0xff81,0xff9f,0xffb9,0xffcf,0xffe1,0xffef,0xfff9,0xffff, |
|---|
| 308 | 0x0000,0x0001,0x0007,0x0011,0x001f,0x0031,0x0047,0x0061, |
|---|
| 309 | 0x007f,0x00a1,0x00c7,0x00f1,0x011f,0x0151,0x0187,0x01c1, |
|---|
| 310 | 0x01ff,0x0241,0x0287,0x02d1,0x031f,0x0371,0x03c7,0x0421, |
|---|
| 311 | 0x047f,0x04e1,0x0547,0x05b1,0x061f,0x0691,0x0707,0x0781, |
|---|
| 312 | 0x07ff,0x0881,0x0907,0x0991,0x0a1f,0x0ab1,0x0b47,0x0be1, |
|---|
| 313 | 0x0c7f,0x0d21,0x0dc7,0x0e71,0x0f1f,0x0fd1,0x1087,0x1141, |
|---|
| 314 | 0x11ff,0x12c1,0x1387,0x1451,0x151f,0x15f1,0x16c7,0x17a1, |
|---|
| 315 | 0x187f,0x1961,0x1a47,0x1b31,0x1c1f,0x1d11,0x1e07,0x1f01, |
|---|
| 316 | 0x1fff,0x2101,0x2207,0x2311,0x241f,0x2531,0x2647,0x2761, |
|---|
| 317 | 0x287f,0x29a1,0x2ac7,0x2bf1,0x2d1f,0x2e51,0x2f87,0x30c1, |
|---|
| 318 | 0x31ff,0x3341,0x3487,0x35d1,0x371f,0x3871,0x39c7,0x3b21, |
|---|
| 319 | 0x3c7f,0x3de1,0x3f47,0x40b1,0x421f,0x4391,0x4507,0x4681, |
|---|
| 320 | 0x47ff,0x4981,0x4b07,0x4c91,0x4e1f,0x4fb1,0x5147,0x52e1, |
|---|
| 321 | 0x547f,0x5621,0x57c7,0x5971,0x5b1f,0x5cd1,0x5e87,0x6041, |
|---|
| 322 | 0x61ff,0x63c1,0x6587,0x6751,0x691f,0x6af1,0x6cc7,0x6ea1, |
|---|
| 323 | 0x707f,0x7261,0x7447,0x7631,0x781f,0x7a11,0x7c07,0x7fff |
|---|
| 324 | }; |
|---|
| 325 | |
|---|
| 326 | /* ADPCMã»ã»ã»ãããªããããããã ã®DPCMã®ãããããŒãã«ã |
|---|
| 327 | ** èªåçæããããããã ãã©256byteã ã£ãã |
|---|
| 328 | ** ããŒãã«ã§ãåé¡ãªãã§ãã |
|---|
| 329 | */ |
|---|
| 330 | |
|---|
| 331 | char koe_ad_trans_tbl[256] = { |
|---|
| 332 | 0x00,0xff,0x01,0xfe,0x02,0xfd,0x03,0xfc,0x04,0xfb,0x05,0xfa,0x06,0xf9,0x07,0xf8, |
|---|
| 333 | 0x08,0xf7,0x09,0xf6,0x0a,0xf5,0x0b,0xf4,0x0c,0xf3,0x0d,0xf2,0x0e,0xf1,0x0f,0xf0, |
|---|
| 334 | 0x10,0xef,0x11,0xee,0x12,0xed,0x13,0xec,0x14,0xeb,0x15,0xea,0x16,0xe9,0x17,0xe8, |
|---|
| 335 | 0x18,0xe7,0x19,0xe6,0x1a,0xe5,0x1b,0xe4,0x1c,0xe3,0x1d,0xe2,0x1e,0xe1,0x1f,0xe0, |
|---|
| 336 | 0x20,0xdf,0x21,0xde,0x22,0xdd,0x23,0xdc,0x24,0xdb,0x25,0xda,0x26,0xd9,0x27,0xd8, |
|---|
| 337 | 0x28,0xd7,0x29,0xd6,0x2a,0xd5,0x2b,0xd4,0x2c,0xd3,0x2d,0xd2,0x2e,0xd1,0x2f,0xd0, |
|---|
| 338 | 0x30,0xcf,0x31,0xce,0x32,0xcd,0x33,0xcc,0x34,0xcb,0x35,0xca,0x36,0xc9,0x37,0xc8, |
|---|
| 339 | 0x38,0xc7,0x39,0xc6,0x3a,0xc5,0x3b,0xc4,0x3c,0xc3,0x3d,0xc2,0x3e,0xc1,0x3f,0xc0, |
|---|
| 340 | 0x40,0xbf,0x41,0xbe,0x42,0xbd,0x43,0xbc,0x44,0xbb,0x45,0xba,0x46,0xb9,0x47,0xb8, |
|---|
| 341 | 0x48,0xb7,0x49,0xb6,0x4a,0xb5,0x4b,0xb4,0x4c,0xb3,0x4d,0xb2,0x4e,0xb1,0x4f,0xb0, |
|---|
| 342 | 0x50,0xaf,0x51,0xae,0x52,0xad,0x53,0xac,0x54,0xab,0x55,0xaa,0x56,0xa9,0x57,0xa8, |
|---|
| 343 | 0x58,0xa7,0x59,0xa6,0x5a,0xa5,0x5b,0xa4,0x5c,0xa3,0x5d,0xa2,0x5e,0xa1,0x5f,0xa0, |
|---|
| 344 | 0x60,0x9f,0x61,0x9e,0x62,0x9d,0x63,0x9c,0x64,0x9b,0x65,0x9a,0x66,0x99,0x67,0x98, |
|---|
| 345 | 0x68,0x97,0x69,0x96,0x6a,0x95,0x6b,0x94,0x6c,0x93,0x6d,0x92,0x6e,0x91,0x6f,0x90, |
|---|
| 346 | 0x70,0x8f,0x71,0x8e,0x72,0x8d,0x73,0x8c,0x74,0x8b,0x75,0x8a,0x76,0x89,0x77,0x88, |
|---|
| 347 | 0x78,0x87,0x79,0x86,0x7a,0x85,0x7b,0x84,0x7c,0x83,0x7d,0x82,0x7e,0x81,0x7f,0x80 |
|---|
| 348 | }; |
|---|
| 349 | |
|---|
| 350 | extern int is_koe_ogg(char* head); |
|---|
| 351 | extern char* decode_koe_ogg(AvgKoeInfo info, int* dest_len); |
|---|
| 352 | |
|---|
| 353 | char* decode_koe(AvgKoeInfo info, int* dest_len) { |
|---|
| 354 | char buf[1024]; |
|---|
| 355 | char* table; |
|---|
| 356 | unsigned char* src_orig, *src; |
|---|
| 357 | unsigned short* dest_orig, *dest; |
|---|
| 358 | int all_len, i, j; |
|---|
| 359 | if (info.stream == NULL) { |
|---|
| 360 | return NULL; |
|---|
| 361 | } |
|---|
| 362 | fseek(info.stream, info.offset, SEEK_SET); |
|---|
| 363 | if (info.type == koe_nwk) { |
|---|
| 364 | return decode_koe_nwa(info, dest_len); |
|---|
| 365 | } |
|---|
| 366 | fread(buf, 1, 0x20, info.stream); |
|---|
| 367 | if (is_koe_ogg(buf)) { |
|---|
| 368 | fseek(info.stream, -20, SEEK_CUR); |
|---|
| 369 | return decode_koe_ogg(info, dest_len); |
|---|
| 370 | } |
|---|
| 371 | /* avg32 ã®å£°ããŒã¿å±é */ |
|---|
| 372 | table = (char*)malloc(info.length*2); |
|---|
| 373 | fseek(info.stream, info.offset, SEEK_SET); |
|---|
| 374 | fread(table, 2, info.length, info.stream); |
|---|
| 375 | |
|---|
| 376 | all_len = 0; |
|---|
| 377 | for (i=0; i < info.length; i++) |
|---|
| 378 | all_len += read_little_endian_short(table + i*2); |
|---|
| 379 | /* ããŒã¿èªã¿èŸŒã¿ */ |
|---|
| 380 | src_orig = (unsigned char*) malloc(all_len); |
|---|
| 381 | dest_orig = (unsigned short*)malloc(info.length * 0x1000 + 0x2c); |
|---|
| 382 | if (src_orig == NULL || dest_orig == NULL) return NULL; |
|---|
| 383 | src = src_orig; |
|---|
| 384 | fread(src, 1, all_len, info.stream); |
|---|
| 385 | *dest_len = info.length * 0x400 * 4; |
|---|
| 386 | const char* header = MakeWavHeader(info.rate, 2, 2, *dest_len); |
|---|
| 387 | memcpy(dest_orig, header, 0x2c); |
|---|
| 388 | dest = dest_orig + 0x2c; |
|---|
| 389 | /* memset(dest_data, 0, table_len * 0x1000); */ |
|---|
| 390 | |
|---|
| 391 | /* å±é */ |
|---|
| 392 | for (i=0; i<info.length; i++) { |
|---|
| 393 | int slen = read_little_endian_short(table+i*2); |
|---|
| 394 | if (slen == 0) { // do nothing |
|---|
| 395 | memset(dest, 0, 0x1000); |
|---|
| 396 | dest += 0x800; src += 0; |
|---|
| 397 | } else if (slen == 0x400) { // table 倿 |
|---|
| 398 | for (j=0; j<0x400; j++) { |
|---|
| 399 | write_little_endian_short((char*)(dest+0), koe_8bit_trans_tbl[*src]); |
|---|
| 400 | write_little_endian_short((char*)(dest+1), koe_8bit_trans_tbl[*src]); |
|---|
| 401 | dest += 2; src++; |
|---|
| 402 | } |
|---|
| 403 | } else { // DPCM |
|---|
| 404 | char d = 0; short o2; |
|---|
| 405 | int k,j; for (j=0, k=0; j<slen && k < 0x800; j++) { |
|---|
| 406 | unsigned char s = src[j]; |
|---|
| 407 | if ( (s+1) & 0x0f) { |
|---|
| 408 | d -= koe_ad_trans_tbl[s & 0x0f]; |
|---|
| 409 | } else { |
|---|
| 410 | unsigned char s2; |
|---|
| 411 | s >>= 4; s &= 0x0f; s2 = s; |
|---|
| 412 | s = src[++j]; s2 |= (s<<4) & 0xf0; |
|---|
| 413 | d -= koe_ad_trans_tbl[s2]; |
|---|
| 414 | } |
|---|
| 415 | o2 = koe_8bit_trans_tbl[ (unsigned char)d]; |
|---|
| 416 | write_little_endian_short((char*)(dest+k), o2); |
|---|
| 417 | write_little_endian_short((char*)(dest+k+1), o2); |
|---|
| 418 | k+=2; |
|---|
| 419 | s >>= 4; |
|---|
| 420 | if ((s+1) & 0x0f) { |
|---|
| 421 | d -= koe_ad_trans_tbl[s & 0x0f]; |
|---|
| 422 | } else { |
|---|
| 423 | d -= koe_ad_trans_tbl[ src[++j] ]; |
|---|
| 424 | } |
|---|
| 425 | o2 = koe_8bit_trans_tbl[ (unsigned char)d]; |
|---|
| 426 | write_little_endian_short((char*)(dest+k), o2); |
|---|
| 427 | write_little_endian_short((char*)(dest+k+1), o2); |
|---|
| 428 | k+=2; |
|---|
| 429 | } |
|---|
| 430 | dest += 0x800; src += slen; |
|---|
| 431 | } |
|---|
| 432 | } |
|---|
| 433 | free( (void*) table); |
|---|
| 434 | free( (void*) src_orig); |
|---|
| 435 | return (char*)dest_orig; |
|---|
| 436 | } |
|---|
| 437 | |
|---|
| 438 | |
|---|