diff --git a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj index 4cc84507e..b516c5e73 100644 --- a/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj +++ b/Frameworks/vgmstream/vgmstream.xcodeproj/project.pbxproj @@ -12,6 +12,10 @@ 830F885C19C9124C00420FB0 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 830F883919C9101900420FB0 /* Vorbis.framework */; }; 8313E3E61902020400B4B6F1 /* mpg123.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; }; 8313E3E71902021800B4B6F1 /* mpg123.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8313E3431901FBDD00B4B6F1 /* mpg123.framework */; }; + 8323894A1D22419B00482226 /* clHCA.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389481D22419B00482226 /* clHCA.c */; }; + 8323894B1D22419B00482226 /* clHCA.h in Headers */ = {isa = PBXBuildFile; fileRef = 832389491D22419B00482226 /* clHCA.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 832389501D2246C300482226 /* hca.c in Sources */ = {isa = PBXBuildFile; fileRef = 8323894F1D2246C300482226 /* hca.c */; }; + 832389521D224C0800482226 /* hca_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 832389511D224C0800482226 /* hca_decoder.c */; }; 834D3A6E19F47C98001C54F6 /* g1l.c in Sources */ = {isa = PBXBuildFile; fileRef = 834D3A6D19F47C98001C54F6 /* g1l.c */; }; 836F6B4718BDB8880095E648 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 836F6B4518BDB8880095E648 /* InfoPlist.strings */; }; 836F6F1E18BDC2190095E648 /* acm_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 836F6DE018BDC2180095E648 /* acm_decoder.c */; }; @@ -448,6 +452,10 @@ 48C2650E1A5D420800A0A3D6 /* vorbisfile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = vorbisfile.h; path = ../Vorbis/include/vorbis/vorbisfile.h; sourceTree = ""; }; 8313E33D1901FBDC00B4B6F1 /* mpg123.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = mpg123.xcodeproj; path = ../mpg123/mpg123.xcodeproj; sourceTree = ""; }; 8315231718BDECA1009AE289 /* VorbisNoDot.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = VorbisNoDot.xcodeproj; path = ../Vorbis/macosx/VorbisNoDot.xcodeproj; sourceTree = ""; }; + 832389481D22419B00482226 /* clHCA.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = clHCA.c; sourceTree = ""; }; + 832389491D22419B00482226 /* clHCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = clHCA.h; sourceTree = ""; }; + 8323894F1D2246C300482226 /* hca.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca.c; sourceTree = ""; }; + 832389511D224C0800482226 /* hca_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hca_decoder.c; sourceTree = ""; }; 834D3A6D19F47C98001C54F6 /* g1l.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = g1l.c; sourceTree = ""; }; 836F6B3918BDB8880095E648 /* vgmstream.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = vgmstream.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 836F6B4418BDB8880095E648 /* vgmstream-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "vgmstream-Info.plist"; sourceTree = ""; }; @@ -806,6 +814,15 @@ name = Products; sourceTree = ""; }; + 832389471D22419B00482226 /* ext_libs */ = { + isa = PBXGroup; + children = ( + 832389481D22419B00482226 /* clHCA.c */, + 832389491D22419B00482226 /* clHCA.h */, + ); + path = ext_libs; + sourceTree = ""; + }; 836F6B2F18BDB8880095E648 = { isa = PBXGroup; children = ( @@ -846,6 +863,7 @@ 836F6B4218BDB8880095E648 /* vgmstream */ = { isa = PBXGroup; children = ( + 832389471D22419B00482226 /* ext_libs */, 836F6DDE18BDC2180095E648 /* src */, 836F6B4318BDB8880095E648 /* Supporting Files */, ); @@ -881,6 +899,7 @@ 836F6DDF18BDC2180095E648 /* coding */ = { isa = PBXGroup; children = ( + 832389511D224C0800482226 /* hca_decoder.c */, 83D7318B1A749EEE00CA1366 /* g719_decoder.c */, 836F6DE018BDC2180095E648 /* acm_decoder.c */, 836F6DE118BDC2180095E648 /* acm_decoder.h */, @@ -961,6 +980,7 @@ 836F6E2718BDC2180095E648 /* meta */ = { isa = PBXGroup; children = ( + 8323894F1D2246C300482226 /* hca.c */, 83EDE5D61A70951A005F5D84 /* mca.c */, 83EDE5D71A70951A005F5D84 /* btsnd.c */, 834D3A6D19F47C98001C54F6 /* g1l.c */, @@ -1237,6 +1257,7 @@ 836F6F3518BDC2190095E648 /* nwa_decoder.h in Headers */, 836F6F2718BDC2190095E648 /* g72x_state.h in Headers */, 836F705418BDC2190095E648 /* streamfile.h in Headers */, + 8323894B1D22419B00482226 /* clHCA.h in Headers */, 836F705918BDC2190095E648 /* vgmstream.h in Headers */, 48C2650F1A5D420800A0A3D6 /* vorbisfile.h in Headers */, 836F705718BDC2190095E648 /* util.h in Headers */, @@ -1426,6 +1447,7 @@ 836F6F3318BDC2190095E648 /* ngc_dtk_decoder.c in Sources */, 836F6FBB18BDC2190095E648 /* ngca.c in Sources */, 836F6F5218BDC2190095E648 /* ps2_adm_blocked.c in Sources */, + 832389521D224C0800482226 /* hca_decoder.c in Sources */, 836F6F9418BDC2190095E648 /* ivb.c in Sources */, 836F6FF118BDC2190095E648 /* ps2_psw.c in Sources */, 836F6F8D18BDC2190095E648 /* gsp_gsb.c in Sources */, @@ -1643,6 +1665,7 @@ 836F6FBE18BDC2190095E648 /* ogg_vorbis_file.c in Sources */, 836F702618BDC2190095E648 /* s14_sss.c in Sources */, 836F6F4818BDC2190095E648 /* halpst_blocked.c in Sources */, + 8323894A1D22419B00482226 /* clHCA.c in Sources */, 836F702E18BDC2190095E648 /* sli.c in Sources */, 836F701D18BDC2190095E648 /* raw.c in Sources */, 836F6FDE18BDC2190095E648 /* ps2_ild.c in Sources */, @@ -1688,6 +1711,7 @@ 836F702718BDC2190095E648 /* sat_baka.c in Sources */, 836F6F8C18BDC2190095E648 /* gh3_bar.c in Sources */, 836F704B18BDC2190095E648 /* xbox_xmu.c in Sources */, + 832389501D2246C300482226 /* hca.c in Sources */, 836F701B18BDC2190095E648 /* psx_gms.c in Sources */, 836F700518BDC2190095E648 /* ps2_vbk.c in Sources */, 836F6FDF18BDC2190095E648 /* ps2_int.c in Sources */, @@ -1766,6 +1790,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/vgmstream/ext_libs"; INSTALL_PATH = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; @@ -1805,6 +1830,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = "$(SRCROOT)/vgmstream/ext_libs"; INSTALL_PATH = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; SDKROOT = macosx; diff --git a/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.c b/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.c new file mode 100644 index 000000000..692c63a8e --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.c @@ -0,0 +1,1605 @@ + +//-------------------------------------------------- +// インクルード +//-------------------------------------------------- +#include "clHCA.h" +//#include +#include +#include + +#ifdef _MSC_VER +#define inline __inline +#endif + +//-------------------------------------------------- +// インライン関数 +//-------------------------------------------------- +//inline short bswap_s16(short v){short r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +static inline unsigned short bswap_u16(unsigned short v){unsigned short r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +//static inline int bswap_s24(int v){int r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;return r>>8;} +static inline unsigned int bswap_u24(unsigned int v){unsigned int r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +//static inline int bswap_s32(int v){int r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +static inline unsigned int bswap_u32(unsigned int v){unsigned int r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +//static inline long long bswap_s64(long long v){long long r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +//static inline unsigned long long bswap_u64(unsigned long long v){unsigned long long r=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;r<<=8;v>>=8;r|=v&0xFF;return r;} +static inline float bswap_f(float v){unsigned int i=bswap_u32(*(unsigned int *)&v);return *(float *)&i;} +static inline unsigned int ceil2(unsigned int a,unsigned int b){return (b>0)?(a/b+((a%b)?1:0)):0;} + +//-------------------------------------------------- +// structure definitions +//-------------------------------------------------- +typedef struct stHeader{//ファイル情報 (必須) + unsigned int hca; // 'HCA' + unsigned short version; // バージョン。v1.3とv2.0の存在を確認 + unsigned short dataOffset; // データオフセット +} stHeader; +typedef struct stFormat{//フォーマット情報 (必須) + unsigned int fmt; // 'fmt' + unsigned int channelCount:8; // チャンネル数 1〜16 + unsigned int samplingRate:24; // サンプリングレート 1〜0x7FFFFF + unsigned int blockCount; // ブロック数 0以上 + unsigned short r01; // 先頭の無音部分(ブロック数*0x400+0x80) + unsigned short r02; // 末尾の無音部分?計算方法不明(0x226) +} stFormat; +typedef struct stCompress{//圧縮情報 (圧縮情報かデコード情報のどちらか一つが必須) + unsigned int comp; // 'comp' + unsigned short blockSize; // ブロックサイズ(CBRのときに有効?) 8〜0xFFFF、0のときはVBR + unsigned char r01; // 不明(1) 0〜r02 v2.0現在1のみ対応 + unsigned char r02; // 不明(15) r01〜0x1F v2.0現在15のみ対応 + unsigned char r03; // 不明(1)(1) + unsigned char r04; // 不明(1)(0) + unsigned char r05; // 不明(0x80)(0x80) + unsigned char r06; // 不明(0x80)(0x20) + unsigned char r07; // 不明(0)(0x20) + unsigned char r08; // 不明(0)(8) + unsigned char reserve1; // 予約 + unsigned char reserve2; // 予約 +} stCompress; +typedef struct stDecode{//デコード情報 (圧縮情報かデコード情報のどちらか一つが必須) + unsigned int dec; // 'dec' + unsigned short blockSize; // ブロックサイズ(CBRのときに有効?) 8〜0xFFFF、0のときはVBR + unsigned char r01; // 不明(1) 0〜r02 v2.0現在1のみ対応 + unsigned char r02; // 不明(15) r01〜0x1F v2.0現在15のみ対応 + unsigned char count1; // type0とtype1の数-1 + unsigned char count2; // type2の数-1 + unsigned char r03:4; // 不明(0) + unsigned char r04:4; // 不明(0) 0は1に修正される + unsigned char enableCount2; // count2を使うフラグ +} stDecode; +typedef struct stVBR{//可変ビットレート情報 (廃止?) + unsigned int vbr; // 'vbr' + unsigned short r01; // 不明 0〜0x1FF + unsigned short r02; // 不明 +} stVBR; +typedef struct stATH{//ATHテーブル情報 (v2.0から廃止?) + unsigned int ath; // 'ath' + unsigned short type; // テーブルの種類(0:全て0 1:テーブル1) +} stATH; +typedef struct stLoop{//ループ情報 + unsigned int loop; // 'loop' + unsigned int loopStart; // ループ開始ブロックインデックス 0〜loopEnd + unsigned int loopEnd; // ループ終了ブロックインデックス loopStart〜(stFormat::blockCount-1) + unsigned short r01; // 不明(0x80)ループフラグ?ループ回数? + unsigned short r02; // 不明(0x226) +} stLoop; +typedef struct stCipher{//暗号テーブル情報 + unsigned int ciph; // 'ciph' + unsigned short type; // 暗号化の種類(0:暗号化なし 1:鍵なし暗号化 0x38:鍵あり暗号化) +} stCipher; +typedef struct stRVA{//相対ボリューム調節情報 + unsigned int rva; // 'rva' + float volume; // ボリューム +} stRVA; +typedef struct stComment{//コメント情報 + unsigned int comm; // 'comm' + unsigned char len; // コメントの長さ? + //char comment[]; +} stComment; +typedef struct stPadding{//パディング + unsigned int pad; // 'pad' +} stPadding; +typedef struct clATH{ + unsigned char _table[0x80]; +} clATH; +typedef struct clCipher{ + unsigned char _table[0x100]; +} clCipher; +typedef struct stChannel{ + float block[0x80]; + float base[0x80]; + char value[0x80]; + char scale[0x80]; + char value2[8]; + int type; + char *value3; + unsigned int count; + float wav1[0x80]; + float wav2[0x80]; + float wav3[0x80]; + float wave[8][0x80]; +} stChannel; +typedef struct clHCA{ + unsigned int _validFile; + unsigned int _version; + unsigned int _dataOffset; + unsigned int _channelCount; + unsigned int _samplingRate; + unsigned int _blockCount; + unsigned int _fmt_r01; + unsigned int _fmt_r02; + unsigned int _blockSize; + unsigned int _comp_r01; + unsigned int _comp_r02; + unsigned int _comp_r03; + unsigned int _comp_r04; + unsigned int _comp_r05; + unsigned int _comp_r06; + unsigned int _comp_r07; + unsigned int _comp_r08; + unsigned int _comp_r09; + unsigned int _vbr_r01; + unsigned int _vbr_r02; + unsigned int _ath_type; + unsigned int _loopStart; + unsigned int _loopEnd; + unsigned int _loop_r01; + unsigned int _loop_r02; + unsigned int _loopFlg; + unsigned int _ciph_type; + unsigned int _ciph_key1; + unsigned int _ciph_key2; + float _rva_volume; + unsigned int _comm_len; + const char *_comm_comment; + clATH _ath; + clCipher _cipher; + stChannel _channel[0x10]; +} clHCA; +typedef struct clData{ + const unsigned char *_data; + int _size; + int _bit; +} clData; + +//-------------------------------------------------- +// コンストラクタ +//-------------------------------------------------- +static void clATH_constructor(clATH *ath); +static void clCipher_constructor(clCipher *cipher); + +static void clHCA_constructor(clHCA *hca,unsigned int ciphKey1,unsigned int ciphKey2){ + memset(hca,0,sizeof(*hca)); + hca->_ciph_key1 = ciphKey1; + hca->_ciph_key2 = ciphKey2; + clATH_constructor(&hca->_ath); + clCipher_constructor(&hca->_cipher); + hca->_validFile = 0; +} + +//-------------------------------------------------- +// HCAチェック +//-------------------------------------------------- +static int clHCA_CheckFile(void *data,unsigned int size){ + return (data&&size>=4&&(*(unsigned int *)data&0x7F7F7F7F)==0x00414348); +} + +//-------------------------------------------------- +// チェックサム +//-------------------------------------------------- +static unsigned short clHCA_CheckSum(const void *data,int size,unsigned short sum){ + const unsigned char *s, *e; + static const unsigned short v[]={ + 0x0000,0x8005,0x800F,0x000A,0x801B,0x001E,0x0014,0x8011,0x8033,0x0036,0x003C,0x8039,0x0028,0x802D,0x8027,0x0022, + 0x8063,0x0066,0x006C,0x8069,0x0078,0x807D,0x8077,0x0072,0x0050,0x8055,0x805F,0x005A,0x804B,0x004E,0x0044,0x8041, + 0x80C3,0x00C6,0x00CC,0x80C9,0x00D8,0x80DD,0x80D7,0x00D2,0x00F0,0x80F5,0x80FF,0x00FA,0x80EB,0x00EE,0x00E4,0x80E1, + 0x00A0,0x80A5,0x80AF,0x00AA,0x80BB,0x00BE,0x00B4,0x80B1,0x8093,0x0096,0x009C,0x8099,0x0088,0x808D,0x8087,0x0082, + 0x8183,0x0186,0x018C,0x8189,0x0198,0x819D,0x8197,0x0192,0x01B0,0x81B5,0x81BF,0x01BA,0x81AB,0x01AE,0x01A4,0x81A1, + 0x01E0,0x81E5,0x81EF,0x01EA,0x81FB,0x01FE,0x01F4,0x81F1,0x81D3,0x01D6,0x01DC,0x81D9,0x01C8,0x81CD,0x81C7,0x01C2, + 0x0140,0x8145,0x814F,0x014A,0x815B,0x015E,0x0154,0x8151,0x8173,0x0176,0x017C,0x8179,0x0168,0x816D,0x8167,0x0162, + 0x8123,0x0126,0x012C,0x8129,0x0138,0x813D,0x8137,0x0132,0x0110,0x8115,0x811F,0x011A,0x810B,0x010E,0x0104,0x8101, + 0x8303,0x0306,0x030C,0x8309,0x0318,0x831D,0x8317,0x0312,0x0330,0x8335,0x833F,0x033A,0x832B,0x032E,0x0324,0x8321, + 0x0360,0x8365,0x836F,0x036A,0x837B,0x037E,0x0374,0x8371,0x8353,0x0356,0x035C,0x8359,0x0348,0x834D,0x8347,0x0342, + 0x03C0,0x83C5,0x83CF,0x03CA,0x83DB,0x03DE,0x03D4,0x83D1,0x83F3,0x03F6,0x03FC,0x83F9,0x03E8,0x83ED,0x83E7,0x03E2, + 0x83A3,0x03A6,0x03AC,0x83A9,0x03B8,0x83BD,0x83B7,0x03B2,0x0390,0x8395,0x839F,0x039A,0x838B,0x038E,0x0384,0x8381, + 0x0280,0x8285,0x828F,0x028A,0x829B,0x029E,0x0294,0x8291,0x82B3,0x02B6,0x02BC,0x82B9,0x02A8,0x82AD,0x82A7,0x02A2, + 0x82E3,0x02E6,0x02EC,0x82E9,0x02F8,0x82FD,0x82F7,0x02F2,0x02D0,0x82D5,0x82DF,0x02DA,0x82CB,0x02CE,0x02C4,0x82C1, + 0x8243,0x0246,0x024C,0x8249,0x0258,0x825D,0x8257,0x0252,0x0270,0x8275,0x827F,0x027A,0x826B,0x026E,0x0264,0x8261, + 0x0220,0x8225,0x822F,0x022A,0x823B,0x023E,0x0234,0x8231,0x8213,0x0216,0x021C,0x8219,0x0208,0x820D,0x8207,0x0202, + }; + for(s=(const unsigned char *)data,e=s+size;s>8)^*s]; + return sum; +} + +//-------------------------------------------------- +// ヘッダ情報をコンソール出力 +//-------------------------------------------------- +#if 0 +static int clHCA_PrintInfo(const char *filenameHCA){ + FILE *fp; + stHeader header; + unsigned char *data; + unsigned char *s; + unsigned int size; + + // temporaries, so we don't need a state structure + unsigned int _version; + unsigned int _dataOffset; + unsigned int _channelCount; + unsigned int _samplingRate; + unsigned int _blockCount; + unsigned int _fmt_r01; + unsigned int _fmt_r02; + unsigned int _blockSize; + unsigned int _comp_r01; + unsigned int _comp_r02; + unsigned int _comp_r03; + unsigned int _comp_r04; + unsigned int _comp_r05; + unsigned int _comp_r06; + unsigned int _comp_r07; + unsigned int _comp_r08; + unsigned int _comp_r09; + unsigned int _vbr_r01; + unsigned int _vbr_r02; + unsigned int _ath_type; + unsigned int _loopStart; + unsigned int _loopEnd; + unsigned int _loop_r01; + unsigned int _loop_r02; + unsigned int _loopFlg; + unsigned int _ciph_type; + unsigned int _ciph_key1; + unsigned int _ciph_key2; + float _rva_volume; + unsigned int _comm_len; + const char *_comm_comment; + + // チェック + if(!(filenameHCA))return -1; + + // HCAファイルを開く + if((fp = fopen(filenameHCA,"rb")) == NULL){ + printf("Error: ファイルが開けませんでした。\n"); + return -1; + } + + // ヘッダチェック + memset(&header,0,sizeof(header)); + fread(&header,sizeof(header),1,fp); + if(!clHCA_CheckFile(&header,sizeof(header))){ + printf("Error: HCAファイルではありません。\n"); + fclose(fp);return -1; + } + + // ヘッダ解析 + header.dataOffset=bswap_u16(header.dataOffset); + data=(unsigned char*) malloc(header.dataOffset); + if(!data){ + printf("Error: メモリ不足です。\n"); + fclose(fp);return -1; + } + fseek(fp,0,SEEK_SET); + fread(data,header.dataOffset,1,fp); + + s=(unsigned char *)data; + size=header.dataOffset; + + // サイズチェック + if(size=sizeof(stHeader) && (*(unsigned int *)s&0x7F7F7F7F)==0x00414348){ + stHeader *hca=(stHeader *)s;s+=sizeof(stHeader); + _version=bswap_u16(hca->version); + _dataOffset=bswap_u16(hca->dataOffset); + printf("コーデック: HCA\n"); + printf("バージョン: %d.%d\n",_version>>8,_version&0xFF); + //if(size<_dataOffset)return -1; + if(clHCA_CheckSum(hca,_dataOffset,0))printf("※ ヘッダが破損しています。改変してる場合もこの警告が出ます。\n"); + size-=sizeof(stHeader); + }else{ + printf("※ HCAチャンクがありません。再生に必要な情報です。\n"); + } + + // fmt + if(size>=sizeof(stFormat) && (*(unsigned int *)s&0x7F7F7F7F)==0x00746D66){ + stFormat *fmt=(stFormat *)s;s+=sizeof(stFormat);size-=sizeof(stFormat); + _channelCount=fmt->channelCount; + _samplingRate=bswap_u24(fmt->samplingRate); + _blockCount=bswap_u32(fmt->blockCount); + _fmt_r01=bswap_u16(fmt->r01); + _fmt_r02=bswap_u16(fmt->r02); + switch(_channelCount){ + case 1:printf("チャンネル数: モノラル (1チャンネル)\n");break; + case 2:printf("チャンネル数: ステレオ (2チャンネル)\n");break; + default:printf("チャンネル数: %dチャンネル\n",_channelCount);break; + } + if(!(_channelCount>=1&&_channelCount<=16)){ + printf("※ チャンネル数の範囲は1〜16です。\n"); + } + printf("サンプリングレート: %dHz\n",_samplingRate); + if(!(_samplingRate>=1&&_samplingRate<=0x7FFFFF)){ + printf("※ サンプリングレートの範囲は1〜8388607(0x7FFFFF)です。\n"); + } + printf("ブロック数: %d\n",_blockCount); + printf("先頭無音ブロック数: %d\n",(_fmt_r01-0x80)/0x400); + printf("末尾無音サンプル数?: %d\n",_fmt_r02); + }else{ + printf("※ fmtチャンクがありません。再生に必要な情報です。\n"); + } + + // comp + if(size>=sizeof(stCompress) && (*(unsigned int *)s&0x7F7F7F7F)==0x706D6F63){ + stCompress *comp=(stCompress *)s;s+=sizeof(stCompress);size-=sizeof(stCompress); + _blockSize=bswap_u16(comp->blockSize); + _comp_r01=comp->r01; + _comp_r02=comp->r02; + _comp_r03=comp->r03; + _comp_r04=comp->r04; + _comp_r05=comp->r05; + _comp_r06=comp->r06; + _comp_r07=comp->r07; + _comp_r08=comp->r08; + printf("ビットレート: CBR (固定ビットレート)\n"); + printf("ブロックサイズ: 0x%04X\n",_blockSize); + if(!(_blockSize>=8&&_blockSize<=0xFFFF)){ + printf("※ ブロックサイズの範囲は8〜65535(0xFFFF)です。v1.3では0でVBRになるようになってましたが、v2.0から廃止されたようです。\n"); + } + printf("comp1: %d\n",_comp_r01); + printf("comp2: %d\n",_comp_r02); + if(!(_comp_r01>=0&&_comp_r01<=_comp_r02&&_comp_r02<=0x1F)){ + printf("※ comp1とcomp2の範囲は0<=comp1<=comp2<=31です。v2.0現在、comp1は1、comp2は15で固定されています。\n"); + } + printf("comp3: %d\n",_comp_r03); + if(!_comp_r03){ + printf("※ comp3は1以上の値です。\n"); + } + printf("comp4: %d\n",_comp_r04); + printf("comp5: %d\n",_comp_r05); + printf("comp6: %d\n",_comp_r06); + printf("comp7: %d\n",_comp_r07); + printf("comp8: %d\n",_comp_r08); + } + + // dec + else if(size>=sizeof(stDecode) && (*(unsigned int *)s&0x7F7F7F7F)==0x00636564){ + stDecode *dec=(stDecode *)s;s+=sizeof(stDecode);size-=sizeof(stDecode); + _blockSize=bswap_u16(dec->blockSize); + _comp_r01=dec->r01; + _comp_r02=dec->r02; + _comp_r03=dec->r04; + _comp_r04=dec->r03; + _comp_r05=dec->count1+1; + _comp_r06=((dec->enableCount2)?dec->count2:dec->count1)+1; + _comp_r07=_comp_r05-_comp_r06; + _comp_r08=0; + printf("ビットレート: CBR (固定ビットレート)\n"); + printf("ブロックサイズ: 0x%04X\n",_blockSize); + if(!(_blockSize>=8&&_blockSize<=0xFFFF)){ + printf("※ ブロックサイズの範囲は8〜65535(0xFFFF)です。v1.3では0でVBRになるようになってましたが、v2.0から廃止されたようです。\n"); + } + printf("dec1: %d\n",_comp_r01); + printf("dec2: %d\n",_comp_r02); + if(!(_comp_r01>=0&&_comp_r01<=_comp_r02&&_comp_r02<=0x1F)){ + printf("※ dec1とdec2の範囲は0<=dec1<=dec2<=31です。v2.0現在、dec1は1、dec2は15で固定されています。\n"); + } + printf("dec3: %d\n",_comp_r03); + if(!_comp_r03){ + printf("※ dec3は再生時に1以上の値に修正されます。\n"); + } + printf("dec4: %d\n",_comp_r04); + printf("dec5: %d\n",_comp_r05); + printf("dec6: %d\n",_comp_r06); + printf("dec7: %d\n",_comp_r07); + }else{ + printf("※ compチャンクまたはdecチャンクがありません。再生に必要な情報です。\n"); + } + + // vbr + if(size>=sizeof(stVBR) && (*(unsigned int *)s&0x7F7F7F7F)==0x00726276){ + stVBR *vbr=(stVBR *)s;s+=sizeof(stVBR);size-=sizeof(stVBR); + _vbr_r01=bswap_u16(vbr->r01); + _vbr_r02=bswap_u16(vbr->r02); + printf("ビットレート: VBR (可変ビットレート) ※v2.0で廃止されています。\n"); + if(!(_blockSize==0)){ + printf("※ compまたはdecチャンクですでにCBRが指定されています。\n"); + } + printf("vbr1: %d\n",_vbr_r01); + if(!(_vbr_r01>=0&&_vbr_r01<=0x1FF)){ + printf("※ vbr1の範囲は0〜511(0x1FF)です。\n"); + } + printf("vbr2: %d\n",_vbr_r02); + }else{ + _vbr_r01=0; + _vbr_r02=0; + } + + // ath + if(size>=6 && (*(unsigned int *)s&0x7F7F7F7F)==0x00687461){ + stATH *ath=(stATH *)s;s+=6;size-=6;//s+=sizeof(stATH); + _ath_type=ath->type; + printf("ATHタイプ:%d ※v2.0から廃止されています。\n",_ath_type); + }else{ + if(_version<0x200){ + printf("ATHタイプ:1 ※v2.0から廃止されています。\n"); + } + } + + // loop + if(size>=sizeof(stLoop) && (*(unsigned int *)s&0x7F7F7F7F)==0x706F6F6C){ + stLoop *loop=(stLoop *)s;s+=sizeof(stLoop);size-=sizeof(stLoop); + _loopStart=bswap_u32(loop->loopStart); + _loopEnd=bswap_u32(loop->loopEnd); + _loop_r01=bswap_u16(loop->r01); + _loop_r02=bswap_u16(loop->r02); + printf("ループ開始ブロック: %d\n",_loopStart); + printf("ループ終了ブロック: %d\n",_loopEnd); + if(!(_loopStart>=0&&_loopStart<=_loopEnd&&_loopEnd<_blockCount)){ + printf("※ ループ開始ブロックとループ終了ブロックの範囲は、0<=ループ開始ブロック<=ループ終了ブロック<ブロック数 です。\n"); + } + printf("ループ情報1: %d\n",_loop_r01); + printf("ループ情報2: %d\n",_loop_r02); + } + +hca-> // ciph + if(size>=6 && (*(unsigned int *)s&0x7F7F7F7F)==0x68706963){ + stCipher *ciph=(stCipher *)s;s+=6;size-=6;//s+=sizeof(stCipher); + _ciph_type=bswap_u16(ciph->type); + switch(_ciph_type){ + case 0:printf("暗号化タイプ: なし\n");break; + case 1:printf("暗号化タイプ: 鍵無し暗号化\n");break; + case 0x38:printf("暗号化タイプ: 鍵有り暗号化 ※正しい鍵を使わないと出力波形がおかしくなります。\n");break; + default:printf("暗号化タイプ: %d\n",_ciph_type);break; + } + if(!(_ciph_type==0||_ciph_type==1||_ciph_type==0x38)){ + printf("※ この暗号化タイプは、v2.0現在再生できません。\n"); + } + } + + // rva + if(size>=sizeof(stRVA) && (*(unsigned int *)s&0x7F7F7F7F)==0x00617672){ + stRVA *rva=(stRVA *)s;s+=sizeof(stRVA);size-=sizeof(stRVA); + _rva_volume=bswap_f(rva->volume); + printf("相対ボリューム調節: %g倍\n",_rva_volume); + } + + // comm + if(size>=5 && (*(unsigned int *)s&0x7F7F7F7F)==0x6D6D6F63){ + stComment *comm=(stComment *)s;s+=5;size-=5;//s+=sizeof(stComment); + _comm_len=comm->len; + _comm_comment=(const char *)s; + printf("コメント: %s\n",_comm_comment); + } + + free(data); + + // 閉じる + fclose(fp); + + return 0; +} +#endif + +//-------------------------------------------------- +// デコードしてWAVEファイルに保存 +//-------------------------------------------------- +#if 0 +static int clHCA_DecodeToWavefile_Decode(void *fp1,void *fp2,unsigned int address,unsigned int count,void *data,void *modeFunction); + +static void clHCA_DecodeToWavefile_DecodeModeFloat(float f,void *fp){fwrite(&f,sizeof(f),1,(FILE *)fp);} +static void clHCA_DecodeToWavefile_DecodeMode8bit(float f,void *fp){int v=(int)(f*0x7F)+0x80;fwrite(&v,1,1,(FILE *)fp);} +static void clHCA_DecodeToWavefile_DecodeMode16bit(float f,void *fp){int v=(int)(f*0x7FFF);fwrite(&v,2,1,(FILE *)fp);} +static void clHCA_DecodeToWavefile_DecodeMode24bit(float f,void *fp){int v=(int)(f*0x7FFFFF);fwrite(&v,3,1,(FILE *)fp);} +static void clHCA_DecodeToWavefile_DecodeMode32bit(float f,void *fp){int v=(int)(f*0x7FFFFFFF);fwrite(&v,4,1,(FILE *)fp);} + +static int clHCA_DecodeToWavefile(clHCA *hca,const char *filenameHCA,const char *filenameWAV,float volume,int mode,int loop){ + FILE *fp1; + FILE *fp2; + stHeader header; + unsigned char *data1; + unsigned char *data2; + struct stWAVEHeader{ + char riff[4]; + unsigned int riffSize; + char wave[4]; + char fmt[4]; + unsigned int fmtSize; + unsigned short fmtType; + unsigned short fmtChannelCount; + unsigned int fmtSamplingRate; + unsigned int fmtSamplesPerSec; + unsigned short fmtSamplingSize; + unsigned short fmtBitCount; + }wavRiff={'R','I','F','F',0,'W','A','V','E','f','m','t',' ',0x10,0,0,0,0,0,0}; + struct stWAVEsmpl{ + char smpl[4]; + unsigned int smplSize; + unsigned int manufacturer; + unsigned int product; + unsigned int samplePeriod; + unsigned int MIDIUnityNote; + unsigned int MIDIPitchFraction; + unsigned int SMPTEFormat; + unsigned int SMPTEOffset; + unsigned int sampleLoops; + unsigned int samplerData; + unsigned int loop_Identifier; + unsigned int loop_Type; + unsigned int loop_Start; + unsigned int loop_End; + unsigned int loop_Fraction; + unsigned int loop_PlayCount; + }wavSmpl={'s','m','p','l',0x3C,0,0,0,0x3C,0,0,0,1,0x18,0,0,0,0,0,0}; + struct stWAVEnote{ + char note[4]; + unsigned int noteSize; + unsigned int dwName; + }wavNote={'n','o','t','e',0,0}; + struct stWAVEdata{ + char data[4]; + unsigned int dataSize; + }wavData={'d','a','t','a',0}; + + // チェック + if(!(filenameHCA&&filenameWAV&&(mode==0||mode==8||mode==16||mode==24||mode==32)&&loop>=0))return -1; + + // HCAファイルを開く + if((fp1 = fopen(filenameHCA,"rb")) == NULL)return -1; + + // ヘッダチェック + memset(&header,0,sizeof(header)); + fread(&header,sizeof(header),1,fp1); + if(!CheckFile(&header,sizeof(header))){fclose(fp1);return -1;} + + // ヘッダ解析 + header.dataOffset=bswap_u16(header.dataOffset); + data1=(unsigned char*) malloc(header.dataOffset); + if(!data1){fclose(fp1);return -1;} + fseek(fp1,0,SEEK_SET); + fread(data1,header.dataOffset,1,fp1); + if(clHCA_Decode(cl,data1,header.dataOffset,0) < 0){free(data1);fclose(fp1);return -1;} + + // WAVEファイルを開く + if((fp2 = fopen(filenameWAV,"wb")) == NULL){free(data1);fclose(fp1);return -1;} + + // WAVEヘッダを書き込み + wavRiff.fmtType=(mode>0)?1:3; + wavRiff.fmtChannelCount=hca->_channelCount; + wavRiff.fmtBitCount=(mode>0)?mode:32; + wavRiff.fmtSamplingRate=hca->_samplingRate; + wavRiff.fmtSamplingSize=wavRiff.fmtBitCount/8*wavRiff.fmtChannelCount; + wavRiff.fmtSamplesPerSec=wavRiff.fmtSamplingRate*wavRiff.fmtSamplingSize; + if(hca->_loopFlg){ + wavSmpl.samplePeriod=(unsigned int)(1/(double)wavRiff.fmtSamplingRate*1000000000); + wavSmpl.loop_Start=hca->_loopStart*0x80*8*wavRiff.fmtSamplingSize; + wavSmpl.loop_End=hca->_loopEnd*0x80*8*wavRiff.fmtSamplingSize; + wavSmpl.loop_PlayCount=(hca->_loop_r01==0x80)?0:hca->_loop_r01; + }else if(loop){ + wavSmpl.loop_Start=0; + wavSmpl.loop_End=hca->_blockCount*0x80*8*wavRiff.fmtSamplingSize; + hca->_loopStart=0; + hca->_loopEnd=hca->_blockCount; + } + if(_comm_comment){ + wavNote.noteSize=4+hca->_comm_len+1; + if(wavNote.noteSize&3)wavNote.noteSize+=4-(wavNote.noteSize&3); + } + wavData.dataSize=hca->_blockCount*0x80*8*wavRiff.fmtSamplingSize+(wavSmpl.loop_End-wavSmpl.loop_Start)*loop; + wavRiff.riffSize=0x1C+((hca->_loopFlg&&!loop)?sizeof(wavSmpl):0)+(hca->_comm_comment?8+wavNote.noteSize:0)+sizeof(wavData)+wavData.dataSize; + fwrite(&wavRiff,sizeof(wavRiff),1,fp2); + if(hca->_loopFlg&&!loop)fwrite(&wavSmpl,sizeof(wavSmpl),1,fp2); + if(hca->_comm_comment){ + int address=ftell(fp2); + fwrite(&wavNote,sizeof(wavNote),1,fp2); + fputs(hca->_comm_comment,fp2); + fseek(fp2,address+8+wavNote.noteSize,SEEK_SET); + } + fwrite(&wavData,sizeof(wavData),1,fp2); + + // 相対ボリュームを調節 + hca->_rva_volume*=volume; + + // デコード + void *modeFunction; + switch(mode){ + case 0:modeFunction=(void *)clHCA_DecodeToWavefile_DecodeModeFloat;break; + case 8:modeFunction=(void *)clHCA_DecodeToWavefile_DecodeMode8bit;break; + case 16:modeFunction=(void *)clHCA_DecodeToWavefile_DecodeMode16bit;break; + case 24:modeFunction=(void *)clHCA_DecodeToWavefile_DecodeMode24bit;break; + case 32:modeFunction=(void *)clHCA_DecodeToWavefile_DecodeMode32bit;break; + } + data2=(unsigned char*) malloc(_blockSize); + if(!data2){free(data1);fclose(fp2);fclose(fp1);return -1;} + if(!loop){ + if(clHCA_DecodeToWavefile_Decode(cl,fp1,fp2,_dataOffset,_blockCount,data2,modeFunction) < 0){free(data2);free(data1);fclose(fp2);fclose(fp1);return -1;} + }else{ + unsigned int loopBlockOffset=hca->_dataOffset+hca->_loopStart*hca->_blockSize; + unsigned int loopBlockCount=hca->_loopEnd-hca->_loopStart; + int i; + if(clHCA_DecodeToWavefile_Decode(cl,fp1,fp2,_dataOffset,_loopEnd,data2,modeFunction) < 0){free(data2);free(data1);fclose(fp2);fclose(fp1);return -1;} + for(i=1;i_blockSize,1,(FILE *)fp1); + if(clHCA_Decode(cl,data,hca->_blockSize,address) < 0)return -1; + for(i=0;i<8;i++){ + for(j=0;j<0x80;j++){ + for(k=0,m=hca->_channelCount;k1){f=1;}else if(f<-1){f=-1;} + ((void (*)(float,void *))modeFunction)(f,fp2); + } + } + } + } + return 0; +} +#endif + +//-------------------------------------------------- +// Decoder utilities +//-------------------------------------------------- + +int clHCA_isOurFile0(const void *data){ + const unsigned char *s=(const unsigned char*)data; + if((*(const unsigned int *)s&0x7F7F7F7F)==0x00414348){ + const stHeader *hca=(const stHeader *)s; + return bswap_u16(hca->dataOffset); + } + return -1; +} + +int clHCA_isOurFile1(const void *data, unsigned int size){ + int minsize; + if (size<8)return -1; + minsize = clHCA_isOurFile0(data); + if (minsize < 0 || minsize > size)return -1; + if (clHCA_CheckSum(data, minsize, 0))return -1; + return 0; +} + +int clHCA_getInfo(clHCA *hca, clHCA_stInfo *info){ + if (!hca->_validFile)return -1; + info->version=hca->_version; + info->dataOffset=hca->_dataOffset; + info->samplingRate=hca->_samplingRate; + info->channelCount=hca->_channelCount; + info->blockSize=hca->_blockSize; + info->blockCount=hca->_blockCount; + info->loopEnabled=hca->_loopFlg; + info->loopStart=hca->_loopStart; + info->loopEnd=hca->_loopEnd; + return 0; +} + +void clHCA_DecodeSamples16(clHCA *hca,signed short *samples){ + const float scale = 32768.0f; + float f; + signed int s; + const float _rva_volume=hca->_rva_volume; + for(int i=0;i<8;i++){ + for(int j=0;j<0x80;j++){ + for(unsigned int k=0,l=hca->_channelCount;k_channel[k].wave[i][j]*_rva_volume; + if(f>1){f=1;}else if(f<-1){f=-1;} + s=(signed int)(f*scale); + if ((unsigned)(s+0x8000)&0xFFFF0000)s=(s>>31)^0x7FFF; + *samples++=(signed short)s; + } + } + } +} + +//-------------------------------------------------- +// Allocation and creation +//-------------------------------------------------- + +int clHCA_sizeof(){ + return sizeof(clHCA); +} + +void clHCA_clear(clHCA *hca,unsigned int ciphKey1,unsigned int ciphKey2){ + clHCA_constructor(hca,ciphKey1,ciphKey2); +} + +clHCA * clHCA_new(unsigned int ciphKey1, unsigned int ciphKey2){ + clHCA *hca = (clHCA *) malloc(clHCA_sizeof()); + if (hca){ + clHCA_constructor(hca,ciphKey1,ciphKey2); + } + return hca; +} + +void clHCA_delete(clHCA *hca){ + free(hca); +} + +//-------------------------------------------------- +// ATH +//-------------------------------------------------- +static void clATH_Init0(clATH *ath); +static void clATH_Init1(clATH *ath,unsigned int key); + +void clATH_constructor(clATH *ath){ + memset(ath,0,sizeof(*ath)); + clATH_Init0(ath); +} + +static int clATH_Init(clATH *ath,int type,unsigned int key){ + switch(type){ + case 0:clATH_Init0(ath);break; + case 1:clATH_Init1(ath,key);break; + default:return -1; + } + return 0; +} + +static const unsigned char * clATH_GetTable(clATH *ath){ + return ath->_table; +} + +void clATH_Init0(clATH *ath){ + memset(ath->_table,0,sizeof(ath->_table)); +} + +void clATH_Init1(clATH *ath, unsigned int key){ + unsigned int i, v; + unsigned char *_table=ath->_table; + static const unsigned char list[]={ + 0x78,0x5F,0x56,0x51,0x4E,0x4C,0x4B,0x49,0x48,0x48,0x47,0x46,0x46,0x45,0x45,0x45, + 0x44,0x44,0x44,0x44,0x43,0x43,0x43,0x43,0x43,0x43,0x42,0x42,0x42,0x42,0x42,0x42, + 0x42,0x42,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x3F,0x3F,0x3F,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D, + 0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, + 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B, + 0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3B,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C, + 0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3D,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3F, + 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F, + 0x3F,0x3F,0x3F,0x3F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x41,0x41,0x41,0x41, + 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41, + 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42, + 0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x43,0x43,0x43, + 0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x43,0x44,0x44, + 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x45,0x45,0x45,0x45, + 0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x46,0x46,0x46,0x46,0x46,0x46,0x46,0x46, + 0x46,0x46,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x48,0x48,0x48,0x48, + 0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x4A,0x4A,0x4A,0x4A, + 0x4A,0x4A,0x4A,0x4A,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4B,0x4C,0x4C,0x4C,0x4C,0x4C, + 0x4C,0x4D,0x4D,0x4D,0x4D,0x4D,0x4D,0x4E,0x4E,0x4E,0x4E,0x4E,0x4E,0x4F,0x4F,0x4F, + 0x4F,0x4F,0x4F,0x50,0x50,0x50,0x50,0x50,0x51,0x51,0x51,0x51,0x51,0x52,0x52,0x52, + 0x52,0x52,0x53,0x53,0x53,0x53,0x54,0x54,0x54,0x54,0x54,0x55,0x55,0x55,0x55,0x56, + 0x56,0x56,0x56,0x57,0x57,0x57,0x57,0x57,0x58,0x58,0x58,0x59,0x59,0x59,0x59,0x5A, + 0x5A,0x5A,0x5A,0x5B,0x5B,0x5B,0x5B,0x5C,0x5C,0x5C,0x5D,0x5D,0x5D,0x5D,0x5E,0x5E, + 0x5E,0x5F,0x5F,0x5F,0x60,0x60,0x60,0x61,0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63, + 0x63,0x64,0x64,0x64,0x65,0x65,0x66,0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69, + 0x69,0x6A,0x6A,0x6A,0x6B,0x6B,0x6B,0x6C,0x6C,0x6D,0x6D,0x6D,0x6E,0x6E,0x6F,0x6F, + 0x70,0x70,0x70,0x71,0x71,0x72,0x72,0x73,0x73,0x73,0x74,0x74,0x75,0x75,0x76,0x76, + 0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x7A,0x7A,0x7B,0x7B,0x7C,0x7C,0x7D,0x7D,0x7E, + 0x7E,0x7F,0x7F,0x80,0x80,0x81,0x81,0x82,0x83,0x83,0x84,0x84,0x85,0x85,0x86,0x86, + 0x87,0x88,0x88,0x89,0x89,0x8A,0x8A,0x8B,0x8C,0x8C,0x8D,0x8D,0x8E,0x8F,0x8F,0x90, + 0x90,0x91,0x92,0x92,0x93,0x94,0x94,0x95,0x95,0x96,0x97,0x97,0x98,0x99,0x99,0x9A, + 0x9B,0x9B,0x9C,0x9D,0x9D,0x9E,0x9F,0xA0,0xA0,0xA1,0xA2,0xA2,0xA3,0xA4,0xA5,0xA5, + 0xA6,0xA7,0xA7,0xA8,0xA9,0xAA,0xAA,0xAB,0xAC,0xAD,0xAE,0xAE,0xAF,0xB0,0xB1,0xB1, + 0xB2,0xB3,0xB4,0xB5,0xB6,0xB6,0xB7,0xB8,0xB9,0xBA,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, + 0xC0,0xC1,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xC9,0xCA,0xCB,0xCC,0xCD, + 0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD, + 0xDE,0xDF,0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xED,0xEE, + 0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFF,0xFF, + }; + for(i=0,v=0;i<0x80;i++,v+=key){ + unsigned int index=v>>13; + if(index>=0x28E){ + memset(&_table[i],0xFF,0x80-i); + break; + } + _table[i]=list[index]; + } +} + +//-------------------------------------------------- +// 暗号化テーブル +//-------------------------------------------------- +static void clCipher_Init0(clCipher *cipher); +static void clCipher_Init1(clCipher *cipher); +static void clCipher_Init56(clCipher *cipher,unsigned int key1,unsigned int key2); + +void clCipher_constructor(clCipher *cipher){ + memset(cipher,0,sizeof(*cipher)); + clCipher_Init0(cipher); +} + +static int clCipher_Init(clCipher *cipher,int type,unsigned int key1,unsigned int key2){ + if(!(key1|key2))type=0; + switch(type){ + case 0:clCipher_Init0(cipher);break; + case 1:clCipher_Init1(cipher);break; + case 56:clCipher_Init56(cipher,key1,key2);break; + default:return -1; + } + return 0; +} + +static void clCipher_Mask(clCipher *cipher,void *data,int size){ + unsigned char *_table=cipher->_table; + unsigned char *d; + for(d=(unsigned char *)data;size>0;d++,size--)*d=_table[*d]; +} + +void clCipher_Init0(clCipher *cipher){ + unsigned char *_table=cipher->_table; + int i; + for(i=0;i<0x100;i++)_table[i]=i; +} + +void clCipher_Init1(clCipher *cipher){ + unsigned char *_table=cipher->_table; + int i, v; + for(i=1,v=0;i<0xFF;i++){ + v=(v*13+11)&0xFF; + if(v==0||v==0xFF)v=(v*13+11)&0xFF; + _table[i]=v; + } + _table[0]=0; + _table[0xFF]=0xFF; +} + +static void clCipher_Init56_CreateTable(unsigned char *r,unsigned char key); + +void clCipher_Init56(clCipher *cipher,unsigned int key1,unsigned int key2){ + unsigned char *_table=cipher->_table; + + // テーブル1を生成 + unsigned char t1[8]; + unsigned char t2[0x10]; + unsigned char t3[0x100],t31[0x10],t32[0x10],*t; + + int i, v; + + if(!key1)key2--; + key1--; + for(i=0;i<7;i++){ + t1[i]=key1; + key1=(key1>>8)|(key2<<24); + key2>>=8; + } + + // テーブル2 + t2[0x00]=t1[1]; t2[0x01]=t1[1]^t1[6]; + t2[0x02]=t1[2]^t1[3]; t2[0x03]=t1[2]; + t2[0x04]=t1[2]^t1[1]; t2[0x05]=t1[3]^t1[4]; + t2[0x06]=t1[3]; t2[0x07]=t1[3]^t1[2]; + t2[0x08]=t1[4]^t1[5]; t2[0x09]=t1[4]; + t2[0x0A]=t1[4]^t1[3]; t2[0x0B]=t1[5]^t1[6]; + t2[0x0C]=t1[5]; t2[0x0D]=t1[5]^t1[4]; + t2[0x0E]=t1[6]^t1[1]; t2[0x0F]=t1[6]; + + // テーブル3 + t=t3; + clCipher_Init56_CreateTable(t31,t1[0]); + for(int i=0;i<0x10;i++){ + clCipher_Init56_CreateTable(t32,t2[i]); + unsigned char v=t31[i]<<4; + for(int j=0;j<0x10;j++){ + *(t++)=v|t32[j]; + } + } + + // CIPHテーブル + t=&_table[1]; + for(i=0,v=0;i<0x100;i++){ + unsigned char a; + v=(v+0x11)&0xFF; + a=t3[v]; + if(a!=0&&a!=0xFF)*(t++)=a; + } + _table[0]=0; + _table[0xFF]=0xFF; + +} + +void clCipher_Init56_CreateTable(unsigned char *r,unsigned char key){ + int mul=((key&1)<<3)|5; + int add=(key&0xE)|1; + key>>=4; + for(int i=0;i<0x10;i++){ + key=(key*mul+add)&0xF; + *(r++)=key; + } +} + +//-------------------------------------------------- +// データ +//-------------------------------------------------- +void clData_constructor(clData *ds,const void *data,int size){ + ds->_data=(const unsigned char *)data; + ds->_size=size*8-16; + ds->_bit=0; +} + +static int clData_CheckBit(clData *ds,int bitSize){ + int v=0; + if(ds->_bit+bitSize<=ds->_size){ + static const int mask[]={0xFFFFFF,0x7FFFFF,0x3FFFFF,0x1FFFFF,0x0FFFFF,0x07FFFF,0x03FFFF,0x01FFFF}; + const unsigned int _bit=ds->_bit; + const unsigned char *data=&ds->_data[_bit>>3]; + v=data[0];v=(v<<8)|data[1];v=(v<<8)|data[2]; + v&=mask[_bit&7]; + v>>=24-(_bit&7)-bitSize; + } + return v; +} + +static int clData_GetBit(clData *ds,int bitSize){ + int v=clData_CheckBit(ds,bitSize); + ds->_bit+=bitSize; + return v; +} + +static void clData_AddBit(clData *ds,int bitSize){ + ds->_bit+=bitSize; +} + +//-------------------------------------------------- +// デコード +//-------------------------------------------------- +static void stChannel_Decode1(stChannel *ch,clData *data,unsigned int a,int b,const unsigned char *ath); +static void stChannel_Decode2(stChannel *ch,clData *data); +static void stChannel_Decode3(stChannel *ch,unsigned int a,unsigned int b,unsigned int c,unsigned int d); +static void stChannel_Decode4(stChannel *ch,int index,unsigned int a,unsigned int b,unsigned int c); +static void stChannel_Decode5(stChannel *ch,int index); + +int clHCA_Decode(clHCA *hca,void *data,unsigned int size,unsigned int address){ + + // チェック + if(!(data))return -1; + + // ヘッダ + if(address==0){ + const unsigned char *s; + char r[0x10]; + unsigned int i, b; + + hca->_validFile = 0; + + s=(const unsigned char *)data; + + // サイズチェック + if(size_version=bswap_u16(h->version); + hca->_dataOffset=bswap_u16(h->dataOffset); + //if(!(_version<=0x200&&_version>0x101))return -1; // バージョンチェック(無効) + if(size_dataOffset)return -1; + //if(clHCA_CheckSum(hca,_dataOffset,0))return -1; // ヘッダの破損チェック(ヘッダ改変を有効にするため破損チェック無効) + size-=sizeof(stHeader); + }else{ + return -1; + } + + // fmt + if(size>=sizeof(stFormat) && (*(const unsigned int *)s&0x7F7F7F7F)==0x00746D66){ + const stFormat *fmt=(const stFormat *)s;s+=sizeof(stFormat);size-=sizeof(stFormat); + hca->_channelCount=fmt->channelCount; + hca->_samplingRate=bswap_u24(fmt->samplingRate); + hca->_blockCount=bswap_u32(fmt->blockCount); + hca->_fmt_r01=bswap_u16(fmt->r01); + hca->_fmt_r02=bswap_u16(fmt->r02); + if(!(hca->_channelCount>=1&&hca->_channelCount<=16))return -1; + if(!(hca->_samplingRate>=1&&hca->_samplingRate<=0x7FFFFF))return -1; + }else{ + return -1; + } + + // comp + if(size>=sizeof(stCompress) && (*(const unsigned int *)s&0x7F7F7F7F)==0x706D6F63){ + const stCompress *comp=(const stCompress *)s;s+=sizeof(stCompress);size-=sizeof(stCompress); + hca->_blockSize=bswap_u16(comp->blockSize); + hca->_comp_r01=comp->r01; + hca->_comp_r02=comp->r02; + hca->_comp_r03=comp->r03; + hca->_comp_r04=comp->r04; + hca->_comp_r05=comp->r05; + hca->_comp_r06=comp->r06; + hca->_comp_r07=comp->r07; + hca->_comp_r08=comp->r08; + if(!((hca->_blockSize>=8&&hca->_blockSize<=0xFFFF)||(hca->_blockSize==0)))return -1; + if(!(/*hca->_comp_r01>=0&&*/hca->_comp_r01<=hca->_comp_r02&&hca->_comp_r02<=0x1F))return -1; + } + + // dec + else if(size>=sizeof(stDecode) && (*(const unsigned int *)s&0x7F7F7F7F)==0x00636564){ + const stDecode *dec=(const stDecode *)s;s+=sizeof(stDecode);size-=sizeof(stDecode); + hca->_blockSize=bswap_u16(dec->blockSize); + hca->_comp_r01=dec->r01; + hca->_comp_r02=dec->r02; + hca->_comp_r03=dec->r04; + hca->_comp_r04=dec->r03; + hca->_comp_r05=dec->count1+1; + hca->_comp_r06=((dec->enableCount2)?dec->count2:dec->count1)+1; + hca->_comp_r07=hca->_comp_r05-hca->_comp_r06; + hca->_comp_r08=0; + if(!((hca->_blockSize>=8&&hca->_blockSize<=0xFFFF)||(hca->_blockSize==0)))return -1; + if(!(/*hca->_comp_r01>=0&&*/hca->_comp_r01<=hca->_comp_r02&&hca->_comp_r02<=0x1F))return -1; + if(!hca->_comp_r03)hca->_comp_r03=1; + }else{ + return -1; + } + + // vbr + if(size>=sizeof(stVBR) && (*(const unsigned int *)s&0x7F7F7F7F)==0x00726276){ + const stVBR *vbr=(const stVBR *)s;s+=sizeof(stVBR);size-=sizeof(stVBR); + hca->_vbr_r01=bswap_u16(vbr->r01); + hca->_vbr_r02=bswap_u16(vbr->r02); + if(!(hca->_blockSize==0&&/*hca->_vbr_r01>=0&&*/hca->_vbr_r01<=0x1FF))return -1; + }else{ + hca->_vbr_r01=0; + hca->_vbr_r02=0; + } + + // ath + if(size>=6 && (*(const unsigned int *)s&0x7F7F7F7F)==0x00687461){ + const stATH *ath=(const stATH *)s;s+=6;size-=6;//s+=sizeof(stATH); + hca->_ath_type=ath->type; + }else{ + hca->_ath_type=(hca->_version<0x200)?1:0;//v1.3ではデフォルト値が1になってたが、v2.0からATHテーブルが廃止されてるみたいなので0に + } + + // loop + if(size>=sizeof(stLoop) && (*(const unsigned int *)s&0x7F7F7F7F)==0x706F6F6C){ + const stLoop *loop=(const stLoop *)s;s+=sizeof(stLoop);size-=sizeof(stLoop); + hca->_loopStart=bswap_u32(loop->loopStart); + hca->_loopEnd=bswap_u32(loop->loopEnd); + hca->_loop_r01=bswap_u16(loop->r01); + hca->_loop_r02=bswap_u16(loop->r02); + hca->_loopFlg=1; + if(!(/*hca->_loopStart>=0&&*/hca->_loopStart<=hca->_loopEnd&&hca->_loopEnd_blockCount))return -1; + }else{ + hca->_loopStart=0; + hca->_loopEnd=0; + hca->_loop_r01=0; + hca->_loop_r02=0x400; + hca->_loopFlg=0; + } + + // ciph + if(size>=6 && (*(const unsigned int *)s&0x7F7F7F7F)==0x68706963){ + const stCipher *ciph=(const stCipher *)s;s+=6;size-=6;//s+=sizeof(stCipher); + hca->_ciph_type=bswap_u16(ciph->type); + if(!(hca->_ciph_type==0||hca->_ciph_type==1||hca->_ciph_type==0x38))return -1; + }else{ + hca->_ciph_type=0; + } + + // rva + if(size>=sizeof(stRVA) && (*(const unsigned int *)s&0x7F7F7F7F)==0x00617672){ + const stRVA *rva=(const stRVA *)s;s+=sizeof(stRVA);size-=sizeof(stRVA); + hca->_rva_volume=bswap_f(rva->volume); + }else{ + hca->_rva_volume=1; + } + + // comm + if(size>=5 && (*(const unsigned int *)s&0x7F7F7F7F)==0x6D6D6F63){ + const stComment *comm=(const stComment *)s;s+=5;size-=5;//s+=sizeof(stComment); + hca->_comm_len=comm->len; + if(hca->_comm_len>size)return -1; + hca->_comm_comment=(char *)s; + s+=hca->_comm_len;size-=hca->_comm_len; + }else{ + hca->_comm_len=0; + hca->_comm_comment=NULL; + } + + // 初期化 + if(clATH_Init(&hca->_ath,hca->_ath_type,hca->_samplingRate) < 0)return -1; + if(clCipher_Init(&hca->_cipher,hca->_ciph_type,hca->_ciph_key1,hca->_ciph_key2))return -1; + + // 値チェック(ヘッダの改変ミスによるエラーを回避するため) + if(!hca->_comp_r03)hca->_comp_r03=1;//0での除算を防ぐため + + // デコード準備 + memset(hca->_channel,0,sizeof(hca->_channel)); + if(!(hca->_comp_r01==1&&hca->_comp_r02==15))return -1; + hca->_comp_r09=ceil2(hca->_comp_r05-(hca->_comp_r06+hca->_comp_r07),hca->_comp_r08); + memset(r,0,sizeof(r)); + b=hca->_channelCount/hca->_comp_r03; + if(hca->_comp_r07&&b>1){ + char *c=r; + for(i=0;i_comp_r03;i++,c+=b){ + switch(b){ + case 2:c[0]=1;c[1]=2;break; + case 3:c[0]=1;c[1]=2;break; + case 4:c[0]=1;c[1]=2;if(hca->_comp_r04==0){c[2]=1;c[3]=2;}break; + case 5:c[0]=1;c[1]=2;if(hca->_comp_r04<=2){c[3]=1;c[4]=2;}break; + case 6:c[0]=1;c[1]=2;c[4]=1;c[5]=2;break; + case 7:c[0]=1;c[1]=2;c[4]=1;c[5]=2;break; + case 8:c[0]=1;c[1]=2;c[4]=1;c[5]=2;c[6]=1;c[7]=2;break; + } + } + } + for(i=0;i_channelCount;i++){ + hca->_channel[i].type=r[i]; + hca->_channel[i].value3=&hca->_channel[i].value[hca->_comp_r06+hca->_comp_r07]; + hca->_channel[i].count=hca->_comp_r06+((r[i]!=2)?hca->_comp_r07:0); + } + + hca->_validFile = 1; + } + + // ブロックデータ + else if(address>=hca->_dataOffset){ + clData d; + int magic; + unsigned int i, j; + if(!hca->_validFile)return -1; + if(size_blockSize)return -1; + if(clHCA_CheckSum(data,hca->_blockSize,0))return -1; + clCipher_Mask(&hca->_cipher,data,hca->_blockSize); + clData_constructor(&d,data,hca->_blockSize); + magic=clData_GetBit(&d,16);//0xFFFF固定 + if(magic==0xFFFF){ + const unsigned int _channelCount=hca->_channelCount; + int a=(clData_GetBit(&d,9)<<8)-clData_GetBit(&d,7); + for(i=0;i<_channelCount;i++)stChannel_Decode1(&hca->_channel[i],&d,hca->_comp_r09,a,clATH_GetTable(&hca->_ath)); + for(i=0;i<8;i++){ + for(j=0;j<_channelCount;j++)stChannel_Decode2(&hca->_channel[j],&d); + for(j=0;j<_channelCount;j++)stChannel_Decode3(&hca->_channel[j],hca->_comp_r09,hca->_comp_r08,hca->_comp_r07+hca->_comp_r06,hca->_comp_r05); + for(j=0;j<_channelCount-1;j++)stChannel_Decode4(&hca->_channel[j],i,hca->_comp_r05-hca->_comp_r06,hca->_comp_r06,hca->_comp_r07); + for(j=0;j<_channelCount;j++)stChannel_Decode5(&hca->_channel[j],i); + } + } + } + + return 0; +} + +//-------------------------------------------------- +// デコード第一段階 +// ベースデータの読み込み +//-------------------------------------------------- +void stChannel_Decode1(stChannel *ch,clData *data,unsigned int a,int b,const unsigned char *ath){ + static const unsigned char scalelist[]={ + // v2.0 + 0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, + 0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, + 0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, + 0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, + 0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, + 0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, + 0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, + 0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // v1.3 + //0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0D,0x0D, + //0x0D,0x0D,0x0D,0x0D,0x0C,0x0C,0x0C,0x0C, + //0x0C,0x0C,0x0B,0x0B,0x0B,0x0B,0x0B,0x0B, + //0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x0A,0x09, + //0x09,0x09,0x09,0x09,0x09,0x08,0x08,0x08, + //0x08,0x08,0x08,0x07,0x06,0x06,0x05,0x04, + //0x04,0x04,0x03,0x03,0x03,0x02,0x02,0x02, + //0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + }; + static const unsigned int valueInt[]={ + 0x342A8D26,0x34633F89,0x3497657D,0x34C9B9BE,0x35066491,0x353311C4,0x356E9910,0x359EF532, + 0x35D3CCF1,0x360D1ADF,0x363C034A,0x367A83B3,0x36A6E595,0x36DE60F5,0x371426FF,0x3745672A, + 0x37838359,0x37AF3B79,0x37E97C38,0x381B8D3A,0x384F4319,0x388A14D5,0x38B7FBF0,0x38F5257D, + 0x3923520F,0x39599D16,0x3990FA4D,0x39C12C4D,0x3A00B1ED,0x3A2B7A3A,0x3A647B6D,0x3A9837F0, + 0x3ACAD226,0x3B071F62,0x3B340AAF,0x3B6FE4BA,0x3B9FD228,0x3BD4F35B,0x3C0DDF04,0x3C3D08A4, + 0x3C7BDFED,0x3CA7CD94,0x3CDF9613,0x3D14F4F0,0x3D467991,0x3D843A29,0x3DB02F0E,0x3DEAC0C7, + 0x3E1C6573,0x3E506334,0x3E8AD4C6,0x3EB8FBAF,0x3EF67A41,0x3F243516,0x3F5ACB94,0x3F91C3D3, + 0x3FC238D2,0x400164D2,0x402C6897,0x4065B907,0x40990B88,0x40CBEC15,0x4107DB35,0x413504F3, + }; + static const unsigned int scaleInt[]={ + 0x00000000,0x3F2AAAAB,0x3ECCCCCD,0x3E924925,0x3E638E39,0x3E3A2E8C,0x3E1D89D9,0x3E088889, + 0x3D842108,0x3D020821,0x3C810204,0x3C008081,0x3B804020,0x3B002008,0x3A801002,0x3A000801, + }; + static const float *valueFloat=(const float *)valueInt; + static const float *scaleFloat=(const float *)scaleInt; + unsigned int i; + const unsigned int count=ch->count; + char *value=ch->value; + char *value2=ch->value2; + char *value3=ch->value3; + char *scale=ch->scale; + float *base=ch->base; + int v=clData_GetBit(data,3); + if(v>=6){ + for(i=0;i>1,v4; + value[0]=v1; + for(i=1;itype==2){ + v=clData_CheckBit(data,4);value2[0]=v; + if(v<15)for(i=0;i<8;i++)value2[i]=clData_GetBit(data,4); + }else{ + for(i=0;i>8)-((v*5)>>1)+1; + if(v<0)v=15; + else if(v>=0x39)v=1; + else v=scalelist[v]; + } + scale[i]=v; + } + memset(&scale[count],0,0x80-count); + for(i=0;icount; + const char *scale=ch->scale; + const float *base=ch->base; + float *block=ch->block; + for(i=0;i>1); + if(!v)clData_AddBit(data,-1); + f=(float)v; + } + block[i]=base[i]*f; + } + memset(&block[count],0,sizeof(float)*(0x80-count)); +} + +//-------------------------------------------------- +// デコード第三段階 +// ブロックデータ修正その1 ※v2.0から追加 +//-------------------------------------------------- +void stChannel_Decode3(stChannel *ch,unsigned int a,unsigned int b,unsigned int c,unsigned int d){ + if(ch->type!=2&&b){ + static const unsigned int listInt[2][0x40]={ + { + 0x00000000,0x00000000,0x32A0B051,0x32D61B5E,0x330EA43A,0x333E0F68,0x337D3E0C,0x33A8B6D5, + 0x33E0CCDF,0x3415C3FF,0x34478D75,0x3484F1F6,0x34B123F6,0x34EC0719,0x351D3EDA,0x355184DF, + 0x358B95C2,0x35B9FCD2,0x35F7D0DF,0x36251958,0x365BFBB8,0x36928E72,0x36C346CD,0x370218AF, + 0x372D583F,0x3766F85B,0x3799E046,0x37CD078C,0x3808980F,0x38360094,0x38728177,0x38A18FAF, + 0x38D744FD,0x390F6A81,0x393F179A,0x397E9E11,0x39A9A15B,0x39E2055B,0x3A16942D,0x3A48A2D8, + 0x3A85AAC3,0x3AB21A32,0x3AED4F30,0x3B1E196E,0x3B52A81E,0x3B8C57CA,0x3BBAFF5B,0x3BF9295A, + 0x3C25FED7,0x3C5D2D82,0x3C935A2B,0x3CC4563F,0x3D02CD87,0x3D2E4934,0x3D68396A,0x3D9AB62B, + 0x3DCE248C,0x3E0955EE,0x3E36FD92,0x3E73D290,0x3EA27043,0x3ED87039,0x3F1031DC,0x3F40213B, + },{ + 0x3F800000,0x3FAA8D26,0x3FE33F89,0x4017657D,0x4049B9BE,0x40866491,0x40B311C4,0x40EE9910, + 0x411EF532,0x4153CCF1,0x418D1ADF,0x41BC034A,0x41FA83B3,0x4226E595,0x425E60F5,0x429426FF, + 0x42C5672A,0x43038359,0x432F3B79,0x43697C38,0x439B8D3A,0x43CF4319,0x440A14D5,0x4437FBF0, + 0x4475257D,0x44A3520F,0x44D99D16,0x4510FA4D,0x45412C4D,0x4580B1ED,0x45AB7A3A,0x45E47B6D, + 0x461837F0,0x464AD226,0x46871F62,0x46B40AAF,0x46EFE4BA,0x471FD228,0x4754F35B,0x478DDF04, + 0x47BD08A4,0x47FBDFED,0x4827CD94,0x485F9613,0x4894F4F0,0x48C67991,0x49043A29,0x49302F0E, + 0x496AC0C7,0x499C6573,0x49D06334,0x4A0AD4C6,0x4A38FBAF,0x4A767A41,0x4AA43516,0x4ADACB94, + 0x4B11C3D3,0x4B4238D2,0x4B8164D2,0x4BAC6897,0x4BE5B907,0x4C190B88,0x4C4BEC15,0x00000000, + } + }; + static const float *listFloat=(float *)listInt[1]; + unsigned int i, j, k, l; + const char *value=ch->value; + const char *value3=ch->value3; + float *block=ch->block; + for(i=0,k=c,l=c-1;itype==1&&c){ + static const unsigned int listInt[]={ + // v2.0 + 0x40000000,0x3FEDB6DB,0x3FDB6DB7,0x3FC92492,0x3FB6DB6E,0x3FA49249,0x3F924925,0x3F800000, + 0x3F5B6DB7,0x3F36DB6E,0x3F124925,0x3EDB6DB7,0x3E924925,0x3E124925,0x00000000,0x00000000, + 0x00000000,0x32A0B051,0x32D61B5E,0x330EA43A,0x333E0F68,0x337D3E0C,0x33A8B6D5,0x33E0CCDF, + 0x3415C3FF,0x34478D75,0x3484F1F6,0x34B123F6,0x34EC0719,0x351D3EDA,0x355184DF,0x358B95C2, + 0x35B9FCD2,0x35F7D0DF,0x36251958,0x365BFBB8,0x36928E72,0x36C346CD,0x370218AF,0x372D583F, + 0x3766F85B,0x3799E046,0x37CD078C,0x3808980F,0x38360094,0x38728177,0x38A18FAF,0x38D744FD, + 0x390F6A81,0x393F179A,0x397E9E11,0x39A9A15B,0x39E2055B,0x3A16942D,0x3A48A2D8,0x3A85AAC3, + 0x3AB21A32,0x3AED4F30,0x3B1E196E,0x3B52A81E,0x3B8C57CA,0x3BBAFF5B,0x3BF9295A,0x3C25FED7, + //↓この2行要らない? + 0x3C5D2D82,0x3C935A2B,0x3CC4563F,0x3D02CD87,0x3D2E4934,0x3D68396A,0x3D9AB62B,0x3DCE248C, + 0x3E0955EE,0x3E36FD92,0x3E73D290,0x3EA27043,0x3ED87039,0x3F1031DC,0x3F40213B,0x00000000, + // v1.3 + //0x40000000,0x3FEDB6DB,0x3FDB6DB7,0x3FC92492,0x3FB6DB6E,0x3FA49249,0x3F924925,0x3F800000, + //0x3F5B6DB7,0x3F36DB6E,0x3F124925,0x3EDB6DB7,0x3E924925,0x3E124925,0x00000000,0x00000000, + }; + float f1=((float *)listInt)[ch[1].value2[index]]; + float f2=f1-2.0f; + float *s=&ch->block[b]; + float *d=&ch[1].block[b]; + unsigned int i; + for(i=0;iblock;d=ch->wav1; + for(i=0,count1=1,count2=0x40;i<7;i++,count1<<=1,count2>>=1){ + float *d1=d; + float *d2=&d[count2]; + float *w; + for(j=0;jwav1;d=ch->block; + for(i=0,count1=0x40,count2=1;i<7;i++,count1>>=1,count2<<=1){ + const float *list1Float=(const float *)list1Int[i]; + const float *list2Float=(const float *)list2Int[i]; + s1=s; + s2=&s1[count2]; + float *d1=d; + float *d2=&d1[count2*2-1]; + float *w; + for(j=0;jwav2; + for(i=0;i<0x80;i++)*(d++)=*(s++); + s=(const float *)list3Int;d=ch->wave[index]; + s1=&ch->wav2[0x40];s2=ch->wav3; + for(int i=0;i<0x40;i++)*(d++)=*(s1++)**(s++)+*(s2++); + for(int i=0;i<0x40;i++)*(d++)=*(s++)**(--s1)-*(s2++); + s1=&ch->wav2[0x40-1];d=ch->wav3; + for(int i=0;i<0x40;i++)*(d++)=*(s1--)**(--s); + for(int i=0;i<0x40;i++)*(d++)=*(--s)**(++s1); +} + diff --git a/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.h b/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.h new file mode 100644 index 000000000..1daaaf825 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/ext_libs/clHCA.h @@ -0,0 +1,66 @@ +#ifndef _clHCA_H +#define _clHCA_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { clHCA_samplesPerBlock = 0x80 * 8 }; + +/* Must pass at least 8 bytes of data to this function. Returns -1 on non-match, or + * positive byte count on success. */ +int clHCA_isOurFile0(const void *data); + +/* Must pass a full header block for success. Returns 0 on success, -1 on failure. */ +int clHCA_isOurFile1(const void *data, unsigned int size); + +/* The opaque state structure. */ +typedef struct clHCA clHCA; + +/* In case you wish to allocate the structure on your own. */ +int clHCA_sizeof(); +void clHCA_clear(clHCA *, unsigned int ciphKey1, unsigned int ciphKey2); + +/* Or you could let the library allocate it. */ +clHCA * clHCA_new(unsigned int ciphKey1, unsigned int ciphKey2); +void clHCA_delete(clHCA *); + +/* Requires a pre-allocated data structure. + * Before any decoding may be performed, the header block must be passed in. + * The recommended way of doing this is to detect the header length with + * clHCA_isOurFile0, validate the header with clHCA_isOurFile1, then pass + * it to this function, with the address of 0. + * Subsequent decodes with non-zero address are assumed to be sample blocks, + * and should be of the blockSize returned by the clHCA_getInfo function. + * Returns 0 on success, -1 on failure. */ +int clHCA_Decode(clHCA *, void *data, unsigned int size, unsigned int address); + +/* This is the simplest decode function, for signed and clipped 16 bit samples. + * May be called after clHCA_Decode, and will return the same data until the next + * block of sample data is passed to clHCA_Decode. */ +void clHCA_DecodeSamples16(clHCA *, signed short * outSamples); + +typedef struct clHCA_stInfo { + unsigned int version; + unsigned int dataOffset; + unsigned int samplingRate; + unsigned int channelCount; + unsigned int blockSize; + unsigned int blockCount; + unsigned int loopEnabled; + unsigned int loopStart; + unsigned int loopEnd; +} clHCA_stInfo; + +/* Retrieve information relevant for decoding and playback with this function. + * Must be called after successfully decoding a header block with clHCA_Decode, + * or else it will fail. + * Returns 0 on success, -1 on failure. */ +int clHCA_getInfo(clHCA *, clHCA_stInfo *out); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c new file mode 100644 index 000000000..5e43dbc63 --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/coding/hca_decoder.c @@ -0,0 +1,82 @@ +#include "../vgmstream.h" + +void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels) { + int samples_done = 0; + + int32_t samples_remain = clHCA_samplesPerBlock - data->sample_ptr; + + void *hca_data = NULL; + + clHCA *hca; + + if ( data->samples_discard ) { + if ( samples_remain <= data->samples_discard ) { + data->samples_discard -= samples_remain; + samples_remain = 0; + } + else { + samples_remain -= data->samples_discard; + data->sample_ptr += data->samples_discard; + data->samples_discard = 0; + } + } + + if ( samples_remain > samples_to_do ) samples_remain = samples_to_do; + + memcpy( outbuf, data->sample_buffer + data->sample_ptr * data->info.channelCount, samples_remain * data->info.channelCount * sizeof(sample) ); + + outbuf += samples_remain * data->info.channelCount; + + data->sample_ptr += samples_remain; + + samples_done += samples_remain; + + hca_data = malloc( data->info.blockSize ); + + if ( !hca_data ) return; + + hca = (clHCA *)(data + 1); + + while ( samples_done < samples_to_do ) { + const unsigned int blockSize = data->info.blockSize; + const unsigned int channelCount = data->info.channelCount; + const unsigned int address = data->info.dataOffset + data->curblock * blockSize; + + if (data->curblock >= data->info.blockCount) { + memset(outbuf, 0, (samples_to_do - samples_done) * channelCount * sizeof(sample)); + break; + } + + if ( read_streamfile((uint8_t*) hca_data, data->start + address, blockSize, data->streamfile) != blockSize ) + break; + + if ( clHCA_Decode( hca, hca_data, blockSize, address ) < 0 ) + break; + + ++data->curblock; + + clHCA_DecodeSamples16( hca, data->sample_buffer ); + + samples_remain = clHCA_samplesPerBlock; + data->sample_ptr = 0; + if ( data->samples_discard ) { + if ( samples_remain <= data->samples_discard ) { + data->samples_discard -= samples_remain; + samples_remain = 0; + } + else { + samples_remain -= data->samples_discard; + data->sample_ptr = data->samples_discard; + data->samples_discard = 0; + } + } + + if ( samples_remain > samples_to_do - samples_done ) samples_remain = samples_to_do - samples_done; + memcpy( outbuf, data->sample_buffer, samples_remain * channelCount * sizeof(sample) ); + samples_done += samples_remain; + outbuf += samples_remain * channelCount; + data->sample_ptr = samples_remain; + } + + free( hca_data ); +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/hca.c b/Frameworks/vgmstream/vgmstream/src/meta/hca.c new file mode 100644 index 000000000..ff8891a0c --- /dev/null +++ b/Frameworks/vgmstream/vgmstream/src/meta/hca.c @@ -0,0 +1,98 @@ +#include "../vgmstream.h" +#include "meta.h" +#include "../util.h" + +VGMSTREAM * init_vgmstream_hca_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); + +VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) { + return init_vgmstream_hca_offset( streamFile, 0, streamFile->get_size(streamFile) ); +} + +VGMSTREAM * init_vgmstream_hca_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) { + /* These I don't know about... */ + static const unsigned int ciphKey1=0x30DBE1AB; + static const unsigned int ciphKey2=0xCC554639; + + VGMSTREAM * vgmstream = NULL; + + char filename[PATH_LIMIT]; + + hca_codec_data * hca_file = ( hca_codec_data * ) calloc(1, sizeof(hca_codec_data) + clHCA_sizeof()); + void * hca_data = NULL; + clHCA * hca; + + uint8_t header[8]; + + int header_size; + + if ( !hca_file ) goto fail; + + if ( size < 8 ) goto fail; + + hca_file->streamfile = streamFile; + hca_file->start = start; + hca_file->size = size; + + if ( read_streamfile( header, start, 8, streamFile) != 8 ) goto fail; + + header_size = clHCA_isOurFile0( header ); + + if ( header_size < 0 ) goto fail; + + hca_data = malloc( header_size ); + + if ( !hca_data ) goto fail; + + memcpy( hca_data, header, 8 ); + + if ( read_streamfile( ((uint8_t*)hca_data) + 8, start + 8, header_size - 8, streamFile ) != header_size - 8 ) goto fail; + + if ( clHCA_isOurFile1( hca_data, header_size ) < 0 ) goto fail; + + hca = (clHCA *)(hca_file + 1); + + clHCA_clear(hca, ciphKey1, ciphKey2); + + if (clHCA_Decode(hca, hca_data, header_size, 0) < 0) goto fail; + + if (clHCA_getInfo(hca, &hca_file->info) < 0) goto fail; + + hca_file->sample_ptr = clHCA_samplesPerBlock; + hca_file->samples_discard = 0; + + streamFile->get_name( streamFile, filename, sizeof(filename) ); + + hca_file->streamfile = streamFile->open(streamFile, filename, STREAMFILE_DEFAULT_BUFFER_SIZE); + if (!hca_file->streamfile) goto fail; + + vgmstream = allocate_vgmstream( hca_file->info.channelCount, 1 ); + if (!vgmstream) goto fail; + + free( hca_data ); + + vgmstream->loop_flag = hca_file->info.loopEnabled; + vgmstream->loop_start_sample = hca_file->info.loopStart * clHCA_samplesPerBlock; + vgmstream->loop_end_sample = hca_file->info.loopEnd * clHCA_samplesPerBlock; + + vgmstream->codec_data = hca_file; + + vgmstream->channels = hca_file->info.channelCount; + vgmstream->sample_rate = hca_file->info.samplingRate; + + vgmstream->num_samples = hca_file->info.blockCount * clHCA_samplesPerBlock; + + vgmstream->coding_type = coding_CRI_HCA; + vgmstream->layout_type = layout_none; + vgmstream->meta_type = meta_HCA; + + return vgmstream; + +fail: + if ( hca_data ) { + free( hca_data ); + } + if ( hca_file ) { + free( hca_file ); + } + return NULL; +} diff --git a/Frameworks/vgmstream/vgmstream/src/meta/meta.h b/Frameworks/vgmstream/vgmstream/src/meta/meta.h index c8956f1be..34f8fd99b 100644 --- a/Frameworks/vgmstream/vgmstream/src/meta/meta.h +++ b/Frameworks/vgmstream/vgmstream/src/meta/meta.h @@ -111,6 +111,10 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch VGMSTREAM * init_vgmstream_sli_ogg(STREAMFILE * streamFile); +VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile); + +VGMSTREAM * init_vgmstream_hca_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size); + #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) VGMSTREAM * init_vgmstream_mp4_aac(STREAMFILE * streamFile); diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.c b/Frameworks/vgmstream/vgmstream/src/vgmstream.c index 858c0b5f5..17fdf9a65 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.c +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.c @@ -338,6 +338,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = { init_vgmstream_bcstm, init_vgmstream_3ds_idsp, init_vgmstream_g1l, + init_vgmstream_hca, }; #define INIT_VGMSTREAM_FCNS (sizeof(init_vgmstream_fcns)/sizeof(init_vgmstream_fcns[0])) @@ -432,6 +433,13 @@ void reset_vgmstream(VGMSTREAM * vgmstream) { ov_pcm_seek(ogg_vorbis_file, 0); } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { + hca_codec_data *data = vgmstream->codec_data; + clHCA *hca = (clHCA *)(data + 1); + data->curblock = 0; + data->sample_ptr = clHCA_samplesPerBlock; + data->samples_discard = 0; + } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { mp4_aac_codec_data *data = vgmstream->codec_data; @@ -623,6 +631,12 @@ void close_vgmstream(VGMSTREAM * vgmstream) { } } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { + if (vgmstream->codec_data) { + free(vgmstream->codec_data); + vgmstream->codec_data = NULL; + } + } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { @@ -1018,6 +1032,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { return 54; case coding_MTAF: return 0x80*2; + case coding_CRI_HCA: + return clHCA_samplesPerBlock; #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) case coding_MP4_AAC: return ((mp4_aac_codec_data*)vgmstream->codec_data)->samples_per_frame; @@ -1399,6 +1415,11 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to vgmstream->channels); break; #endif + case coding_CRI_HCA: + decode_hca(vgmstream->codec_data, + buffer+samples_written*vgmstream->channels,samples_to_do, + vgmstream->channels); + break; #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) case coding_MP4_AAC: decode_mp4_aac(vgmstream->codec_data, @@ -1685,6 +1706,12 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) { ov_pcm_seek_lap(ogg_vorbis_file, vgmstream->loop_sample); } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { + hca_codec_data *data = (hca_codec_data *)(vgmstream->codec_data); + data->curblock = data->info.loopStart; + data->sample_ptr = clHCA_samplesPerBlock; + data->samples_discard = 0; + } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data); @@ -3314,7 +3341,7 @@ fail: static int get_vgmstream_channel_count(VGMSTREAM * vgmstream) { if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = vgmstream->codec_data; + scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; if (data) { return data->substream_count; } @@ -3324,7 +3351,7 @@ static int get_vgmstream_channel_count(VGMSTREAM * vgmstream) } #ifdef VGM_USE_VORBIS if (vgmstream->coding_type==coding_ogg_vorbis) { - ogg_vorbis_codec_data *data = vgmstream->codec_data; + ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data; if (data) { return 1; @@ -3334,9 +3361,19 @@ static int get_vgmstream_channel_count(VGMSTREAM * vgmstream) } } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { + hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data; + + if (data) { + return 1; + } + else { + return 0; + } + } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { - mp4_aac_codec_data *data = vgmstream->codec_data; + mp4_aac_codec_data *data = (mp4_aac_codec_data *) vgmstream->codec_data; if (data) { return 1; } @@ -3351,19 +3388,24 @@ static int get_vgmstream_channel_count(VGMSTREAM * vgmstream) static STREAMFILE * get_vgmstream_streamfile(VGMSTREAM * vgmstream, int channel) { if (vgmstream->layout_type==layout_scd_int) { - scd_int_codec_data *data = vgmstream->codec_data; + scd_int_codec_data *data = (scd_int_codec_data *) vgmstream->codec_data; return data->intfiles[channel]; } #ifdef VGM_USE_VORBIS if (vgmstream->coding_type==coding_ogg_vorbis) { - ogg_vorbis_codec_data *data = vgmstream->codec_data; + ogg_vorbis_codec_data *data = (ogg_vorbis_codec_data *) vgmstream->codec_data; return data->ov_streamfile.streamfile; } #endif + if (vgmstream->coding_type==coding_CRI_HCA) { + hca_codec_data *data = (hca_codec_data *) vgmstream->codec_data; + + return data->streamfile; + } #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) if (vgmstream->coding_type==coding_MP4_AAC) { - mp4_aac_codec_data *data = vgmstream->codec_data; + mp4_aac_codec_data *data = (mp4_aac_codec_data *) vgmstream->codec_data; return data->if_file.streamfile; } #endif diff --git a/Frameworks/vgmstream/vgmstream/src/vgmstream.h b/Frameworks/vgmstream/vgmstream/src/vgmstream.h index e7de364a8..c0db60c44 100644 --- a/Frameworks/vgmstream/vgmstream/src/vgmstream.h +++ b/Frameworks/vgmstream/vgmstream/src/vgmstream.h @@ -53,6 +53,8 @@ enum { PATH_LIMIT = 32768 }; #include "maiatrac3plus.h" #endif +#include "clHCA.h" + #ifdef BUILD_VGMSTREAM #include "coding/acm_decoder.h" #include "coding/nwa_decoder.h" @@ -161,6 +163,8 @@ typedef enum { coding_PCM16LE_XOR_int, /* sample-level xor */ coding_LSF, /* lsf ADPCM */ coding_MTAF, /* Konami IMA-derived MTAF ADPCM */ + + coding_CRI_HCA, /* CRI High Compression Audio */ #if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC) coding_MP4_AAC, @@ -593,6 +597,7 @@ typedef enum { meta_G1L, // Tecmo Koei G1L meta_MCA, // Capcom MCA "MADP" meta_XB3D_ADX, // Xenoblade Chronicles 3D ADX + meta_HCA, #ifdef VGM_USE_MP4V2 meta_MP4, #endif @@ -826,6 +831,17 @@ typedef struct { STREAMFILE **intfiles; } scd_int_codec_data; +typedef struct { + STREAMFILE *streamfile; + uint64_t start; + uint64_t size; + clHCA_stInfo info; + unsigned int curblock; + unsigned int sample_ptr, samples_discard; + signed short sample_buffer[clHCA_samplesPerBlock * 16]; + // clHCA exists here +} hca_codec_data; + #ifdef VGM_USE_MP4V2 typedef struct { STREAMFILE *streamfile; diff --git a/Plugins/vgmstream/vgmstream/VGMDecoder.m b/Plugins/vgmstream/vgmstream/VGMDecoder.m index 8757735cf..a03987d40 100644 --- a/Plugins/vgmstream/vgmstream/VGMDecoder.m +++ b/Plugins/vgmstream/vgmstream/VGMDecoder.m @@ -226,7 +226,7 @@ err1: + (NSArray *)fileTypes { - return [NSArray arrayWithObjects:@"2dx9", @"aaap", @"aax", @"acm", @"adp", @"adpcm", @"ads", @"adx", @"afc", @"agsc", @"ahx",@"aifc", @"aiff", @"aix", @"amts", @"as4", @"asd", @"asf", @"asr", @"ass", @"ast", @"aud", @"aus", @"baf", @"baka", @"bar", @"bcstm", @"bcwav", @"bfstm", @"bfwav", @"bfwavnsmbu", @"bg00", @"bgw", @"bh2pcm", @"bmdx", @"bns", @"bnsf", @"bo2", @"brstm", @"caf", @"capdsp", @"ccc", @"cfn", @"cnk", @"dcs", @"dcsw", @"ddsp", @"de2", @"dmsg", @"dsp", @"dvi", @"dxh", @"eam", @"emff", @"enth", @"fag", @"filp", @"fsb", @"fwav", @"gca", @"gcm", @"gcsw", @"gcw", @"genh", @"gms", @"gsp", @"hgc1", @"his", @"hps", @"hwas", @"idsp", @"idvi", @"ikm", @"ild", @"int", @"isd", @"ish", @"ivaud", @"ivb", @"joe", @"kces", @"kcey", @"khv", @"kraw", @"leg", @"logg", @"lps", @"lsf", @"lwav", @"matx", @"mcg", @"mi4", @"mib", @"mic", @"mihb", @"mpdsp", @"msa", @"mss", @"msvp", @"mus", @"musc", @"musx", @"mwv", @"myspd", @"ndp", @"npsf", @"nus3bank", @"nwa", @"omu", @"otm", @"p3d", @"pcm", @"pdt", @"pnb", @"pos", @"psh", @"psw", @"raw", @"rkv", @"rnd", @"rrds", @"rsd", @"rsf", @"rstm", @"rwar", @"rwav", @"rws", @"rwsd", @"rwx", @"rxw", @"s14", @"sab", @"sad", @"sap", @"sc", @"scd", @"sd9", @"sdt", @"seg", @"sfl", @"sfs", @"sl3", @"sli", @"smp", @"smpl", @"snd", @"sng", @"sns", @"spd", @"sps", @"spsd", @"spt", @"spw", @"ss2", @"ss7", @"ssm", @"sss", @"ster", @"sth", @"stm", @"stma", @"str", @"strm", @"sts", @"stx", @"svag", @"svs", @"swav", @"swd", @"tec", @"thp", @"tk5", @"tydsp", @"um3", @"vag", @"vas", @"vgs", @"vig", @"vjdsp", @"voi", @"vpk", @"vs", @"vsf", @"waa", @"wac", @"wad", @"wam", @"was", @"wavm", @"wb", @"wii", @"wp2", @"wsd", @"wsi", @"wvs", @"xa", @"xa2", @"xa30", @"xmu", @"xss", @"xvas", @"xwav", @"xwb", @"ydsp", @"ymf", @"zsd", @"zwdsp", nil]; + return [NSArray arrayWithObjects:@"2dx9", @"aaap", @"aax", @"acm", @"adp", @"adpcm", @"ads", @"adx", @"afc", @"agsc", @"ahx",@"aifc", @"aiff", @"aix", @"amts", @"as4", @"asd", @"asf", @"asr", @"ass", @"ast", @"aud", @"aus", @"baf", @"baka", @"bar", @"bcstm", @"bcwav", @"bfstm", @"bfwav", @"bfwavnsmbu", @"bg00", @"bgw", @"bh2pcm", @"bmdx", @"bns", @"bnsf", @"bo2", @"brstm", @"caf", @"capdsp", @"ccc", @"cfn", @"cnk", @"dcs", @"dcsw", @"ddsp", @"de2", @"dmsg", @"dsp", @"dvi", @"dxh", @"eam", @"emff", @"enth", @"fag", @"filp", @"fsb", @"fwav", @"gca", @"gcm", @"gcsw", @"gcw", @"genh", @"gms", @"gsp", @"hca", @"hgc1", @"his", @"hps", @"hwas", @"idsp", @"idvi", @"ikm", @"ild", @"int", @"isd", @"ish", @"ivaud", @"ivb", @"joe", @"kces", @"kcey", @"khv", @"kraw", @"leg", @"logg", @"lps", @"lsf", @"lwav", @"matx", @"mcg", @"mi4", @"mib", @"mic", @"mihb", @"mpdsp", @"msa", @"mss", @"msvp", @"mus", @"musc", @"musx", @"mwv", @"myspd", @"ndp", @"npsf", @"nus3bank", @"nwa", @"omu", @"otm", @"p3d", @"pcm", @"pdt", @"pnb", @"pos", @"psh", @"psw", @"raw", @"rkv", @"rnd", @"rrds", @"rsd", @"rsf", @"rstm", @"rwar", @"rwav", @"rws", @"rwsd", @"rwx", @"rxw", @"s14", @"sab", @"sad", @"sap", @"sc", @"scd", @"sd9", @"sdt", @"seg", @"sfl", @"sfs", @"sl3", @"sli", @"smp", @"smpl", @"snd", @"sng", @"sns", @"spd", @"sps", @"spsd", @"spt", @"spw", @"ss2", @"ss7", @"ssm", @"sss", @"ster", @"sth", @"stm", @"stma", @"str", @"strm", @"sts", @"stx", @"svag", @"svs", @"swav", @"swd", @"tec", @"thp", @"tk5", @"tydsp", @"um3", @"vag", @"vas", @"vgs", @"vig", @"vjdsp", @"voi", @"vpk", @"vs", @"vsf", @"waa", @"wac", @"wad", @"wam", @"was", @"wavm", @"wb", @"wii", @"wp2", @"wsd", @"wsi", @"wvs", @"xa", @"xa2", @"xa30", @"xmu", @"xss", @"xvas", @"xwav", @"xwb", @"ydsp", @"ymf", @"zsd", @"zwdsp", nil]; } + (NSArray *)mimeTypes