using Godot; using System.Reflection; using System.Collections.Generic; using System.Text; namespace Rokojori { public class WaveTable:iPhaseGenerator { float[] _samples; public float[] samples => _samples; public void SetPitchRange( float minPitch, float maxPitch ) { } public float Get( float phase ) { var samplePosition = phase * _samples.Length; samplePosition = MathX.Repeat( samplePosition, _samples.Length ); var l = (int) samplePosition; var h = MathX.Repeat( l + 1, _samples.Length ); var lerp = samplePosition - l; return Mathf.Lerp( _samples[ l ], _samples[ h ], lerp ); } public static WaveTable FromSamples( float[] samples ) { var wt = new WaveTable(); wt._samples = samples; return wt; } public void Normalize() { var max = 0f; for ( int i = 0; i < _samples.Length; i++ ) { max = Mathf.Max( Mathf.Abs( _samples[ i ] ), max ); } for ( int i = 0; i < _samples.Length; i++ ) { _samples[ i ] = _samples[ i ] / max; } } public static WaveTable FromSines( Vector2[] magnitudesAndPhases, float filterStart = -1, float filterEnd = -1, int size = 4096 ) { var fftReal = new float[ size ]; var fftImaginary = new float[ size ]; var hasNoFilter = ( filterStart == -1 && filterEnd == -1 ); for ( int i = 0; i < magnitudesAndPhases.Length; i++ ) { var filter = hasNoFilter ? 1 : ( 1f - MathX.NormalizeClamped( i, filterStart, filterEnd ) ); fftReal[ i ] = Mathf.Cos( magnitudesAndPhases[ i ].Y ) * magnitudesAndPhases[ i ].X * filter; fftImaginary[ i ] = Mathf.Sin( magnitudesAndPhases[ i ].Y ) * magnitudesAndPhases[ i ].X * filter; } FFT.Inverse( size, fftReal, fftImaginary ); return FromSamples( fftReal ); } } }