2021-03-24 00:04:34 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MetasoundBPMToSecondsNode.h"
# include "Internationalization/Text.h"
# include "MetasoundExecutableOperator.h"
2023-08-02 14:38:51 -04:00
# include "MetasoundFrontendNodesCategories.h"
2021-03-24 00:04:34 -04:00
# include "MetasoundNodeRegistrationMacro.h"
2022-03-17 13:14:50 -04:00
# include "MetasoundParamHelper.h"
2021-03-24 00:04:34 -04:00
# include "MetasoundPrimitives.h"
# include "MetasoundStandardNodesNames.h"
# include "MetasoundTime.h"
2022-01-18 17:44:56 -05:00
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes"
2021-03-24 00:04:34 -04:00
namespace Metasound
{
namespace BPMToSecondsVertexNames
{
2022-03-17 13:14:50 -04:00
METASOUND_PARAM ( InputBPM , " BPM " , " Beats Per Minute. " )
METASOUND_PARAM ( InputBeatMultiplier , " Beat Multiplier " , " The multiplier of the BPM. " )
METASOUND_PARAM ( InputDivOfWholeNote , " Divisions of Whole Note " , " Divisions of a whole note. " )
METASOUND_PARAM ( OutputTimeSeconds , " Seconds " , " The output time in seconds. " )
2021-03-24 00:04:34 -04:00
}
class FBPMToSecondsOperator : public TExecutableOperator < FBPMToSecondsOperator >
{
public :
static const FNodeClassMetadata & GetNodeInfo ( ) ;
static const FVertexInterface & GetVertexInterface ( ) ;
static TUniquePtr < IOperator > CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors ) ;
2023-03-02 14:40:35 -05:00
FBPMToSecondsOperator ( const FCreateOperatorParams & InParams , const FFloatReadRef & InBPM , const FFloatReadRef & InBeatMultiplier , const FFloatReadRef & InDivOfWholeNote ) ;
2021-03-24 00:04:34 -04:00
2023-05-22 13:28:27 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override ;
virtual void BindOutputs ( FOutputVertexInterfaceData & InOutVertexData ) override ;
2021-03-24 00:04:34 -04:00
virtual FDataReferenceCollection GetInputs ( ) const override ;
virtual FDataReferenceCollection GetOutputs ( ) const override ;
2023-03-02 14:40:35 -05:00
void Reset ( const IOperator : : FResetParams & InParams ) ;
2021-03-24 00:04:34 -04:00
void Execute ( ) ;
private :
void UpdateTime ( ) ;
FFloatReadRef BPM ;
FFloatReadRef BeatMultiplier ;
FFloatReadRef DivOfWholeNote ;
// The output seconds
FTimeWriteRef TimeSeconds ;
// Cached midi note value. Used to catch if the value changes to recompute freq output.
float PrevBPM = - 1.0f ;
float PrevBeatMultiplier = - 1.0f ;
float PrevDivOfWholeNote = - 1.0f ;
2023-03-02 14:40:35 -05:00
static constexpr float MaxBPM = UE_MAX_FLT / 4 ;
static constexpr float MinBPM = 1.f ;
static constexpr float MaxBeatMultiplier = UE_MAX_FLT / 4 ;
static constexpr float MinBeatMultiplier = KINDA_SMALL_NUMBER ;
static constexpr float MaxDivOfWholeNote = UE_MAX_FLT / 4 ;
static constexpr float MinDivOfWholeNote = 1.f ;
2021-03-24 00:04:34 -04:00
} ;
2023-03-02 14:40:35 -05:00
FBPMToSecondsOperator : : FBPMToSecondsOperator ( const FCreateOperatorParams & InParams , const FFloatReadRef & InBPM , const FFloatReadRef & InBeatMultiplier , const FFloatReadRef & InDivOfWholeNote )
2021-03-24 00:04:34 -04:00
: BPM ( InBPM )
, BeatMultiplier ( InBeatMultiplier )
, DivOfWholeNote ( InDivOfWholeNote )
2023-03-02 14:40:35 -05:00
, TimeSeconds ( TDataWriteReferenceFactory < FTime > : : CreateExplicitArgs ( InParams . OperatorSettings ) )
2021-03-24 00:04:34 -04:00
{
2023-03-02 14:40:35 -05:00
Reset ( InParams ) ;
2021-03-24 00:04:34 -04:00
}
2023-05-22 13:28:27 -04:00
void FBPMToSecondsOperator : : BindInputs ( FInputVertexInterfaceData & InOutVertexData )
2021-03-24 00:04:34 -04:00
{
using namespace BPMToSecondsVertexNames ;
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputBPM ) , BPM ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputBeatMultiplier ) , BeatMultiplier ) ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputDivOfWholeNote ) , DivOfWholeNote ) ;
}
2021-03-24 00:04:34 -04:00
2023-05-22 13:28:27 -04:00
void FBPMToSecondsOperator : : BindOutputs ( FOutputVertexInterfaceData & InOutVertexData )
{
using namespace BPMToSecondsVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputTimeSeconds ) , TimeSeconds ) ;
}
FDataReferenceCollection FBPMToSecondsOperator : : GetInputs ( ) const
{
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
2021-03-24 00:04:34 -04:00
}
FDataReferenceCollection FBPMToSecondsOperator : : GetOutputs ( ) const
{
2023-05-22 13:28:27 -04:00
// This should never be called. Bind(...) is called instead. This method
// exists as a stop-gap until the API can be deprecated and removed.
checkNoEntry ( ) ;
return { } ;
2021-03-24 00:04:34 -04:00
}
void FBPMToSecondsOperator : : UpdateTime ( )
{
2023-03-02 14:40:35 -05:00
float CurrBPM = FMath : : Clamp ( * BPM , MinBPM , MaxBPM ) ;
float CurrBeatMultiplier = FMath : : Clamp ( * BeatMultiplier , MinBeatMultiplier , MaxBeatMultiplier ) ;
float CurrDivOfWholeNote = FMath : : Clamp ( * DivOfWholeNote , MinDivOfWholeNote , MaxDivOfWholeNote ) ;
2021-03-24 00:04:34 -04:00
if ( ! FMath : : IsNearlyEqual ( PrevBPM , CurrBPM ) | |
! FMath : : IsNearlyEqual ( PrevBeatMultiplier , CurrBeatMultiplier ) | |
! FMath : : IsNearlyEqual ( PrevDivOfWholeNote , CurrDivOfWholeNote ) )
{
PrevBPM = CurrBPM ;
PrevBeatMultiplier = CurrBeatMultiplier ;
PrevDivOfWholeNote = CurrDivOfWholeNote ;
check ( CurrBPM > 0.0f ) ;
check ( CurrDivOfWholeNote > 0.0f ) ;
const float QuarterNoteTime = 60.0f / CurrBPM ;
float NewTimeSeconds = 4.0f * ( float ) CurrBeatMultiplier * QuarterNoteTime / CurrDivOfWholeNote ;
* TimeSeconds = FTime ( NewTimeSeconds ) ;
}
}
2023-03-02 14:40:35 -05:00
void FBPMToSecondsOperator : : Reset ( const IOperator : : FResetParams & InParams )
{
UpdateTime ( ) ;
}
2021-03-24 00:04:34 -04:00
void FBPMToSecondsOperator : : Execute ( )
{
UpdateTime ( ) ;
}
const FVertexInterface & FBPMToSecondsOperator : : GetVertexInterface ( )
{
using namespace BPMToSecondsVertexNames ;
static const FVertexInterface Interface (
FInputVertexInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputBPM ) , 90.0f ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputBeatMultiplier ) , 1.0f ) ,
TInputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputDivOfWholeNote ) , 4.0f )
2021-03-24 00:04:34 -04:00
) ,
FOutputVertexInterface (
2022-03-31 16:49:59 -04:00
TOutputDataVertex < FTime > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputTimeSeconds ) )
2021-03-24 00:04:34 -04:00
)
) ;
return Interface ;
}
const FNodeClassMetadata & FBPMToSecondsOperator : : GetNodeInfo ( )
{
auto InitNodeInfo = [ ] ( ) - > FNodeClassMetadata
{
FNodeClassMetadata Info ;
2022-01-18 17:44:56 -05:00
Info . ClassName = { StandardNodes : : Namespace , " BPMToSeconds " , " " } ;
2021-03-24 00:04:34 -04:00
Info . MajorVersion = 1 ;
2022-01-18 17:44:56 -05:00
Info . MinorVersion = 1 ;
2022-02-10 18:36:47 -05:00
Info . DisplayName = METASOUND_LOCTEXT ( " BPMToSecondsNode_DisplayName " , " BPM To Seconds " ) ;
Info . Description = METASOUND_LOCTEXT ( " BPMToSecondsNode_Desc " , " Calculates a beat time in seconds from the given BPM, beat multiplier and divisions of a whole note. " ) ;
2021-03-24 00:04:34 -04:00
Info . Author = PluginAuthor ;
2023-08-02 14:38:51 -04:00
Info . CategoryHierarchy = { NodeCategories : : Conversions } ;
2021-03-24 00:04:34 -04:00
Info . PromptIfMissing = PluginNodeMissingPrompt ;
Info . DefaultInterface = GetVertexInterface ( ) ;
2022-08-17 16:42:56 -04:00
Info . Keywords = { METASOUND_LOCTEXT ( " BPMNodeRhythmKeyword " , " Rhythm " ) , METASOUND_LOCTEXT ( " BPMNodeTempoKeyword " , " Tempo " ) } ;
2021-03-24 00:04:34 -04:00
return Info ;
} ;
static const FNodeClassMetadata Info = InitNodeInfo ( ) ;
return Info ;
}
TUniquePtr < IOperator > FBPMToSecondsOperator : : CreateOperator ( const FCreateOperatorParams & InParams , FBuildErrorArray & OutErrors )
{
using namespace BPMToSecondsVertexNames ;
const FDataReferenceCollection & InputCollection = InParams . InputDataReferences ;
const FInputVertexInterface & InputInterface = GetVertexInterface ( ) . GetInputInterface ( ) ;
2022-03-17 13:14:50 -04:00
FFloatReadRef InBPM = InputCollection . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputBPM ) , InParams . OperatorSettings ) ;
FFloatReadRef InBeatMultiplier = InputCollection . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputBeatMultiplier ) , InParams . OperatorSettings ) ;
FFloatReadRef InDivOfWholeNote = InputCollection . GetDataReadReferenceOrConstructWithVertexDefault < float > ( InputInterface , METASOUND_GET_PARAM_NAME ( InputDivOfWholeNote ) , InParams . OperatorSettings ) ;
2021-03-24 00:04:34 -04:00
2023-03-02 14:40:35 -05:00
return MakeUnique < FBPMToSecondsOperator > ( InParams , InBPM , InBeatMultiplier , InDivOfWholeNote ) ;
2021-03-24 00:04:34 -04:00
}
FBPMToSecondsNode : : FBPMToSecondsNode ( const FNodeInitData & InitData )
: FNodeFacade ( InitData . InstanceName , InitData . InstanceID , TFacadeOperatorClass < FBPMToSecondsOperator > ( ) )
{
}
METASOUND_REGISTER_NODE ( FBPMToSecondsNode )
}
# undef LOCTEXT_NAMESPACE