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.

369 lines
8.9 KiB

3 years ago
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. if (FileData.Num() < 1024) {
  144. return unknownProblem;
  145. }
  146. for (int i = 0; i < 1024; i++) {
  147. if ((FileData[i] << 8 | (FileData[i+1] & 0xF0)) == 0xFFF0) {
  148. if (CheckFrameInfo(FileData, i, 0) != -1) {
  149. if (TestPath.EndsWith(".ogg")) {
  150. return "That looks like an MP3, you can't just rename files to change their type.\nGo get audacity and convert it properly.";
  151. }
  152. return "That looks like an MP3, but it needs to be an ogg.\nPlease use audacity to convert it.";
  153. }
  154. return unknownProblem;
  155. }
  156. }
  157. return unknownProblem;
  158. }
  159. FString UBPFileIO::CheckImageFormatMatches(const FString & TestPath)
  160. {
  161. FString unknownProblem = "Something's weird with your cover image, and i don't know what it is.";
  162. IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
  163. TArray<uint8> FileData;
  164. if (!FFileHelper::LoadFileToArray(FileData, *TestPath))
  165. {
  166. UE_LOG(LogTemp, Error, TEXT("Failed to load file"));
  167. return unknownProblem;
  168. }
  169. EImageFormat fileFormat = ImageWrapperModule.DetectImageFormat(FileData.GetData(), FileData.Num());
  170. if ((TestPath.EndsWith(".png") && fileFormat == EImageFormat::PNG) ||
  171. ((TestPath.EndsWith(".jpg") || TestPath.EndsWith(".jpeg")) && (fileFormat == EImageFormat::JPEG || fileFormat == EImageFormat::GrayscaleJPEG)))
  172. {
  173. return unknownProblem;
  174. } else if (!TestPath.EndsWith(".png") && !TestPath.EndsWith(".jpg") && !TestPath.EndsWith(".jpeg")) {
  175. return "Your cover image needs to be a jpg or png and end with .jpg, .jpeg or .png";
  176. }
  177. FString fileFormatStr;
  178. switch (fileFormat) {
  179. case EImageFormat::BMP:
  180. fileFormatStr = "BMP";
  181. break;
  182. case EImageFormat::PNG:
  183. fileFormatStr = "PNG";
  184. break;
  185. case EImageFormat::JPEG:
  186. case EImageFormat::GrayscaleJPEG:
  187. fileFormatStr = "JPG";
  188. break;
  189. case EImageFormat::ICO:
  190. fileFormatStr = "ICO";
  191. break;
  192. case EImageFormat::EXR:
  193. fileFormatStr = "EXR";
  194. break;
  195. case EImageFormat::ICNS:
  196. fileFormatStr = "ICNS";
  197. break;
  198. case EImageFormat::Invalid:
  199. default:
  200. fileFormatStr = "Unknown";
  201. }
  202. return "Your cover image appears to be a " + fileFormatStr + " file, but the extension does not match";
  203. }
  204. TArray<FString> UBPFileIO::FindAllDirectories(const FString & TestDir)
  205. {
  206. TArray<FString> result;
  207. IFileManager& FileManager = IFileManager::Get();
  208. FString FinalPath = TestDir + "/*";
  209. FileManager.FindFiles(result, *FinalPath, false, true);
  210. return result;
  211. }
  212. TArray<FString> UBPFileIO::FindAllFiles(const FString & TestDir)
  213. {
  214. TArray<FString> result;
  215. IFileManager& FileManager = IFileManager::Get();
  216. FString FinalPath = TestDir + "/*";
  217. FileManager.FindFiles(result, *FinalPath, true, false);
  218. return result;
  219. }
  220. bool UBPFileIO::VerifyFile(const FString & TestFile)
  221. {
  222. if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*TestFile))
  223. {
  224. return true;
  225. }
  226. return false;
  227. }
  228. bool UBPFileIO::RenameOrMoveFile(const FString & InputFile, const FString & OutputFile)
  229. {
  230. if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*InputFile))
  231. {
  232. return false;
  233. }
  234. if (!FPlatformFileManager::Get().GetPlatformFile().MoveFile(*OutputFile, *InputFile))
  235. {
  236. return false;
  237. }
  238. return true;
  239. }
  240. bool UBPFileIO::CopyFile(const FString & File, const FString& OutputDirectory, const FString& newName)
  241. {
  242. IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
  243. if (PlatformFile.FileExists(*File))
  244. {
  245. if (PlatformFile.DirectoryExists(*OutputDirectory))
  246. {
  247. PlatformFile.CopyFile(*FString(OutputDirectory + "/" + newName), *File);
  248. return true;
  249. }
  250. }
  251. return false;
  252. }
  253. bool UBPFileIO::DeleteFile(const FString & File)
  254. {
  255. if (!FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*File))
  256. {
  257. return false;
  258. }
  259. return true;
  260. }
  261. bool UBPFileIO::DeleteDirectory(const FString & Directory)
  262. {
  263. if (!FPlatformFileManager::Get().GetPlatformFile().DeleteDirectoryRecursively(*Directory))
  264. {
  265. return false;
  266. }
  267. return true;
  268. }
  269. int UBPFileIO::getFileSize(const FString & File)
  270. {
  271. return FPlatformFileManager::Get().GetPlatformFile().FileSize(*File);
  272. }
  273. int UBPFileIO::getTimestamp(const FString & File)
  274. {
  275. return FPlatformFileManager::Get().GetPlatformFile().GetTimeStamp(*File).ToUnixTimestamp();
  276. }
  277. bool UBPFileIO::SaveStringTextToFile(
  278. FString SaveDirectory,
  279. FString JoyfulFileName,
  280. FString SaveText,
  281. bool AllowOverWriting
  282. ) {
  283. if (!FPlatformFileManager::Get().GetPlatformFile().CreateDirectoryTree(*SaveDirectory))
  284. {
  285. //Could not make the specified directory
  286. return false;
  287. //~~~~~~~~~~~~~~~~~~~~~~
  288. }
  289. //get complete file path
  290. SaveDirectory += "\\";
  291. SaveDirectory += JoyfulFileName;
  292. //No over-writing?
  293. if (!AllowOverWriting)
  294. {
  295. //Check if file exists already
  296. if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*SaveDirectory))
  297. {
  298. //no overwriting
  299. return false;
  300. }
  301. }
  302. return FFileHelper::SaveStringToFile(SaveText, *SaveDirectory, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM);
  303. }