2021-04-01 18:38:40 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "DSP/MidiNoteQuantizer.h"
# include "Math/NumericLimits.h"
namespace Audio
{
2023-05-25 18:45:39 -04:00
namespace Note
{
static const float B1 = 11.0f ;
static const float Bb1 = 10.0f ;
static const float A1 = 9.0f ;
static const float Ab1 = 8.0f ;
static const float G1 = 7.0f ;
static const float Gb1 = 6.0f ;
static const float F1 = 5.0f ;
static const float E1 = 4.0f ;
static const float Eb1 = 3.0f ;
static const float D1 = 2.0f ;
static const float Db1 = 1.0f ;
static const float C1 = 0.0f ;
}
2021-04-01 18:38:40 -04:00
ScaleDegreeSet : : ScaleDegreeSet ( const TArray < float > & InScaleDegrees , const TArray < float > & InChordTones )
: ScaleDegrees ( InScaleDegrees )
, ChordTones ( InChordTones )
{
}
TArrayView < float > ScaleDegreeSet : : GetScaleDegreeSet ( bool bChordTonesOnlyIfApplicable )
{
if ( bChordTonesOnlyIfApplicable & & ChordTones . Num ( ) )
{
return ChordTones ;
}
return ScaleDegrees ;
}
float FMidiNoteQuantizer : : QuantizeMidiNote ( const float InNote , const float InRoot , EMusicalScale : : Scale InScale , bool bChordTonesOnlyIfApplicable )
{
return QuantizeMidiNote ( InNote , InRoot , ScaleDegreeSetMap [ InScale ] . GetScaleDegreeSet ( bChordTonesOnlyIfApplicable ) ) ;
}
2023-05-25 18:45:39 -04:00
float FMidiNoteQuantizer : : QuantizeMidiNote ( const float InNote , const float InRoot , const TArrayView < float > InScaleDegrees , const float InSemitoneScaleRange )
2021-04-01 18:38:40 -04:00
{
2023-05-25 18:45:39 -04:00
// QuantizeValueToScaleDegree() works within a single octave, so map incoming note to within the first octave
2021-04-01 18:38:40 -04:00
const float NoteRootDelta = ( InNote - InRoot ) ;
2023-05-25 18:45:39 -04:00
const float ClampedSemitoneScaleRange = FMath : : Max ( InSemitoneScaleRange , 1.0f ) ;
const float InNoteOctave = FMath : : FloorToFloat ( NoteRootDelta / ClampedSemitoneScaleRange ) ;
const float ValueToQuant = NoteRootDelta - ( InSemitoneScaleRange * InNoteOctave ) ;
2021-04-01 18:38:40 -04:00
const float QuantizedValue = QuantizeValueToScaleDegree ( ValueToQuant , InScaleDegrees ) ;
2023-05-25 18:45:39 -04:00
// reconstruct the quantized midi note given the InRoot and original octave
return ( InSemitoneScaleRange * InNoteOctave + QuantizedValue ) + InRoot ;
2021-04-01 18:38:40 -04:00
}
2023-05-25 18:45:39 -04:00
float FMidiNoteQuantizer : : QuantizeValueToScaleDegree ( const float InValue , const TArrayView < float > InScaleDegrees , const float InSemitoneScaleRange )
2021-04-01 18:38:40 -04:00
{
// the Set we are quantizing to should have at least 2 elements
2023-05-25 18:45:39 -04:00
if ( ! InScaleDegrees . Num ( ) )
2021-04-01 18:38:40 -04:00
{
return InValue ;
}
2023-05-25 18:45:39 -04:00
// First check the min delta against the scale range
float QuantizedValue = InSemitoneScaleRange ;
float CurrMinDelta = FMath : : Abs ( InValue - InSemitoneScaleRange ) ;
2021-04-01 18:38:40 -04:00
2023-05-25 18:45:39 -04:00
// Then check the given scale degree array
2021-04-01 18:38:40 -04:00
for ( int32 i = 0 ; i < InScaleDegrees . Num ( ) ; + + i )
{
2023-05-25 18:45:39 -04:00
float NewDelta = FMath : : Abs ( InValue - InScaleDegrees [ i ] ) ;
if ( NewDelta < CurrMinDelta )
2021-04-01 18:38:40 -04:00
{
2023-05-25 18:45:39 -04:00
CurrMinDelta = NewDelta ;
QuantizedValue = InScaleDegrees [ i ] ;
2021-04-01 18:38:40 -04:00
}
}
2023-05-25 18:45:39 -04:00
return QuantizedValue ;
2021-04-01 18:38:40 -04:00
}
// Initialize our note & chord arrays
/* REQUIREMENTS:
* The ( optional ) second array defines Chord Tones , if empty , the first array will be used always
* - this is ideally a subset of the first array ( user - facing UI / UX will imply this ) , but does not technically need to be and is not enforced .
2023-05-25 18:45:39 -04:00
*
2021-04-01 18:38:40 -04:00
* The first array MUST have at least 1 entry or it will ensure .
2023-05-25 18:45:39 -04:00
*
2021-04-01 18:38:40 -04:00
* Both array MUST be in ascending order , or quantization behavior will be broken . This is not enforced at runtime and quantization and will not warn / ensure
2023-05-25 18:45:39 -04:00
*
2021-04-01 18:38:40 -04:00
* The Arrays must represent a full octave ( inclusive ) : the lowest element being ( 0.0 and the highest being 12.0 )
*/
TMap < EMusicalScale : : Scale , ScaleDegreeSet > FMidiNoteQuantizer : : ScaleDegreeSetMap {
/* entry example:
* { EMusicalScale : : Scale : : [ SCALE NAME ] ,
{ { [ ( required ) SCALE DEGREES ] } , { [ ( optional ) CHORD TONES ] } } }
*/
{ EMusicalScale : : Scale : : Major ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Dominant7th_Mixolydian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : A1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Minor_Dorian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : A1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : HalfDiminished_Locrian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : Eb1 , Note : : F1 , Note : : Gb1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : Gb1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Diminished ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : Gb1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : Gb1 , Note : : A1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : MajorPentatonic ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : G1 , Note : : A1 } , { Note : : C1 , Note : : E1 , Note : : G1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Lydian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : G1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Bebop_Major ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : G1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : HarmonicMajor ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : LydianAugmented ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : Ab1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Augmented ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : Eb1 , Note : : E1 , Note : : G1 , Note : : Ab1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : Ab1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : SixthModeOfHarmonicMinor ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Eb1 , Note : : E1 , Note : : Gb1 , Note : : G1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Diminished_BeginWithHalfStep ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : Eb1 , Note : : E1 , Note : : Gb1 , Note : : G1 , Note : : A1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Blues ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Eb1 , Note : : F1 , Note : : Gb1 , Note : : G1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Bebop_Dominant ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : A1 , Note : : Bb1 , Note : : B1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Spanish_or_Jewish ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : LydianDominant ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : G1 , Note : : A1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Hindu ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : WholeTone ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : E1 , Note : : Gb1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Chromatic ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : D1 , Note : : Eb1 , Note : : E1 , Note : : F1 , Note : : Gb1 , Note : : G1 , Note : : Ab1 , Note : : A1 , Note : : Bb1 , Note : : B1 } , { Note : : C1 , Note : : D1 , Note : : E1 , Note : : Gb1 , Note : : Ab1 , Note : : Bb1 /* Every other note */ } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : DiminishedWholeTone ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : Eb1 , Note : : E1 , Note : : Gb1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : Gb1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : MinorPentatonic ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Bebop_Minor ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : MelodicMinor ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Bebop_MinorNumber2 ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : HarmonicMinor ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Diminished_BeginWithWholeStep ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : Gb1 , Note : : Ab1 , Note : : A1 , Note : : B1 } , { Note : : C1 , Note : : Eb1 , Note : : Gb1 , Note : : B1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : Phrygian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : Db1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : NaturalMinor_Aeolian ,
2023-05-25 18:45:39 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : G1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : G1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
, { EMusicalScale : : Scale : : HalfDiminished_LocrianNumber2 ,
2023-08-01 15:07:40 -04:00
{ { Note : : C1 , Note : : D1 , Note : : Eb1 , Note : : F1 , Note : : Gb1 , Note : : Ab1 , Note : : Bb1 } , { Note : : C1 , Note : : Eb1 , Note : : Gb1 , Note : : Bb1 } } }
2021-04-01 18:38:40 -04:00
} ;
2023-03-02 14:40:35 -05:00
} // namespace Audio