diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..1a3f4b8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,25 @@ +name: build + +on: + push: + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: microsoft/setup-msbuild@v1.0.2 + - name: Compile + run: | + msbuild /p:Configuration=Release /p:Platform="x86" + mv Release/*.exe ./ + mv Release/*.dll ./ + 7z a cri2wav.7z *.exe *.dll + - name: Upload + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: cri2wav.7z + tag: latest + overwrite: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1aeef73 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vs/ +Release/ +Debug/ +src/Release/ +src/Debug/ diff --git a/HCADecoder README.md b/HCADecoder README.md new file mode 100644 index 0000000..ee937d1 --- /dev/null +++ b/HCADecoder README.md @@ -0,0 +1,78 @@ +# HCAデコーダ + +# HCAファイルのデコード方法 + + HCAファイルをhca.exeにドラッグ&ドロップすると、同じファイル名のWAVEファイルができます。 + 複数ファイルのデコードにも対応してます。 + デコードオプションはデフォルト値のままです。 + + デコードオプションを指定したいときは + オプション指定デコード.batにドラッグ&ドロップしてください。 + こちらも複数ファイルのデコードに対応してます。 + + +# HCAファイルの復号化方法 + + HCAファイルを復号化.batにドラッグ&ドロップすると、HCAファイル自体が復号化されます。 + 上書きされるので注意してください。 + 複数ファイルの復号化にも対応してます。 + + +# 仕様 + + デフォルトのデコードオプションは + 音量 = 1(倍) + ビットモード = 16(ビット) + ループ回数 = 0(回) + 復号鍵 = CC55463930DBE1AB ※PSO2で使われている鍵 + です。 + + HCAファイルにループ情報が入っていた場合、WAVEファイルにsmplチャンクを追加してます。 + ただし、デコードオプションのループ回数が1回以上のときは、smplチャンクを追加せず、直接波形データとして出力します。 + このとき出力される波形データは以下のようになります。 + ※HCAファイルにループ情報が入っていない場合、ループ開始位置とループ終了位置をそれぞれ先頭位置と末尾位置として扱います。 + [先頭位置~ループ終了位置]+[ループ開始位置~ループ終了位置]×(ループ回数-1)+[ループ開始位置~末尾位置] + + HCAファイルにコメント情報が入っていた場合、WAVEファイルにnoteチャンクを追加してます。 + + +# 注意事項 + + 一応バージョンチェックを外してますが + 今後、v2.1以降のHCAが出てきたとき、デコードに失敗する可能性があります。 + + HCAヘッダの破損チェックも無効にしています。 + これはヘッダを改変しやすくするためです。 + もし本当に破損していてもエラーになりません。 + + 暗号テーブルで使用する鍵はゲーム別に異なります。※開発会社によっては同じ鍵を使うことをがあります。 + 暗号テーブルの種類が0x38のとき、鍵が異なるとうまくデコードされません。 + + 復号鍵を指定してデコードするときは + オプション指定デコード.batをテキストエディタで開いて、デフォルト値設定の復号鍵を変更しておくと楽です。 + + CBRのみ対応。VBRはデコードに失敗します。※VBRは存在しない可能性あり。 + + コマンドプロンプトの仕様で、&を含むファイルパス(ファイル名やフォルダ名)は + オプション指定デコード.batや、復号化.batなどのバッチファイルにドラッグ&ドロップすると + ファイルが開けず、エラーが出ます。 + + +# 免責事項 + + このアプリケーションを利用した事によるいかなる損害も作者は一切の責任を負いません。 + 自己の責任の上で使用して下さい。 + + +# その他 + + HCAv2.0からヘッダのVBRチェックをやってない痕跡があるので + 最初からCBRのみしか存在しないのかもしれない。 + + ATHテーブルもType0しか存在しなかった痕跡あり。 + + 普通にデコードすると16ビットPCMになるので音質が劣化するよ! + オプション指定デコードで、ビットモードをfloatにすると劣化しないよ! + でもHCA自体が非可逆圧縮なので元々劣化してるよ! + どっちだよ! + diff --git a/README.md b/README.md index ee937d1..94a98e9 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,12 @@ -# HCAデコーダ +# 提取转换CriWare CBX/ACB/AWB/HCA音轨 -# HCAファイルのデコード方法 +## Usage +cri2wav directory [key1] [key2] - HCAファイルをhca.exeにドラッグ&ドロップすると、同じファイル名のWAVEファイルができます。 - 複数ファイルのデコードにも対応してます。 - デコードオプションはデフォルト値のままです。 - - デコードオプションを指定したいときは - オプション指定デコード.batにドラッグ&ドロップしてください。 - こちらも複数ファイルのデコードに対応してます。 - - -# HCAファイルの復号化方法 - - HCAファイルを復号化.batにドラッグ&ドロップすると、HCAファイル自体が復号化されます。 - 上書きされるので注意してください。 - 複数ファイルの復号化にも対応してます。 - - -# 仕様 - - デフォルトのデコードオプションは - 音量 = 1(倍) - ビットモード = 16(ビット) - ループ回数 = 0(回) - 復号鍵 = CC55463930DBE1AB ※PSO2で使われている鍵 - です。 - - HCAファイルにループ情報が入っていた場合、WAVEファイルにsmplチャンクを追加してます。 - ただし、デコードオプションのループ回数が1回以上のときは、smplチャンクを追加せず、直接波形データとして出力します。 - このとき出力される波形データは以下のようになります。 - ※HCAファイルにループ情報が入っていない場合、ループ開始位置とループ終了位置をそれぞれ先頭位置と末尾位置として扱います。 - [先頭位置~ループ終了位置]+[ループ開始位置~ループ終了位置]×(ループ回数-1)+[ループ開始位置~末尾位置] - - HCAファイルにコメント情報が入っていた場合、WAVEファイルにnoteチャンクを追加してます。 - - -# 注意事項 - - 一応バージョンチェックを外してますが - 今後、v2.1以降のHCAが出てきたとき、デコードに失敗する可能性があります。 - - HCAヘッダの破損チェックも無効にしています。 - これはヘッダを改変しやすくするためです。 - もし本当に破損していてもエラーになりません。 - - 暗号テーブルで使用する鍵はゲーム別に異なります。※開発会社によっては同じ鍵を使うことをがあります。 - 暗号テーブルの種類が0x38のとき、鍵が異なるとうまくデコードされません。 - - 復号鍵を指定してデコードするときは - オプション指定デコード.batをテキストエディタで開いて、デフォルト値設定の復号鍵を変更しておくと楽です。 - - CBRのみ対応。VBRはデコードに失敗します。※VBRは存在しない可能性あり。 - - コマンドプロンプトの仕様で、&を含むファイルパス(ファイル名やフォルダ名)は - オプション指定デコード.batや、復号化.batなどのバッチファイルにドラッグ&ドロップすると - ファイルが開けず、エラーが出ます。 - - -# 免責事項 - - このアプリケーションを利用した事によるいかなる損害も作者は一切の責任を負いません。 - 自己の責任の上で使用して下さい。 - - -# その他 - - HCAv2.0からヘッダのVBRチェックをやってない痕跡があるので - 最初からCBRのみしか存在しないのかもしれない。 - - ATHテーブルもType0しか存在しなかった痕跡あり。 - - 普通にデコードすると16ビットPCMになるので音質が劣化するよ! - オプション指定デコードで、ビットモードをfloatにすると劣化しないよ! - でもHCA自体が非可逆圧縮なので元々劣化してるよ! - どっちだよ! +## 使用说明 +cri2wav 目录 [密钥1] [密钥2] +## Thanks +[vgmtoolbox](https://sourceforge.net/p/vgmtoolbox/wiki/Home) +[Nyagamon](https://github.com/Nyagamon) +[Perfare](https://github.com/Perfare) diff --git a/Source.cpp b/Source.cpp deleted file mode 100644 index 565841b..0000000 --- a/Source.cpp +++ /dev/null @@ -1,154 +0,0 @@ - -//-------------------------------------------------- -// CN[h -//-------------------------------------------------- -#define WIN32_LEAN_AND_MEAN -#include -#include -#include "clHCA.h" - -//-------------------------------------------------- -// 10iƂ݂ȂĐlɕϊ(ȈՔ) -//-------------------------------------------------- -int atoi(const char *s) { - int r = 0; - bool sign = false; if (*s == '+') { s++; } - else if (*s == '-') { sign = true; s++; } - while (*s) { - if (*s >= '0'&&*s <= '9')r = r * 10 + (*s - '0'); - else break; - s++; - } - return sign ? -r : r; -} -float atof(const char *s) { - int r1 = 0, r2 = 0, c = 1; - bool sign = false; if (*s == '+') { s++; } - else if (*s == '-') { sign = true; s++; } - while (*s) { - if (*s >= '0'&&*s <= '9')r1 = r1 * 10 + (*s - '0'); - else break; - s++; - } - if (*s == '.') { - s++; - while (*s) { - if (*s >= '0'&&*s <= '9') { r2 = r2 * 10 + (*s - '0'); c *= 10; } - else break; - s++; - } - } - float r = r1 + ((c>0) ? r2 / (float)c : 0); - return sign ? -r : r; -} - -//-------------------------------------------------- -// 16iƂ݂ȂĐlɕϊ -//-------------------------------------------------- -int atoi16(const char *s) { - int r = 0; - bool sign = false; if (*s == '+') { s++; } - else if (*s == '-') { sign = true; s++; } - while (*s) { - if (*s >= '0'&&*s <= '9')r = (r << 4) | (*s - '0'); - else if (*s >= 'A'&&*s <= 'F')r = (r << 4) | (*s - 'A' + 10); - else if (*s >= 'a'&&*s <= 'f')r = (r << 4) | (*s - 'a' + 10); - else break; - s++; - } - return sign ? -r : r; -} - -//-------------------------------------------------- -// C -//-------------------------------------------------- -int main(int argc, char *argv[]) { - - // R}hC - unsigned int count = 0; - char *filenameOut = NULL; - //bool decodeFlg=false; - float volume = 1; - unsigned int ciphKey1 = 0xE0748978; - unsigned int ciphKey2 = 0xCF222F1F; - int mode = 16; - int loop = 0; - bool info = false; - bool decrypt = false; - for (int i = 1; i + + + + Debug + Win32 + + + Release + Win32 + + + + {C53C6C2C-9832-4B11-AA47-3EE889961ED1} + v4.0 + ManagedCProj + cri2wav + 10.0 + + + + Application + true + v142 + true + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + true + + + false + + + + Level3 + Disabled + WIN32;_DEBUG;%(PreprocessorDefinitions) + + + + + + + + Level3 + WIN32;NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + format.dll + + + vgmtutil.dll + + + + + + \ No newline at end of file diff --git a/src/cri2wav.vcxproj.user b/src/cri2wav.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/src/cri2wav.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/format.dll b/src/format.dll new file mode 100644 index 0000000..6a128ad Binary files /dev/null and b/src/format.dll differ diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..23266a7 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,59 @@ +#include "clHCA.h" + +using namespace System; +using namespace System::IO; +using namespace System::Runtime::InteropServices; +using namespace VGMToolbox::format; + +int main(array ^args) { + unsigned int ciphKey1 = 0, ciphKey2 = 0; + switch (args->Length) { + case 3: { + ciphKey1 = System::Convert::ToInt32(args[1], 16); + ciphKey2 = System::Convert::ToInt32(args[2], 16); + } + case 1: { + clHCA hca(ciphKey1, ciphKey2); + float volume = 1; + int mode = 16; + int loop = 0; + auto dir = gcnew DirectoryInfo(args[0]); + auto dir2 = Directory::CreateDirectory(args[0] + "/waveout"); + + for each (auto cpkfile in dir->GetFiles("*.cpk", SearchOption::AllDirectories)) { + Console::WriteLine(L"Extract CPK Archive: '{0}'", cpkfile->Name); + auto fs = gcnew FileStream(cpkfile->FullName, FileMode::Open, FileAccess::Read, FileShare::Read); + auto af = gcnew CriCpkArchive(); + af->Initialize(fs, 0, false); + af->ExtractAll(); + fs->Close(); + } + + for each (auto acbfile in dir->GetFiles("*.acb", SearchOption::AllDirectories)) { + Console::WriteLine(L"Extract ACB/AWB Archive: '{0}'", acbfile->Name); + auto fs = gcnew FileStream(acbfile->FullName, FileMode::Open, FileAccess::Read, FileShare::Read); + auto af = gcnew CriAcbFile(fs, 0, false); + af->ExtractAll(); + fs->Close(); + auto destinationFolder = gcnew DirectoryInfo(Path::Combine(acbfile->DirectoryName, L"_vgmt_acb_ext_" + Path::GetFileNameWithoutExtension(acbfile->FullName))); + auto hcafiles = destinationFolder->GetFiles(L"*.hca", SearchOption::AllDirectories); + auto OutFolder = dir2->FullName; + if (hcafiles->Length > 1) { + OutFolder = Path::Combine(dir2->FullName, Path::GetFileNameWithoutExtension(acbfile->FullName)); + Directory::CreateDirectory(OutFolder); + } + for each (auto hcafile in hcafiles) { + Console::WriteLine(L"Convert file: '{0}'", hcafile->Name); + auto filenameIn = (char*)(void*)Marshal::StringToHGlobalAnsi(hcafile->FullName); + auto filenameOut = (char*)(void*)Marshal::StringToHGlobalAnsi(Path::Combine(OutFolder, Path::GetFileNameWithoutExtension(hcafile->FullName) + L".wav")); + hca.DecodeToWavefile(filenameIn, filenameOut, volume, mode, loop); + } + } + return 0; + } + default: { + Console::WriteLine(L"Usage: cri2wav input_directory [key1] [key2]"); + return 1; + } + } +} \ No newline at end of file diff --git a/src/vgmtutil.dll b/src/vgmtutil.dll new file mode 100644 index 0000000..5fb8c24 Binary files /dev/null and b/src/vgmtutil.dll differ