/step2/tools/brstmConv.php

https://gitlab.com/SplatModdingHub/ConversionTools · PHP · 207 lines · 200 code · 6 blank · 1 comment · 10 complexity · 93ec6229600838b335840b8b31307fd4 MD5 · raw file

  1. <?php
  2. // Written by soneek [soneek00@gmail.com][http://github.com/soneek]
  3. function hex2str($hex) { // from http://www.linux-support.com/cms/php-convert-hex-strings-to-ascii-strings/
  4. $str = '';
  5. for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
  6. return $str;
  7. }
  8. function read( $handle, $offset, $nbytes, $type/*bin=0 hex=1 dec=2*/, $endianFlag)
  9. {
  10. fseek( $handle, $offset );
  11. if ($endianFlag)
  12. $output = strrev(fread( $handle, $nbytes ));
  13. else
  14. $output = fread( $handle, $nbytes );
  15. if ( $type != "b" ) {
  16. $output = bin2hex($output);
  17. }
  18. if ( $type == "d" ) {
  19. $output = hexdec( $output );
  20. }
  21. else if ($type == "s") {
  22. $output = hex2str($output);
  23. }
  24. return $output;
  25. }
  26. $file = $argv[1];
  27. if ( !file_exists( $file ) ) {
  28. echo "File doesn't exist (" . $file . ")\n";
  29. exit;
  30. }
  31. else {
  32. if (!isset($argv[2]) || ($argv[2] != "bcstm" && $argv[2] != "bfstm"))
  33. $type = "bcstm"; // Default option will be bcstm output
  34. else
  35. $type = $argv[2];
  36. if (isset($argv[3]) && $argv[3] == "fea")
  37. $game = "fea";
  38. else
  39. $game = "";
  40. if ($type == "bcstm")
  41. $endFlag = true;
  42. else
  43. $endFlag = false;
  44. $brstm = fopen($file, "rb");
  45. if (read($brstm, 0, 4, "s", 0) != "RSTM") {
  46. echo "Not a brstm file\n";
  47. fclose($brstm);
  48. exit;
  49. }
  50. else {
  51. echo "BRSTM opened\n";
  52. $rstmSize = read($brstm, 8, 4, "d", $endFlag);
  53. $rstmInfoOffset = read($brstm, 0x10, 4, "d", 0);
  54. $rstmType = read($brstm, 0x60, 1, "d", $endFlag);
  55. if ($rstmType != 2) {
  56. echo "This only supports BRSTMs with the DSP-ADPCM codec\n";
  57. fclose($brstm);
  58. exit;
  59. }
  60. else {
  61. $rstmSize = read($brstm, 0x8, 4, "d", false);
  62. $rstmInfoSize = read($brstm, 0x14, 4, "d", false);
  63. $rstmSeekOffset = read($brstm, 0x18, 4, "d", false);
  64. $rstmSeekSize = read($brstm, 0x1c, 4, "d", false);
  65. $rstmDataOffset = read($brstm, 0x20, 4, "d", false);
  66. $rstmDataSize = read($brstm, 0x24, 4, "d", false);
  67. $rstmLoopFlag = read($brstm, 0x61, 1, "d", false);
  68. $rstmChannelCount = read($brstm, 0x62, 1, "d", false);
  69. $rstmSampleRate = read($brstm, 0x64, 2, "d", false);
  70. $rstmLoopStart = read($brstm, 0x68, 4, "d", false);
  71. $rstmSampleCount = read($brstm, 0x6c, 4, "d", false);
  72. $coeffPtr1 = read($brstm, 0x5c, 4, "d", false);
  73. $coeffPtr2 = read($brstm, $coeffPtr1 + 0x50, 4, "d", false);
  74. $coeffOffset = 0x50 + $coeffPtr2;
  75. // Opening output file
  76. $outfile = fopen(str_replace("brstm", $type, $file), "wb");
  77. if ($type == "bcstm") {
  78. fwrite($outfile, "CSTM" . pack("vvvnVvvvvVVvvVVvvV*", 0xfeff, 0x40, 0, 2, $rstmSize, 3, 0, 0x4000, 0, $rstmInfoOffset, $rstmInfoSize, 0x4001, 0, $rstmSeekOffset, $rstmSeekSize, 0x4002, 0, $rstmDataOffset, $rstmDataSize, 0, 0) . "INFO" . pack("VvvVvvVvvV", $rstmInfoSize, 0x4100, 0, 0x18, 0x101, 0, 0x50, 0x101, 0, 0x54 + ceil($rstmChannelCount / 2) * 8) . pack("CCCCV*", $rstmType, $rstmLoopFlag, $rstmChannelCount, 0, $rstmSampleRate, $rstmLoopStart, $rstmSampleCount));
  79. for ($i = 0; $i < 6; $i++)
  80. fwrite($outfile, read($brstm, 0x74 + $i * 4, 4, "b", $endFlag));
  81. fwrite($outfile, pack("VVvvVV", 4, 0x3800, 0x1f00, 0, 0x18, ceil($rstmChannelCount / 2)));
  82. for ($i = 0; $i < ceil($rstmChannelCount / 2); $i++)
  83. fwrite($outfile, pack("vvV", 0x4101, 0, $rstmChannelCount * 12 + 8 + $i * 0x14));
  84. fwrite($outfile, pack("V", $rstmChannelCount));
  85. for ($i = 0; $i < $rstmChannelCount; $i++)
  86. fwrite($outfile, pack("vvV", 0x4102, 0, 4 + $rstmChannelCount * 8 + ($rstmChannelCount / 2) * 0x14 + $i * 8));
  87. $rstmBlahMetaDataOffset = read($brstm, 0x9c, 4, "d", false);
  88. for ($i = 0; $i < $rstmChannelCount / 2; $i++) {
  89. if ($game == "fea" && $i == 0)
  90. fwrite($outfile, pack("CCvvvVVccv", 0x73, 64, 0, 0x100, 0, 0xc, 2, 2 * $i, 2 * $i + 1, 0));
  91. else
  92. fwrite($outfile, pack("CCvvvVVccv", 127, 64, 0, 0x100, 0, 0xc, 2, 2 * $i, 2 * $i + 1, 0));
  93. }
  94. for ($i = 0; $i < $rstmChannelCount; $i++)
  95. fwrite($outfile, pack("vvV", 0x300, 0, $rstmChannelCount * 8 + $i * 0x26));
  96. // Now to write coefficients and stuff
  97. for ($i = 0; $i < $rstmChannelCount; $i++) {
  98. for ($j = 0; $j < 16; $j++)
  99. fwrite($outfile, read($brstm, $coeffOffset + $i * 0x38 + $j * 2, 2, "b", $endFlag));
  100. for ($j = 0; $j < 7; $j++)
  101. fwrite($outfile, read($brstm, $coeffOffset + $i * 0x38 + $j * 2 + 0x22, 2, "b", $endFlag));
  102. }
  103. // Padding the file
  104. if ((ftell($outfile) % 16) != 0)
  105. $padlength = 16 - (ftell($outfile) % 16);
  106. else
  107. $padlength = 0;
  108. for ($i = 0; $i < $padlength; $i++)
  109. fwrite($outfile, pack("C", 0));
  110. $infoSizeDifference = $rstmInfoSize + $rstmInfoOffset - ftell($outfile);
  111. echo $rstmInfoOffset;
  112. fseek($outfile, 0xc, SEEK_SET);
  113. fwrite($outfile, pack("V", $rstmSize - $infoSizeDifference));
  114. fseek($outfile, 0x1c, SEEK_SET);
  115. fwrite($outfile, pack("V", $rstmInfoSize - $infoSizeDifference));
  116. fseek($outfile, 0x24, SEEK_SET);
  117. fwrite($outfile, pack("V", $rstmSeekOffset - $infoSizeDifference));
  118. fseek($outfile, 0x30, SEEK_SET);
  119. fwrite($outfile, pack("V", $rstmDataOffset - $infoSizeDifference));
  120. fseek($outfile, 0, SEEK_END);
  121. fseek($brstm, $rstmSeekOffset + 0x10, SEEK_SET);
  122. fwrite($outfile, "SEEK" . pack("V*", $rstmSeekSize, 0, 0));
  123. for ($i = 0; $i < ($rstmSeekSize - 16) / 2; $i++)
  124. fwrite($outfile, strrev(fread($brstm, 2)));
  125. fseek($brstm, $rstmDataOffset + 0x20, SEEK_SET);
  126. fwrite($outfile, "DATA" . pack("V*", $rstmDataSize, 0, 0, 0, 0, 0, 0));
  127. }
  128. // Converting BRSTM to BFSTM
  129. else if ($type == "bfstm") {
  130. fwrite($outfile, "FSTM" . pack("nnnnNnnnnNNnnNNnnN*", 0xfeff, 0x40, 3, 0, $rstmSize, 3, 0, 0x4000, 0, $rstmInfoOffset, $rstmInfoSize, 0x4001, 0, $rstmSeekOffset, $rstmSeekSize, 0x4002, 0, $rstmDataOffset, $rstmDataSize, 0, 0) . "INFO" . pack("NnnNnnNnnN", $rstmInfoSize, 0x4100, 0, 0x18, 0x101, 0, 0x50, 0x101, 0, 0x54 + ceil($rstmChannelCount / 2) * 8) . pack("CCCCN*", $rstmType, $rstmLoopFlag, $rstmChannelCount, 0, $rstmSampleRate, $rstmLoopStart, $rstmSampleCount));
  131. for ($i = 0; $i < 6; $i++)
  132. fwrite($outfile, read($brstm, 0x74 + $i * 4, 4, "b", $endFlag));
  133. fwrite($outfile, pack("NNnnNV", 4, 0x3800, 0x1f00, 0, 0x18, ceil($rstmChannelCount / 2)));
  134. for ($i = 0; $i < ceil($rstmChannelCount / 2); $i++)
  135. fwrite($outfile, pack("nnN", 0x4101, 0, $rstmChannelCount * 12 + 8 + $i * 0x14));
  136. fwrite($outfile, pack("N", $rstmChannelCount));
  137. for ($i = 0; $i < $rstmChannelCount; $i++)
  138. fwrite($outfile, pack("nnN", 0x4102, 0, 4 + $rstmChannelCount * 8 + ceil($rstmChannelCount / 2) * 0x14 + $i * 8));
  139. for ($i = 0; $i < $rstmChannelCount / 2; $i++) {
  140. fwrite($outfile, pack("CCnNNNCCn", 127, 64, 0, 0x100, 0xc, 2, 2 * $i, 2 * $i + 1, 0));
  141. }
  142. for ($i = 0; $i < $rstmChannelCount; $i++)
  143. fwrite($outfile, pack("nnN", 0x300, 0, $rstmChannelCount * 8 + $i * 0x26));
  144. for ($i = 0; $i < $rstmChannelCount; $i++) {
  145. for ($j = 0; $j < 16; $j++)
  146. fwrite($outfile, read($brstm, $coeffOffset + $i * 0x38 + $j * 2, 2, "b", $endFlag));
  147. for ($j = 0; $j < 7; $j++)
  148. fwrite($outfile, read($brstm, $coeffOffset + $i * 0x38 + $j * 2 + 0x22, 2, "b", $endFlag));
  149. }
  150. // Padding the file
  151. if ((ftell($outfile) % 16) != 0)
  152. $padlength = 16 - (ftell($outfile) % 16);
  153. else
  154. $padlength = 0;
  155. for ($i = 0; $i < $padlength; $i++)
  156. fwrite($outfile, pack("C", 0));
  157. $infoSizeDifference = $rstmInfoSize + $rstmInfoOffset - ftell($outfile);
  158. echo $rstmInfoOffset;
  159. fseek($outfile, 0xc, SEEK_SET);
  160. fwrite($outfile, pack("N", $rstmSize - $infoSizeDifference));
  161. fseek($outfile, 0x1c, SEEK_SET);
  162. fwrite($outfile, pack("N", $rstmInfoSize - $infoSizeDifference));
  163. fseek($outfile, 0x24, SEEK_SET);
  164. fwrite($outfile, pack("N", $rstmSeekOffset - $infoSizeDifference));
  165. fseek($outfile, 0x30, SEEK_SET);
  166. fwrite($outfile, pack("N", $rstmDataOffset - $infoSizeDifference));
  167. fseek($outfile, 0, SEEK_END);
  168. fseek($brstm, $rstmSeekOffset + 0x10, SEEK_SET);
  169. fwrite($outfile, "SEEK" . pack("N*", $rstmSeekSize, 0, 0));
  170. for ($i = 0; $i < ($rstmSeekSize - 16) / 2; $i++)
  171. fwrite($outfile, fread($brstm, 2));
  172. fseek($brstm, $rstmDataOffset + 0x20, SEEK_SET);
  173. fwrite($outfile, "DATA" . pack("N*", $rstmDataSize, 0, 0, 0, 0, 0, 0));
  174. }
  175. // The DATA portion is exactly the same, between B(R/C/F)STM, so we can copy the rest as is
  176. while(!feof($brstm))
  177. fwrite($outfile, fread($brstm, 1024 * 8));
  178. }
  179. }
  180. fclose($outfile);
  181. fclose($brstm);
  182. }
  183. ?>