mirror of
https://github.com/FunkinCrew/Funkin.git
synced 2024-11-30 11:26:53 -05:00
110 lines
2.6 KiB
Haxe
110 lines
2.6 KiB
Haxe
package dsp;
|
|
|
|
using Lambda;
|
|
|
|
|
|
/**
|
|
Signal processing miscellaneous utilities.
|
|
**/
|
|
class Signal {
|
|
/**
|
|
Returns a smoothed version of the input array using a moving average.
|
|
**/
|
|
public static function smooth(y:Array<Float>, n:Int) : Array<Float> {
|
|
if (n <= 0) {
|
|
return null;
|
|
} else if (n == 1) {
|
|
return y.copy();
|
|
} else {
|
|
var smoothed = new Array<Float>();
|
|
smoothed.resize(y.length);
|
|
for (i in 0...y.length) {
|
|
var m = i + 1 < n ? i : n - 1;
|
|
smoothed[i] = sum(y.slice(i - m, i + 1));
|
|
}
|
|
return smoothed;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Finds indexes of peaks in the order they appear in the input sequence.
|
|
|
|
@param threshold Minimal peak height wrt. its neighbours, defaults to 0.
|
|
@param minHeight Minimal peak height wrt. the whole input, defaults to global minimum.
|
|
**/
|
|
public static function findPeaks(
|
|
y:Array<Float>,
|
|
?threshold:Float,
|
|
?minHeight:Float
|
|
) : Array<Int> {
|
|
threshold = threshold == null ? 0.0 : Math.abs(threshold);
|
|
minHeight = minHeight == null ? Signal.min(y) : minHeight;
|
|
|
|
var peaks = new Array<Int>();
|
|
|
|
final dy = [for (i in 1...y.length) y[i] - y[i-1]];
|
|
for (i in 1...dy.length) {
|
|
// peak: function growth positive to its left and negative to its right
|
|
if (
|
|
dy[i-1] > threshold && dy[i] < -threshold &&
|
|
y[i] > minHeight
|
|
) {
|
|
peaks.push(i);
|
|
}
|
|
}
|
|
|
|
return peaks;
|
|
}
|
|
|
|
/**
|
|
Returns the sum of all the elements of a given array.
|
|
|
|
This function tries to minimize floating-point precision errors.
|
|
**/
|
|
public static function sum(array:Array<Float>) : Float {
|
|
// Neumaier's "improved Kahan-Babuska algorithm":
|
|
|
|
var sum = 0.0;
|
|
var c = 0.0; // running compensation for lost precision
|
|
|
|
for (v in array) {
|
|
var t = sum + v;
|
|
c += Math.abs(sum) >= Math.abs(v)
|
|
? (sum - t) + v // sum is bigger => low-order digits of v are lost
|
|
: (v - t) + sum; // v is bigger => low-order digits of sum are lost
|
|
sum = t;
|
|
}
|
|
|
|
return sum + c; // correction only applied at the very end
|
|
}
|
|
|
|
/**
|
|
Returns the average value of an array.
|
|
**/
|
|
public static function mean(y:Array<Float>) : Float
|
|
return sum(y) / y.length;
|
|
|
|
/**
|
|
Returns the global maximum.
|
|
**/
|
|
public static function max(y:Array<Float>) : Float
|
|
return y.fold(Math.max, y[0]);
|
|
|
|
/**
|
|
Returns the global maximum's index.
|
|
**/
|
|
public static function maxi(y:Array<Float>) : Int
|
|
return y.foldi((yi, m, i) -> yi > y[m] ? i : m, 0);
|
|
|
|
/**
|
|
Returns the global minimum.
|
|
**/
|
|
public static function min(y:Array<Float>) : Float
|
|
return y.fold(Math.min, y[0]);
|
|
|
|
/**
|
|
Returns the global minimum's index.
|
|
**/
|
|
public static function mini(y:Array<Float>) : Int
|
|
return y.foldi((yi, m, i) -> yi < y[m] ? i : m, 0);
|
|
}
|