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 }