1 /** 2 * Copyright: Copyright Auburn Sounds 2015 and later. 3 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 4 * Authors: Guillaume Piolat 5 */ 6 module dplug.dsp.window; 7 8 import std.math; 9 10 import dplug.core.alignedbuffer; 11 12 // Useful reference: 13 // https://en.wikipedia.org/wiki/Window_function 14 15 16 enum WindowType 17 { 18 RECT, 19 BARTLETT, 20 HANN, 21 HAMMING, 22 NUTTALL, 23 BLACKMANN_NUTTALL, 24 BLACKMANN_HARRIS, 25 FLATTOP_SR785, // Flat top window 26 KAISER_BESSEL, // Kaiser-Bessel window, this one need a parameter alpha (typical values: 1.0 to 4.0) 27 } 28 29 struct WindowDesc 30 { 31 WindowType type; 32 float param; 33 } 34 35 void generateWindow(T)(WindowDesc desc, T[] output) pure nothrow @nogc 36 { 37 int N = cast(int)(output.length); 38 for (int i = 0; i < N; ++i) 39 { 40 output[i] = cast(T)(evalWindow(desc, i, N)); 41 } 42 } 43 44 void generateNormalizedWindow(T)(WindowDesc desc, T[] output) pure nothrow @nogc 45 { 46 int N = cast(int)(output.length); 47 T sum = 0; 48 for (int i = 0; i < N; ++i) 49 { 50 output[i] = cast(T)(evalWindow(desc, i, N)); 51 sum += output[i]; 52 } 53 T invSum = 1 / sum; 54 for (int i = 0; i < N; ++i) 55 output[i] *= invSum; 56 } 57 58 deprecated("This function disappeared.") double secondaryLobeAttenuationInDb(WindowType type) pure nothrow @nogc 59 { 60 return double.nan; 61 } 62 63 double evalWindow(WindowDesc desc, int n, int N) pure nothrow @nogc 64 { 65 static double computeKaiserFunction(double alpha, int n, int N) pure nothrow @nogc 66 { 67 static double I0(double x) pure nothrow @nogc 68 { 69 double sum = 1; 70 double mx = x * 0.5; 71 double denom = 1; 72 double numer = 1; 73 for (int m = 1; m <= 32; m++) 74 { 75 numer *= mx; 76 denom *= m; 77 double term = numer / denom; 78 sum += term * term; 79 } 80 return sum; 81 } 82 83 double piAlpha = PI * alpha; 84 double C = 2.0 * n / (N - 1.0) - 1.0; 85 double result = I0(piAlpha * sqrt(1.0 - C * C)) / I0(piAlpha); 86 return result; 87 } 88 89 final switch(desc.type) 90 { 91 case WindowType.RECT: 92 return 1.0; 93 94 case WindowType.BARTLETT: 95 { 96 double nm1 = (N - 1.0)/2; 97 return 1 - abs(n - nm1) / nm1; 98 } 99 100 case WindowType.HANN: 101 { 102 double phi = (2 * PI * n ) / (N - 1); 103 return 0.5 - 0.5 * cos(phi); 104 } 105 106 case WindowType.HAMMING: 107 { 108 double phi = (2 * PI * n ) / (N - 1); 109 return 0.54 - 0.46 * cos(phi); 110 } 111 112 case WindowType.NUTTALL: 113 { 114 double phi = (2 * PI * n ) / (N - 1); 115 return 0.355768 - 0.487396 * cos(phi) + 0.144232 * cos(2 * phi) - 0.012604 * cos(3 * phi); 116 } 117 118 case WindowType.BLACKMANN_HARRIS: 119 { 120 double phi = (2 * PI * n ) / (N - 1); 121 return 0.35875 - 0.48829 * cos(phi) + 0.14128 * cos(2 * phi) - 0.01168 * cos(3 * phi); 122 } 123 124 case WindowType.BLACKMANN_NUTTALL: 125 { 126 double phi = (2 * PI * n ) / (N - 1); 127 return 0.3635819 - 0.4891775 * cos(phi) + 0.1365995 * cos(2 * phi) - 0.0106411 * cos(3 * phi); 128 } 129 130 case WindowType.FLATTOP_SR785: 131 { 132 double phi = (2 * PI * n ) / (N - 1); 133 return 1 - 1.93 * cos(phi) + 1.29 * cos(2 * phi) - 0.388 * cos(3 * phi) + 0.028 * cos(4 * phi); 134 } 135 136 case WindowType.KAISER_BESSEL: 137 return computeKaiserFunction(desc.param, n, N); 138 } 139 } 140 141 struct Window(T) if (is(T == float) || is(T == double)) 142 { 143 void initialize(WindowDesc desc, int lengthInSamples) nothrow @nogc 144 { 145 _lengthInSamples = lengthInSamples; 146 _window.reallocBuffer(lengthInSamples); 147 generateWindow!T(desc, _window); 148 } 149 150 ~this() nothrow @nogc 151 { 152 _window.reallocBuffer(0); 153 } 154 155 double sumOfWindowSamples() pure const nothrow @nogc 156 { 157 double result = 0; 158 foreach(windowValue; _window) 159 result += windowValue; 160 return result; 161 } 162 163 @disable this(this); 164 165 T[] _window = null; 166 int _lengthInSamples; 167 alias _window this; 168 }