A modded EditSaber for making beat saber maps.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
8.1 KiB

3 years ago
3 years ago
  1. // Fill out your copyright notice in the Description page of Project Settings.
  2. #include "BPFileIO.h"
  3. #include "ModuleManager.h"
  4. #include "FileHelper.h"
  5. #include "ImageUtils.h"
  6. #include "IImageWrapper.h"
  7. #include "IImageWrapperModule.h"
  8. bool UBPFileIO::VerifyOrCreateDirectory(const FString & TestDir)
  9. {
  10. IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
  11. // Directory Exists?
  12. if (!PlatformFile.DirectoryExists(*TestDir))
  13. {
  14. PlatformFile.CreateDirectory(*TestDir);
  15. if (!PlatformFile.DirectoryExists(*TestDir))
  16. {
  17. return false;
  18. }
  19. }
  20. return true;
  21. }
  22. bool UBPFileIO::VerifyDirectory(const FString & TestDir)
  23. {
  24. IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
  25. // Directory Exists?
  26. if (!PlatformFile.DirectoryExists(*TestDir))
  27. {
  28. return false;
  29. }
  30. return true;
  31. }
  32. uint8 getMpegVersion(uint8 num) {
  33. /*
  34. 00 - MPEG Version 2.5 (unofficial)
  35. 01 - reserved
  36. 10 - MPEG Version 2 (ISO/IEC 13818-3)
  37. 11 - MPEG Version 1 (ISO/IEC 11172-3)
  38. */
  39. if ((num & 0x03) == 0x03) {
  40. return 1;
  41. }
  42. if ((num & 0x02) == 0x02) {
  43. return 2;
  44. }
  45. return 0;
  46. }
  47. uint8 getMpegLayer(uint8 num) {
  48. /**
  49. 00 - reserved
  50. 01 - Layer III
  51. 10 - Layer II
  52. 11 - Layer I
  53. */
  54. if ((num & 0x03) == 0x03) {
  55. return 1;
  56. }
  57. if ((num & 0x02) == 0x02) {
  58. return 2;
  59. }
  60. if ((num & 0x01) == 0x01) {
  61. return 3;
  62. }
  63. return 0;
  64. }
  65. int BITRATES[3][5][16] = { {},
  66. {
  67. {},
  68. {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0},
  69. {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0},
  70. {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0},
  71. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  72. },
  73. {
  74. {},
  75. {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0},
  76. {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
  77. {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0},
  78. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  79. }
  80. };
  81. int SAMPLE_RATES[3][4] = {
  82. {0, 0, 0, 0},
  83. {44100, 48000, 32000, 0},
  84. {22050, 24000, 16000, 0}
  85. };
  86. int SAMPLES_PER_FRAME[3][4] = {
  87. {0, 0, 0, 0},
  88. {0, 384, 1152, 1152},
  89. {0, 384, 1152, 576}
  90. };
  91. int getMpegFrameLength(bool has_padding, int sample_rate, uint8 layer, int bitrate, int num_samples) {
  92. uint8 padding = has_padding ? 1 : 0;
  93. if (sample_rate == 0) {
  94. return 0;
  95. }
  96. if (layer == 1) {
  97. return ((int) (12.0 * bitrate / sample_rate + padding)) * 4;
  98. }
  99. return ((int) (num_samples * (bitrate / 8) / sample_rate)) + padding;
  100. }
  101. uint8 getMpegChannels(uint8 num) {
  102. /*
  103. 00 - Stereo
  104. 01 - Joint stereo (Stereo)
  105. 10 - Dual channel (2 mono channels)
  106. 11 - Single channel (Mono)
  107. */
  108. if ((num & 0x03) == 0x03) {
  109. return 1;
  110. }
  111. return 2;
  112. }
  113. int CheckFrameInfo(TArray<uint8> FileData, int i, int depth) {
  114. bool isMP3 = (FileData[i] << 8 | (FileData[i + 1] & 0xF0)) == 0xFFF0;
  115. if (!isMP3) return -1;
  116. bool padding = (FileData[i + 2] & 0x02) >> 1 == 0x01;
  117. uint8 mpegVersion = getMpegVersion(FileData[i + 1] >> 3);
  118. uint8 mpegLayer = getMpegLayer(FileData[i + 1] >> 1);
  119. int bitRate = BITRATES[mpegVersion][mpegLayer][(FileData[i + 2] >> 4) & 0x0F] * 1000;
  120. int sampleRate = SAMPLE_RATES[mpegVersion][(FileData[i + 2] >> 2) & 0x03];
  121. int sampleCount = SAMPLES_PER_FRAME[mpegVersion][mpegLayer];
  122. uint8 channels = getMpegChannels(FileData[i + 3] >> 6);
  123. int frameLength = getMpegFrameLength(padding, sampleRate, mpegLayer, bitRate, sampleCount);
  124. if (frameLength == 0) return -1;
  125. UE_LOG(LogTemp, Error, TEXT("Possible mp3 V: %d, L: %d, P: %d, Bitrate: %d, Channels: %d, Sample rate: %d, Sample count: %d, Frame len: %d"), mpegVersion, mpegLayer, padding, bitRate, channels, sampleRate, sampleCount, frameLength);
  126. if (depth < 2) {
  127. int otherBitrate = CheckFrameInfo(FileData, i + frameLength, depth + 1);
  128. if (otherBitrate != bitRate) {
  129. return -1;
  130. }
  131. }
  132. return bitRate;
  133. }
  134. FString UBPFileIO::CheckAudioFormatMatches(const FString & TestPath)
  135. {
  136. FString unknownProblem = "Error loading song file";
  137. TArray<uint8> FileData;
  138. if (!FFileHelper::LoadFileToArray(FileData, *TestPath))
  139. {
  140. UE_LOG(LogTemp, Error, TEXT("Failed to load file"));
  141. return unknownProblem;
  142. }
  143. for (int i = 0; i < 1024; i++) {
  144. if ((FileData[i] << 8 | (FileData[i+1] & 0xF0)) == 0xFFF0) {
  145. if (CheckFrameInfo(FileData, i, 0) != -1) {
  146. if (TestPath.EndsWith(".ogg")) {
  147. return "That looks like an MP3, you can't just rename files to change their type.\nGo get audacity and convert it properly.";
  148. }
  149. return "That looks like an MP3, but it needs to be an ogg.\nPlease use audacity to convert it.";
  150. }
  151. return unknownProblem;
  152. }
  153. }
  154. return unknownProblem;
  155. }
  156. FString UBPFileIO::CheckImageFormatMatches(const FString & TestPath)
  157. {
  158. FString unknownProblem = "Something's weird with your cover image, and i don't know what it is.";
  159. IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
  160. TArray<uint8> FileData;
  161. if (!FFileHelper::LoadFileToArray(FileData, *TestPath))
  162. {
  163. UE_LOG(LogTemp, Error, TEXT("Failed to load file"));
  164. return unknownProblem;
  165. }
  166. EImageFormat fileFormat = ImageWrapperModule.DetectImageFormat(FileData.GetData(), FileData.Num());
  167. if ((TestPath.EndsWith(".png") && fileFormat == EImageFormat::PNG) ||
  168. ((TestPath.EndsWith(".jpg") || TestPath.EndsWith(".jpeg")) && (fileFormat == EImageFormat::JPEG || fileFormat == EImageFormat::GrayscaleJPEG)))
  169. {
  170. return unknownProblem;
  171. } else if (!TestPath.EndsWith(".png") && !TestPath.EndsWith(".jpg") && !TestPath.EndsWith(".jpeg")) {
  172. return "Your cover image needs to be a jpg or png and end with .jpg, .jpeg or .png";
  173. }
  174. FString fileFormatStr;
  175. switch (fileFormat) {
  176. case EImageFormat::BMP:
  177. fileFormatStr = "BMP";
  178. break;
  179. case EImageFormat::PNG:
  180. fileFormatStr = "PNG";
  181. break;
  182. case EImageFormat::JPEG:
  183. case EImageFormat::GrayscaleJPEG:
  184. fileFormatStr = "JPG";
  185. break;
  186. case EImageFormat::ICO:
  187. fileFormatStr = "ICO";
  188. break;
  189. case EImageFormat::EXR:
  190. fileFormatStr = "EXR";
  191. break;
  192. case EImageFormat::ICNS:
  193. fileFormatStr = "ICNS";
  194. break;
  195. case EImageFormat::Invalid:
  196. default:
  197. fileFormatStr = "Unknown";
  198. }
  199. return "Your cover image appears to be a " + fileFormatStr + " file, but the extension does not match";
  200. }
  201. TArray<FString> UBPFileIO::FindAllDirectories(const FString & TestDir)
  202. {
  203. TArray<FString> result;
  204. IFileManager& FileManager = IFileManager::Get();
  205. FString FinalPath = TestDir + "/*";
  206. FileManager.FindFiles(result, *FinalPath, false, true);
  207. return result;
  208. }
  209. TArray<FString> UBPFileIO::FindAllFiles(const FString & TestDir)
  210. {
  211. TArray<FString> result;
  212. IFileManager& FileManager = IFileManager::Get();
  213. FString FinalPath = TestDir + "/*";
  214. FileManager.FindFiles(result, *FinalPath, true, false);
  215. return result;
  216. }
  217. bool UBPFileIO::VerifyFile(const FString & TestFile)
  218. {
  219. if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*TestFile))
  220. {
  221. return true;
  222. }
  223. return false;
  224. }
  225. bool UBPFileIO::RenameOrMoveFile(const FString & InputFile, const FString & OutputFile)
  226. {
  227. if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*InputFile))
  228. {
  229. return false;
  230. }
  231. if (!FPlatformFileManager::Get().GetPlatformFile().MoveFile(*OutputFile, *InputFile))
  232. {
  233. return false;
  234. }
  235. return true;
  236. }
  237. bool UBPFileIO::CopyFile(const FString & File, const FString& OutputDirectory, const FString& newName)
  238. {
  239. IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
  240. if (PlatformFile.FileExists(*File))
  241. {
  242. if (PlatformFile.DirectoryExists(*OutputDirectory))
  243. {
  244. PlatformFile.CopyFile(*FString(OutputDirectory + "/" + newName), *File);
  245. return true;
  246. }
  247. }
  248. return false;
  249. }
  250. bool UBPFileIO::DeleteFile(const FString & File)
  251. {
  252. if (!FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*File))
  253. {
  254. return false;
  255. }
  256. return true;
  257. }
  258. bool UBPFileIO::DeleteDirectory(const FString & Directory)
  259. {
  260. if (!FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*Directory))
  261. {
  262. return false;
  263. }
  264. return true;
  265. }
  266. int UBPFileIO::getFileSize(const FString & File)
  267. {
  268. return FPlatformFileManager::Get().GetPlatformFile().FileSize(*File);
  269. }
  270. int UBPFileIO::getTimestamp(const FString & File)
  271. {
  272. return FPlatformFileManager::Get().GetPlatformFile().GetTimeStamp(*File).ToUnixTimestamp();
  273. }