mirror of
https://github.com/Theaninova/BeatLanguageMapper.git
synced 2026-01-19 00:13:06 +00:00
Initial Commit!
いきますよ!
This commit is contained in:
111
Source/MediocreMapper/BPFileIO.cpp
Normal file
111
Source/MediocreMapper/BPFileIO.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "BPFileIO.h"
|
||||
|
||||
bool UBPFileIO::VerifyOrCreateDirectory(const FString & TestDir)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
|
||||
// Directory Exists?
|
||||
if (!PlatformFile.DirectoryExists(*TestDir))
|
||||
{
|
||||
PlatformFile.CreateDirectory(*TestDir);
|
||||
|
||||
if (!PlatformFile.DirectoryExists(*TestDir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UBPFileIO::VerifyDirectory(const FString & TestDir)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
|
||||
// Directory Exists?
|
||||
if (!PlatformFile.DirectoryExists(*TestDir))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TArray<FString> UBPFileIO::FindAllDirectories(const FString & TestDir)
|
||||
{
|
||||
TArray<FString> result;
|
||||
IFileManager& FileManager = IFileManager::Get();
|
||||
FString FinalPath = TestDir + "/*";
|
||||
|
||||
FileManager.FindFiles(result, *FinalPath, false, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
TArray<FString> UBPFileIO::FindAllFiles(const FString & TestDir)
|
||||
{
|
||||
TArray<FString> result;
|
||||
IFileManager& FileManager = IFileManager::Get();
|
||||
FString FinalPath = TestDir + "/*";
|
||||
|
||||
FileManager.FindFiles(result, *FinalPath, true, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool UBPFileIO::VerifyFile(const FString & TestFile)
|
||||
{
|
||||
if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*TestFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UBPFileIO::RenameOrMoveFile(const FString & InputFile, const FString & OutputFile)
|
||||
{
|
||||
if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*InputFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FPlatformFileManager::Get().GetPlatformFile().MoveFile(*OutputFile, *InputFile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UBPFileIO::CopyFile(const FString & File, const FString& OutputDirectory, const FString& newName)
|
||||
{
|
||||
IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
|
||||
|
||||
if (PlatformFile.FileExists(*File))
|
||||
{
|
||||
if (PlatformFile.DirectoryExists(*OutputDirectory))
|
||||
{
|
||||
PlatformFile.CopyFile(*FString(OutputDirectory + "/" + newName), *File);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UBPFileIO::DeleteFile(const FString & File)
|
||||
{
|
||||
if (!FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*File))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UBPFileIO::DeleteDirectory(const FString & Directory)
|
||||
{
|
||||
if (!FPlatformFileManager::Get().GetPlatformFile().DeleteDirectory(*Directory))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
46
Source/MediocreMapper/BPFileIO.h
Normal file
46
Source/MediocreMapper/BPFileIO.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "PlatformFilemanager.h"
|
||||
#include "GenericPlatformFile.h"
|
||||
#include "FileManager.h"
|
||||
#include "BPFileIO.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class MEDIOCREMAPPER_API UBPFileIO : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool VerifyOrCreateDirectory(const FString& TestDir);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool VerifyDirectory(const FString& TestDir);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static TArray<FString> FindAllDirectories(const FString& TestDir);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static TArray<FString> FindAllFiles(const FString& TestDir);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool VerifyFile(const FString& TestFile);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool RenameOrMoveFile(const FString& InputFile, const FString& OutputFile);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool CopyFile(const FString& File, const FString& OutputDirectory, const FString& newName);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool DeleteFile(const FString& File);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "File IO")
|
||||
static bool DeleteDirectory(const FString& Directory);
|
||||
};
|
||||
27
Source/MediocreMapper/BP_BPMChange.cpp
Normal file
27
Source/MediocreMapper/BP_BPMChange.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "BP_BPMChange.h"
|
||||
|
||||
|
||||
// Sets default values
|
||||
ABP_BPMChange::ABP_BPMChange()
|
||||
{
|
||||
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
|
||||
PrimaryActorTick.bCanEverTick = true;
|
||||
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void ABP_BPMChange::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void ABP_BPMChange::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
}
|
||||
|
||||
28
Source/MediocreMapper/BP_BPMChange.h
Normal file
28
Source/MediocreMapper/BP_BPMChange.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "BP_BPMChange.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class MEDIOCREMAPPER_API ABP_BPMChange : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
// Sets default values for this actor's properties
|
||||
ABP_BPMChange();
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
public:
|
||||
// Called every frame
|
||||
virtual void Tick(float DeltaTime) override;
|
||||
|
||||
|
||||
|
||||
};
|
||||
6
Source/MediocreMapper/BeatSaberEditor.cpp
Normal file
6
Source/MediocreMapper/BeatSaberEditor.cpp
Normal file
@@ -0,0 +1,6 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "BeatSaberEditor.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, MediocreMapper, "MediocreMapper" );
|
||||
6
Source/MediocreMapper/BeatSaberEditor.h
Normal file
6
Source/MediocreMapper/BeatSaberEditor.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
25
Source/MediocreMapper/MediocreMapper.Build.cs
Normal file
25
Source/MediocreMapper/MediocreMapper.Build.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class MediocreMapper : ModuleRules
|
||||
{
|
||||
public MediocreMapper(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent" });
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { });
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
||||
// Uncomment if you are using online features
|
||||
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
|
||||
|
||||
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
|
||||
PrivateDependencyModuleNames.AddRange(new string[] { "Kiss_FFT" });
|
||||
PublicDependencyModuleNames.Add("Kiss_FFT");
|
||||
}
|
||||
}
|
||||
288
Source/MediocreMapper/RenderWaveform.cpp
Normal file
288
Source/MediocreMapper/RenderWaveform.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "RenderWaveform.h"
|
||||
|
||||
// KISS Headers, that we need for the decompression part
|
||||
#include "ThirdParty/Kiss_FFT/kiss_fft129/kiss_fft.h"
|
||||
#include "ThirdParty/Kiss_FFT/kiss_fft129/tools/kiss_fftnd.h"
|
||||
|
||||
bool bNormalizeOutputToDb = false;
|
||||
bool bShowLogDebug = false;
|
||||
bool bShowWarningDebug = false;
|
||||
bool bShowErrorDebug = false;
|
||||
|
||||
// Log Category
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogRenderWave, Log, All);
|
||||
|
||||
// Short Defines to faster debug
|
||||
#define PrintLog(TextToLog) if(bShowLogDebug) UE_LOG(LogRenderWave, Log, TextToLog)
|
||||
#define PrintWarning(TextToLog) if(bShowWarningDebug) UE_LOG(LogRenderWave, Warning, TextToLog)
|
||||
#define PrintError(TextToLog) if(bShowErrorDebug) UE_LOG(LogRenderWave, Error, TextToLog)
|
||||
|
||||
#include "Sound/SoundWave.h"
|
||||
#include "AudioDevice.h"
|
||||
#include "Runtime/Engine/Public/VorbisAudioInfo.h"
|
||||
#include "Developer/TargetPlatform/Public/Interfaces/IAudioFormat.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogRenderWave);
|
||||
|
||||
float GetFFTInValue(const int16 InSampleValue, const int16 InSampleIndex, const int16 InSampleCount)
|
||||
{
|
||||
float FFTValue = InSampleValue;
|
||||
|
||||
// Apply the Hann window
|
||||
FFTValue *= 0.5f * (1 - FMath::Cos(2 * PI * InSampleIndex / (InSampleCount - 1)));
|
||||
|
||||
return FFTValue;
|
||||
}
|
||||
|
||||
void CalculateFrequencySpectrum(USoundWave* InSoundWaveRef, const float InStartTime, const float InDuration, TArray<float>& OutFrequencies)
|
||||
{
|
||||
// Clear the Array before continuing
|
||||
OutFrequencies.Empty();
|
||||
|
||||
const int32 NumChannels = InSoundWaveRef->NumChannels;
|
||||
const int32 SampleRate = InSoundWaveRef->SampleRate;
|
||||
|
||||
// Make sure the Number of Channels is correct
|
||||
if (NumChannels > 0 && NumChannels <= 2)
|
||||
{
|
||||
// Check if we actually have a Buffer to work with
|
||||
if (InSoundWaveRef->CachedRealtimeFirstBuffer)
|
||||
{
|
||||
// The first sample is just the StartTime * SampleRate
|
||||
int32 FirstSample = SampleRate * InStartTime;
|
||||
|
||||
// The last sample is the SampleRate times (StartTime plus the Duration)
|
||||
int32 LastSample = SampleRate * (InStartTime + InDuration);
|
||||
|
||||
// Get Maximum amount of samples in this Sound
|
||||
const int32 SampleCount = InSoundWaveRef->RawPCMDataSize / (2 * NumChannels);
|
||||
|
||||
// An early check if we can create a Sample window
|
||||
FirstSample = FMath::Min(SampleCount, FirstSample);
|
||||
LastSample = FMath::Min(SampleCount, LastSample);
|
||||
|
||||
// Actual amount of samples we gonna read
|
||||
int32 SamplesToRead = LastSample - FirstSample;
|
||||
|
||||
if (SamplesToRead < 0) {
|
||||
|
||||
PrintError(TEXT("Number of SamplesToRead is < 0!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Shift the window enough so that we get a PowerOfTwo. FFT works better with that
|
||||
int32 PoT = 2;
|
||||
|
||||
while (SamplesToRead > PoT) {
|
||||
PoT *= 2;
|
||||
}
|
||||
|
||||
// Now we have a good PowerOfTwo to work with
|
||||
SamplesToRead = PoT;
|
||||
|
||||
// Create two 2-dim Arrays for complex numbers | Buffer and Output
|
||||
kiss_fft_cpx* Buffer[2] = {0};
|
||||
kiss_fft_cpx* Output[2] = {0};
|
||||
|
||||
// Create 1-dim Array with one slot for SamplesToRead
|
||||
int32 Dims[1] = {SamplesToRead};
|
||||
|
||||
// alloc once and forget, should probably move to a init/deinit func
|
||||
static kiss_fftnd_cfg STF = kiss_fftnd_alloc(Dims, 1, 0, nullptr, nullptr);
|
||||
|
||||
int16* SamplePtr = reinterpret_cast<int16*>(InSoundWaveRef->CachedRealtimeFirstBuffer);
|
||||
|
||||
// Allocate space in the Buffer and Output Arrays for all the data that FFT returns
|
||||
for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ChannelIndex++)
|
||||
{
|
||||
Buffer[ChannelIndex] = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx) * SamplesToRead);
|
||||
Output[ChannelIndex] = (kiss_fft_cpx*)KISS_FFT_MALLOC(sizeof(kiss_fft_cpx) * SamplesToRead);
|
||||
}
|
||||
|
||||
// Shift our SamplePointer to the Current "FirstSample"
|
||||
SamplePtr += FirstSample * NumChannels;
|
||||
|
||||
float precomputeMultiplier = 2.f * PI / (SamplesToRead - 1);
|
||||
|
||||
for (int32 SampleIndex = 0; SampleIndex < SamplesToRead; SampleIndex++)
|
||||
{
|
||||
float rMult = 0.f;
|
||||
if (SamplePtr != NULL && (SampleIndex + FirstSample < SampleCount))
|
||||
{
|
||||
rMult = 0.5f * (1.f - FMath::Cos(precomputeMultiplier * SampleIndex));
|
||||
}
|
||||
for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ChannelIndex++)
|
||||
{
|
||||
// Make sure the Point is Valid and we don't go out of bounds
|
||||
if (SamplePtr != NULL && (SampleIndex + FirstSample < SampleCount))
|
||||
{
|
||||
// Use Window function to get a better result for the Data (Hann Window)
|
||||
Buffer[ChannelIndex][SampleIndex].r = rMult * (*SamplePtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer[ChannelIndex][SampleIndex].r = 0.f;
|
||||
}
|
||||
Buffer[ChannelIndex][SampleIndex].i = 0.f;
|
||||
|
||||
// Take the next Sample
|
||||
SamplePtr++;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the Buffer is filled, use the FFT
|
||||
for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ChannelIndex++)
|
||||
{
|
||||
if (Buffer[ChannelIndex])
|
||||
{
|
||||
kiss_fftnd(STF, Buffer[ChannelIndex], Output[ChannelIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
OutFrequencies.AddZeroed(SamplesToRead);
|
||||
|
||||
for (int32 SampleIndex = 0; SampleIndex < SamplesToRead; ++SampleIndex)
|
||||
{
|
||||
float ChannelSum = 0.0f;
|
||||
|
||||
for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
|
||||
{
|
||||
if (Output[ChannelIndex])
|
||||
{
|
||||
// With this we get the actual Frequency value for the frequencies from 0hz to ~22000hz
|
||||
ChannelSum += FMath::Sqrt(FMath::Square(Output[ChannelIndex][SampleIndex].r) + FMath::Square(Output[ChannelIndex][SampleIndex].i));
|
||||
}
|
||||
}
|
||||
|
||||
if (bNormalizeOutputToDb)
|
||||
{
|
||||
OutFrequencies[SampleIndex] = FMath::LogX(10, ChannelSum / NumChannels) * 10;
|
||||
} else
|
||||
{
|
||||
OutFrequencies[SampleIndex] = ChannelSum / NumChannels;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to free up the FFT stuff
|
||||
// KISS_FFT_FREE(STF);
|
||||
|
||||
for (int32 ChannelIndex = 0; ChannelIndex < NumChannels; ++ChannelIndex)
|
||||
{
|
||||
KISS_FFT_FREE(Buffer[ChannelIndex]);
|
||||
KISS_FFT_FREE(Output[ChannelIndex]);
|
||||
}
|
||||
} else {
|
||||
PrintError(TEXT("InSoundVisData.PCMData is a nullptr!"));
|
||||
}
|
||||
} else {
|
||||
PrintError(TEXT("Number of Channels is < 0!"));
|
||||
}
|
||||
}
|
||||
|
||||
void URenderWaveform::BP_RenderWaveform(USoundWave* InSoundWaveRef, UProceduralMeshComponent* Mesh, float InSongPosition, int SizeX){
|
||||
if (!IsValid(InSoundWaveRef)){
|
||||
return;
|
||||
}
|
||||
if (!IsValid(Mesh)){
|
||||
return;
|
||||
}
|
||||
|
||||
int nbVert = Mesh->GetProcMeshSection(0)->ProcVertexBuffer.Num();
|
||||
bool valid;
|
||||
|
||||
TArray<FVector> Vertices;
|
||||
TArray<FVector> Normals;
|
||||
TArray<FVector2D> UV0;
|
||||
TArray<FLinearColor> VertexColors;
|
||||
TArray<FProcMeshTangent> Tangents;
|
||||
|
||||
Vertices.AddDefaulted(nbVert);
|
||||
Normals.Init(FVector(0.0f, 0.0f, 1.0f), nbVert);
|
||||
UV0.AddDefaulted(nbVert);
|
||||
VertexColors.AddDefaulted(nbVert);
|
||||
Tangents.Init(FProcMeshTangent(1.0f, 0.0f, 0.0f), nbVert);
|
||||
|
||||
for (size_t i = 0; i < 320; ++i){
|
||||
float duration = (1 / 64.f);
|
||||
float startTime = duration * i + InSongPosition;
|
||||
|
||||
valid = true;
|
||||
if (startTime < 0.0f || startTime >= InSoundWaveRef->Duration || startTime + duration >= InSoundWaveRef->Duration) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
TArray<float> results;
|
||||
|
||||
if (valid) CalculateFrequencySpectrum(InSoundWaveRef, startTime, duration, results);
|
||||
|
||||
for (size_t j = 0; j < 64; ++j){
|
||||
float height;
|
||||
|
||||
if (valid) height = results[j * 8.f] / 50000.f;
|
||||
else height = 0;
|
||||
|
||||
Vertices[To1D(i, j, SizeX)] = FVector(i, j, height);
|
||||
VertexColors[To1D(i, j, SizeX)] = FLinearColor(height, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh->UpdateMeshSection_LinearColor(0, Vertices, Normals, UV0, VertexColors, Tangents);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void URenderWaveform::BP_GenerateSpectrogramMesh(UProceduralMeshComponent* Mesh, int SizeX, int SizeY)
|
||||
{
|
||||
if (!IsValid(Mesh) || SizeX <= 0 || SizeY <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<FVector> Vertices;
|
||||
TArray<int> Faces;
|
||||
TArray<FVector> Normals;
|
||||
TArray<FVector2D> UV0;
|
||||
TArray<FLinearColor> VertexColors;
|
||||
TArray<FProcMeshTangent> Tangents;
|
||||
|
||||
Vertices.AddDefaulted(SizeX * SizeY);
|
||||
Normals.AddDefaulted(SizeX * SizeY);
|
||||
UV0.AddDefaulted(SizeX * SizeY);
|
||||
VertexColors.AddDefaulted(SizeX * SizeY);
|
||||
Tangents.AddDefaulted(SizeX * SizeY);
|
||||
Faces.AddZeroed((SizeX - 1) * (SizeY - 1) * 6);
|
||||
|
||||
for (int j = 0; j < SizeY; ++j)
|
||||
{
|
||||
for (int i = 0; i < SizeX; ++i)
|
||||
{
|
||||
Vertices[To1D(i, j, SizeX)] = FVector(i,j, 0.0f);
|
||||
Normals[To1D(i, j, SizeX)] = FVector(0.0f, 0.0f, 1.0f);
|
||||
UV0[To1D(i, j, SizeX)] = FVector2D(0.0f, 0.0f);
|
||||
VertexColors[To1D(i, j, SizeX)] = FLinearColor(0.0f, 0.0f, 0.0f);
|
||||
Tangents[To1D(i, j, SizeX)] = FProcMeshTangent(1.0f, 0.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < SizeY - 1; ++j)
|
||||
{
|
||||
for (int i = 0; i < SizeX - 1; ++i)
|
||||
{
|
||||
Faces[To1D(i, j, SizeX - 1) * 6] = To1D(i, j, SizeX);
|
||||
Faces[To1D(i, j, SizeX - 1) * 6 + 1] = To1D(i, j + 1, SizeX);
|
||||
Faces[To1D(i, j, SizeX - 1) * 6 + 2] = To1D(i + 1, j, SizeX);
|
||||
|
||||
Faces[To1D(i, j, SizeX - 1) * 6 + 3] = To1D(i + 1, j, SizeX);
|
||||
Faces[To1D(i, j, SizeX - 1) * 6 + 4] = To1D(i, j + 1, SizeX);
|
||||
Faces[To1D(i, j, SizeX - 1) * 6 + 5] = To1D(i + 1, j + 1, SizeX);
|
||||
}
|
||||
}
|
||||
|
||||
Mesh->CreateMeshSection_LinearColor(0, Vertices, Faces, Normals, UV0, VertexColors, Tangents, false);
|
||||
}
|
||||
|
||||
int URenderWaveform::To1D(int x, int y, int sizeX)
|
||||
{
|
||||
return (sizeX * y) + x;
|
||||
}
|
||||
32
Source/MediocreMapper/RenderWaveform.h
Normal file
32
Source/MediocreMapper/RenderWaveform.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
|
||||
#include "Sound/SoundWave.h"
|
||||
#include "Engine/CanvasRenderTarget2D.h"
|
||||
#include "Engine/Canvas.h"
|
||||
#include "ProceduralMeshComponent.h"
|
||||
|
||||
#include "RenderWaveform.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class MEDIOCREMAPPER_API URenderWaveform : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Render Spectrogram"), Category = "Render Spectrogram")
|
||||
static void BP_RenderWaveform(USoundWave* InSoundWaveRef, UProceduralMeshComponent* Mesh, float InSongPosition, int SizeX);
|
||||
|
||||
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Generate Spectrogram Mesh"), Category = "Render Spectrogram")
|
||||
static void BP_GenerateSpectrogramMesh(UProceduralMeshComponent* Mesh, int SizeX, int SizeY);
|
||||
|
||||
private:
|
||||
static int To1D(int x, int y, int sizeX);
|
||||
};
|
||||
Reference in New Issue
Block a user