1 /**
2 * Copyright 2017 Cut Through Recordings
3 * License: MIT License
4 * Author(s): Ethan Reker
5 */
6 module ddsp.util.functions;
7 
8 import std.math;
9 import core.stdc.stdlib;
10 import std.conv : emplace;
11 import std.algorithm : clamp;
12 
13 /++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
14  + This is a collection of useful DSP related functions and algorithms.
15  + if you feel anything is missing, please feel free to add it.
16  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/
17 
18 /// Accepts a floating point value and returns its decibel equivalent.
19 /// `value` should be in the range of -1 to 1 and returns a float in the
20 /// range -96 to 0
21 float floatToDecibel(float value) nothrow @nogc
22 {
23     return 20 * log(value); 
24 }
25 
26 /// Accepts a decibel value and returns its floating point equivalent.
27 float decibelToFloat(float value) nothrow @nogc
28 {
29     return pow(10, value/20);
30 }
31 
32 /// Accepts a time in milliseconds and the sample rate
33 /// Returns the amount of samples that corresponds to the
34 /// time in milliseconds.
35 float msToSamples(float ms, float sampleRate) nothrow @nogc
36 {
37     return ms * (sampleRate / 1000);
38 }
39 
40 /// Accepts a number of samples and the sample rate.
41 /// Returns the corresponding time in milliseconds.
42 float samplesToMs(float samples, float sampleRate) nothrow @nogc
43 {
44     return samples / (1000 / sampleRate);
45 }
46 
47 /// Lagrange Interpolation
48 /// Accepts:
49 ///         arrX = an array of x coordinates.
50 ///         arrY = an array of y coordinates.
51 ///         order = the number of coordinates (size of arrX & arrY)
52 ///         input = the x coordinate whose corresponding y value will be found
53 /// Returns a y value along the curve that touches each (x,y) pair from arrX
54 /// and arrY.    The pair (input, sum) is a point on that curve.
55 float lagrpol(float[] arrX, float [] arrY, int order, float input) nothrow @nogc
56 {
57     float sum = 0;
58     for(int i = 0; i < order; ++i)
59     {
60         float Lg = 1.0f;
61         for(int j = 0; j < order; ++j)
62         {
63             if (i != j)
64                 Lg *= (input - arrX[j])/(arrX[i] - arrX[j]);
65         }
66         sum += Lg * arrY[i];
67     }
68     return sum;
69 }
70 
71 /// Linear Interpolation between two points.
72 /// (x1,y1) is the leftmost point and (x2,y2)
73 /// is the rightmost point. x is some number
74 /// between x1 and x2.
75 /// Returns the corresopnding y value for x
76 /// such that (x,y) is a point on the line
77 /// that intersects (x1,y1) and (x2,y2)
78 float linearInterp(float x1, float x2, float y1, float y2, float x) nothrow @nogc
79 {
80     return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
81 }
82 
83 /// sinc(x) aka the sampling function.
84 float sinc(float x)
85 {
86     if(x == 0)
87         return 1;
88     else
89         return sin(x) / x;
90 }
91 
92 unittest
93 {
94     import std.stdio;
95 
96     bool runTest = false;
97 
98     if(runTest)
99     {
100         float[] x = [1, 0.7079457844, 0.5011872336, 0.2511886432, 0.0630957344, 0.0039810717, 0.0000158489];
101         float[] y = [1, 0.833333333, 0.666666666, 0.5, 0.333333333, 0.166666666, 0];
102 
103         writefln("Functions test..");
104         writefln("x: %s", x);
105         writefln("y: %s", y);
106         for(int i = 0; i < 101; ++i)
107         {
108             writefln("Lagrange x = %s: %s",cast(float)i / 100, lagrpol(x, y, 2, cast(float)i/100));
109         }
110     }
111 }
112 
113 deprecated("Use std.math.round instead")
114 {
115     /// Simple nothrow @nogc method of rounding a float to an int
116     int roundToInt(float x) nothrow @nogc
117     {
118         return x - cast(int)x >= 0.5f ? (cast(int) x) + 1 : cast(int) x; 
119     }
120 }