diff --git a/Content/Blueprints/BP_controller.uasset b/Content/Blueprints/BP_controller.uasset index 58fb054..6a7ef55 100644 Binary files a/Content/Blueprints/BP_controller.uasset and b/Content/Blueprints/BP_controller.uasset differ diff --git a/Content/Blueprints/WidgetSongInfos.uasset b/Content/Blueprints/WidgetSongInfos.uasset index 786d554..8741c73 100644 Binary files a/Content/Blueprints/WidgetSongInfos.uasset and b/Content/Blueprints/WidgetSongInfos.uasset differ diff --git a/Source/MediocreMapAssistant2/BPFileIO.cpp b/Source/MediocreMapAssistant2/BPFileIO.cpp index 1a1e3cf..afaf50b 100644 --- a/Source/MediocreMapAssistant2/BPFileIO.cpp +++ b/Source/MediocreMapAssistant2/BPFileIO.cpp @@ -38,6 +38,159 @@ bool UBPFileIO::VerifyDirectory(const FString & TestDir) return true; } +uint8 getMpegVersion(uint8 num) { + + /* + 00 - MPEG Version 2.5 (unofficial) + 01 - reserved + 10 - MPEG Version 2 (ISO/IEC 13818-3) + 11 - MPEG Version 1 (ISO/IEC 11172-3) + */ + + if ((num & 0x03) == 0x03) { + return 1; + } + + if ((num & 0x02) == 0x02) { + return 2; + } + + return 0; +} + +uint8 getMpegLayer(uint8 num) { + + /** + 00 - reserved + 01 - Layer III + 10 - Layer II + 11 - Layer I + */ + + if ((num & 0x03) == 0x03) { + return 1; + } + + if ((num & 0x02) == 0x02) { + return 2; + } + + if ((num & 0x01) == 0x01) { + return 3; + } + + return 0; +} + +int BITRATES[3][5][16] = { {}, + { + {}, + {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0}, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }, + { + {}, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + } +}; + +int SAMPLE_RATES[3][4] = { + {0, 0, 0, 0}, + {44100, 48000, 32000, 0}, + {22050, 24000, 16000, 0} +}; + +int SAMPLES_PER_FRAME[3][4] = { + {0, 0, 0, 0}, + {0, 384, 1152, 1152}, + {0, 384, 1152, 576} +}; + +int getMpegFrameLength(bool has_padding, int sample_rate, uint8 layer, int bitrate, int num_samples) { + + uint8 padding = has_padding ? 1 : 0; + if (sample_rate == 0) { + return 0; + } + + if (layer == 1) { + return ((int) (12.0 * bitrate / sample_rate + padding)) * 4; + } + + return ((int) (num_samples * (bitrate / 8) / sample_rate)) + padding; +} + +uint8 getMpegChannels(uint8 num) { + + /* + 00 - Stereo + 01 - Joint stereo (Stereo) + 10 - Dual channel (2 mono channels) + 11 - Single channel (Mono) + */ + + if ((num & 0x03) == 0x03) { + return 1; + } + + return 2; +} + +int CheckFrameInfo(TArray FileData, int i, int depth) { + bool isMP3 = (FileData[i] << 8 | (FileData[i + 1] & 0xF0)) == 0xFFF0; + if (!isMP3) return -1; + + bool padding = (FileData[i + 2] & 0x02) >> 1 == 0x01; + uint8 mpegVersion = getMpegVersion(FileData[i + 1] >> 3); + uint8 mpegLayer = getMpegLayer(FileData[i + 1] >> 1); + int bitRate = BITRATES[mpegVersion][mpegLayer][(FileData[i + 2] >> 4) & 0x0F] * 1000; + int sampleRate = SAMPLE_RATES[mpegVersion][(FileData[i + 2] >> 2) & 0x03]; + int sampleCount = SAMPLES_PER_FRAME[mpegVersion][mpegLayer]; + uint8 channels = getMpegChannels(FileData[i + 3] >> 6); + + int frameLength = getMpegFrameLength(padding, sampleRate, mpegLayer, bitRate, sampleCount); + if (frameLength == 0) return -1; + + 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); + + if (depth < 2) { + int otherBitrate = CheckFrameInfo(FileData, i + frameLength, depth + 1); + if (otherBitrate != bitRate) { + return -1; + } + } + return bitRate; +} + +FString UBPFileIO::CheckAudioFormatMatches(const FString & TestPath) +{ + FString unknownProblem = "Error loading song file"; + + TArray FileData; + if (!FFileHelper::LoadFileToArray(FileData, *TestPath)) + { + UE_LOG(LogTemp, Error, TEXT("Failed to load file")); + return unknownProblem; + } + + for (int i = 0; i < 1024; i++) { + if ((FileData[i] << 8 | (FileData[i+1] & 0xF0)) == 0xFFF0) { + if (CheckFrameInfo(FileData, i, 0) != -1) { + return "That looks like an MP3, you can't just rename files to change their type.\nGo get audacity and convert it properly."; + } + + return unknownProblem; + } + } + + return unknownProblem; +} + FString UBPFileIO::CheckImageFormatMatches(const FString & TestPath) { FString unknownProblem = "Something's weird with your cover image, and i don't know what it is."; diff --git a/Source/MediocreMapAssistant2/BPFileIO.h b/Source/MediocreMapAssistant2/BPFileIO.h index 6b5bc45..0e6347d 100644 --- a/Source/MediocreMapAssistant2/BPFileIO.h +++ b/Source/MediocreMapAssistant2/BPFileIO.h @@ -23,6 +23,9 @@ class MEDIOCREMAPASSISTANT2_API UBPFileIO : public UBlueprintFunctionLibrary UFUNCTION(BlueprintCallable, Category = "File IO") static bool VerifyDirectory(const FString& TestDir); + UFUNCTION(BlueprintCallable, Category = "File IO") + static FString CheckAudioFormatMatches(const FString& TestPath); + UFUNCTION(BlueprintCallable, Category = "File IO") static FString CheckImageFormatMatches(const FString& TestPath);