2021-02-16 20:07:50 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "Internationalization/Text.h"
2021-03-25 00:13:33 -04:00
# include "MetasoundFacade.h"
2021-02-16 20:07:50 -04:00
# include "MetasoundExecutableOperator.h"
# include "MetasoundNodeRegistrationMacro.h"
# include "MetasoundPrimitives.h"
# include "MetasoundStandardNodesNames.h"
2021-04-01 18:38:40 -04:00
# include "MetasoundStandardNodesCategories.h"
2021-02-16 20:07:50 -04:00
# include "DSP/Dsp.h"
2021-03-25 00:13:33 -04:00
# include "MetasoundParamHelper.h"
2021-02-16 20:07:50 -04:00
2021-04-07 02:57:54 -04:00
# define LOCTEXT_NAMESPACE "MetasoundStandardNodes_MidiToFreqNode"
2021-02-16 20:07:50 -04:00
namespace Metasound
{
2021-03-25 00:13:33 -04:00
namespace MidiToFrequencyVertexNames
2021-03-18 08:38:58 -04:00
{
2021-03-25 00:13:33 -04:00
METASOUND_PARAM ( InputMidi , " MIDI In " , " A value representing a MIDI note value. " ) ;
METASOUND_PARAM ( OutputFreq , " Out Frequency " , " Output frequency value in hertz that corresponds to the input Midi note value. " ) ;
2021-03-18 08:38:58 -04:00
}
2021-02-16 20:07:50 -04:00
2021-03-25 00:13:33 -04:00
namespace MidiToFrequencyPrivate
{
template < typename ValueType >
struct TMidiToFreqNodeSpecialization
{
} ;
template < >
struct TMidiToFreqNodeSpecialization < int32 >
{
static int32 GetFreqValue ( int32 InMidi )
{
return Audio : : GetFrequencyFromMidi ( FMath : : Clamp ( InMidi , 0 , 127 ) ) ;
}
static bool IsValueEqual ( int32 InValueA , int32 InValueB )
{
return InValueA = = InValueB ;
}
} ;
template < >
struct TMidiToFreqNodeSpecialization < float >
{
static float GetFreqValue ( float InMidi )
{
return Audio : : GetFrequencyFromMidi ( FMath : : Clamp ( InMidi , 0.0f , 127.0f ) ) ;
}
static bool IsValueEqual ( float InValueA , float InValueB )
{
return FMath : : IsNearlyEqual ( InValueA , InValueB ) ;
}
} ;
}
template < typename ValueType >
class TMidiToFreqOperator : public TExecutableOperator < TMidiToFreqOperator < ValueType > >
2021-02-16 20:07:50 -04:00
{
public :
static const FNodeClassMetadata & GetNodeInfo ( ) ;
static const FVertexInterface & GetVertexInterface ( ) ;
2023-10-13 19:29:51 -04:00
static TUniquePtr < IOperator > CreateOperator ( const FBuildOperatorParams & InParams , FBuildResults & OutResults ) ;
2021-02-16 20:07:50 -04:00
2023-10-13 19:29:51 -04:00
TMidiToFreqOperator ( const FBuildOperatorParams & InParams , const TDataReadReference < ValueType > & InMidiNote ) ;
2021-02-16 20:07:50 -04:00
2023-05-22 13:28:27 -04:00
virtual void BindInputs ( FInputVertexInterfaceData & InOutVertexData ) override ;
virtual void BindOutputs ( FOutputVertexInterfaceData & InOutVertexData ) override ;
2021-02-16 20:07:50 -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-02-16 20:07:50 -04:00
void Execute ( ) ;
private :
2021-03-25 00:13:33 -04:00
// The input Midi value
TDataReadReference < ValueType > MidiNote ;
2021-02-16 20:07:50 -04:00
// The output frequency
FFloatWriteRef FreqOutput ;
2021-03-25 00:13:33 -04:00
// Cached Midi note value. Used to catch if the value changes to recompute freq output.
ValueType PrevMidiNote ;
2021-02-16 20:07:50 -04:00
} ;
2021-03-25 00:13:33 -04:00
template < typename ValueType >
2023-10-13 19:29:51 -04:00
TMidiToFreqOperator < ValueType > : : TMidiToFreqOperator ( const FBuildOperatorParams & InParams , const TDataReadReference < ValueType > & InMidiNote )
2021-03-25 00:13:33 -04:00
: MidiNote ( InMidiNote )
, FreqOutput ( FFloatWriteRef : : CreateNew ( Audio : : GetFrequencyFromMidi ( * InMidiNote ) ) )
, PrevMidiNote ( * InMidiNote )
2021-02-16 20:07:50 -04:00
{
2023-03-02 14:40:35 -05:00
Reset ( InParams ) ;
2021-02-16 20:07:50 -04:00
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
2023-05-22 13:28:27 -04:00
void TMidiToFreqOperator < ValueType > : : BindInputs ( FInputVertexInterfaceData & InOutVertexData )
2021-02-16 20:07:50 -04:00
{
2021-03-25 00:13:33 -04:00
using namespace MidiToFrequencyVertexNames ;
2021-03-18 08:38:58 -04:00
2023-05-22 13:28:27 -04:00
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( InputMidi ) , MidiNote ) ;
}
2021-02-16 20:07:50 -04:00
2023-05-22 13:28:27 -04:00
template < typename ValueType >
void TMidiToFreqOperator < ValueType > : : BindOutputs ( FOutputVertexInterfaceData & InOutVertexData )
{
using namespace MidiToFrequencyVertexNames ;
InOutVertexData . BindReadVertex ( METASOUND_GET_PARAM_NAME ( OutputFreq ) , FreqOutput ) ;
}
template < typename ValueType >
FDataReferenceCollection TMidiToFreqOperator < ValueType > : : 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-02-16 20:07:50 -04:00
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
FDataReferenceCollection TMidiToFreqOperator < ValueType > : : GetOutputs ( ) const
2021-02-16 20:07:50 -04:00
{
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-02-16 20:07:50 -04:00
}
2023-03-02 14:40:35 -05:00
template < typename ValueType >
void TMidiToFreqOperator < ValueType > : : Reset ( const IOperator : : FResetParams & InParams )
{
using namespace MidiToFrequencyPrivate ;
PrevMidiNote = * MidiNote ;
* FreqOutput = TMidiToFreqNodeSpecialization < ValueType > : : GetFreqValue ( PrevMidiNote ) ;
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
void TMidiToFreqOperator < ValueType > : : Execute ( )
2021-02-16 20:07:50 -04:00
{
2021-03-25 00:13:33 -04:00
using namespace MidiToFrequencyPrivate ;
2021-02-16 20:07:50 -04:00
2021-03-25 00:13:33 -04:00
// Only do anything if the Midi note changes
if ( ! TMidiToFreqNodeSpecialization < ValueType > : : IsValueEqual ( * MidiNote , PrevMidiNote ) )
{
PrevMidiNote = * MidiNote ;
* FreqOutput = TMidiToFreqNodeSpecialization < ValueType > : : GetFreqValue ( PrevMidiNote ) ;
2021-02-16 20:07:50 -04:00
}
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
const FVertexInterface & TMidiToFreqOperator < ValueType > : : GetVertexInterface ( )
2021-02-16 20:07:50 -04:00
{
2021-03-25 00:13:33 -04:00
using namespace MidiToFrequencyVertexNames ;
2021-03-18 08:38:58 -04:00
2021-02-16 20:07:50 -04:00
static const FVertexInterface Interface (
FInputVertexInterface (
2022-03-31 16:49:59 -04:00
TInputDataVertex < ValueType > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( InputMidi ) , ( ValueType ) 60.0f )
2021-02-16 20:07:50 -04:00
) ,
FOutputVertexInterface (
2022-03-31 16:49:59 -04:00
TOutputDataVertex < float > ( METASOUND_GET_PARAM_NAME_AND_METADATA ( OutputFreq ) )
2021-02-16 20:07:50 -04:00
)
) ;
return Interface ;
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
const FNodeClassMetadata & TMidiToFreqOperator < ValueType > : : GetNodeInfo ( )
2021-02-16 20:07:50 -04:00
{
auto InitNodeInfo = [ ] ( ) - > FNodeClassMetadata
{
2021-05-10 16:56:43 -04:00
const FName DataTypeName = GetMetasoundDataTypeName < ValueType > ( ) ;
const FName OperatorName = TEXT ( " MIDI To Frequency " ) ;
2022-02-10 18:36:47 -05:00
const FText NodeDisplayName = METASOUND_LOCTEXT_FORMAT ( " RandomGetArrayOpDisplayNamePattern " , " MIDI To Frequency ({0}) " , GetMetasoundDataTypeDisplayText < ValueType > ( ) ) ;
const FText NodeDescription = METASOUND_LOCTEXT ( " Metasound_MidiToFreqNodeDescription " , " Converts a Midi note value to a frequency (hz) value. " ) ;
2021-03-25 00:13:33 -04:00
2021-02-16 20:07:50 -04:00
FNodeClassMetadata Info ;
2021-08-09 15:08:37 -04:00
Info . ClassName = { StandardNodes : : Namespace , OperatorName , DataTypeName } ;
2021-02-16 20:07:50 -04:00
Info . MajorVersion = 1 ;
Info . MinorVersion = 0 ;
2021-03-25 00:13:33 -04:00
Info . DisplayName = NodeDisplayName ;
Info . Description = NodeDescription ;
2021-02-16 20:07:50 -04:00
Info . Author = PluginAuthor ;
Info . PromptIfMissing = PluginNodeMissingPrompt ;
Info . DefaultInterface = GetVertexInterface ( ) ;
2021-08-09 15:08:37 -04:00
Info . CategoryHierarchy . Emplace ( NodeCategories : : Music ) ;
2022-08-17 16:42:56 -04:00
Info . Keywords . Add ( METASOUND_LOCTEXT ( " MIDIToFreqPitchKeyword " , " Pitch " ) ) ;
2021-02-16 20:07:50 -04:00
return Info ;
} ;
static const FNodeClassMetadata Info = InitNodeInfo ( ) ;
return Info ;
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
2023-10-13 19:29:51 -04:00
TUniquePtr < IOperator > TMidiToFreqOperator < ValueType > : : CreateOperator ( const FBuildOperatorParams & InParams , FBuildResults & OutResults )
2021-02-16 20:07:50 -04:00
{
2021-03-25 00:13:33 -04:00
using namespace MidiToFrequencyVertexNames ;
2023-10-13 19:29:51 -04:00
const FInputVertexInterfaceData & InputData = InParams . InputData ;
2021-03-18 08:38:58 -04:00
2023-10-13 19:29:51 -04:00
TDataReadReference < ValueType > InMidiNote = InputData . GetOrCreateDefaultDataReadReference < ValueType > ( METASOUND_GET_PARAM_NAME ( InputMidi ) , InParams . OperatorSettings ) ;
2021-02-16 20:07:50 -04:00
2023-03-02 14:40:35 -05:00
return MakeUnique < TMidiToFreqOperator > ( InParams , InMidiNote ) ;
2021-02-16 20:07:50 -04:00
}
2021-03-25 00:13:33 -04:00
template < typename ValueType >
class METASOUNDSTANDARDNODES_API TMidiToFreqNode : public FNodeFacade
2021-02-16 20:07:50 -04:00
{
2021-03-25 00:13:33 -04:00
public :
/**
* Constructor used by the Metasound Frontend .
*/
TMidiToFreqNode ( const FNodeInitData & InitData )
: FNodeFacade ( InitData . InstanceName , InitData . InstanceID , TFacadeOperatorClass < TMidiToFreqOperator < ValueType > > ( ) )
{
2021-02-16 20:07:50 -04:00
2021-03-25 00:13:33 -04:00
}
} ;
using FMidiToFreqNodeInt32 = TMidiToFreqNode < int32 > ;
METASOUND_REGISTER_NODE ( FMidiToFreqNodeInt32 )
using FMidiToFreqNodeFloat = TMidiToFreqNode < float > ;
METASOUND_REGISTER_NODE ( FMidiToFreqNodeFloat )
2021-02-16 20:07:50 -04:00
}
# undef LOCTEXT_NAMESPACE