1 module pixelperfectengine.audio.base.func; 2 3 /* 4 * Copyright (C) 2015-2021, by Laszlo Szeremi under the Boost license. 5 * 6 * Pixel Perfect Engine, audio.base.func module. 7 * 8 * Contains common audio functions for mixing, codecs, etc. 9 */ 10 11 import inteli.emmintrin; 12 import bitleveld.reinterpret; 13 import bitleveld.datatypes; 14 15 import std.math; 16 17 18 public import pixelperfectengine.audio.base.types; 19 import pixelperfectengine.system.etc; 20 21 ///Constant for fast integer to floating point conversion 22 package immutable __m128 CONV_RATIO_RECIPROCAL = __m128(-1.0 / ushort.min); 23 ///For IMA ADPCM 24 ///Needs less storage at the cost of worse quality 25 package static immutable byte[4] ADPCM_INDEX_TABLE_2BIT = 26 [-1, 2, 27 -1, 2]; 28 ///For IMA ADPCM 29 ///Needs less storage at the cost of worse quality 30 package static immutable byte[8] ADPCM_INDEX_TABLE_3BIT = 31 [-1, -1, 2, 4, 32 -1, -1, 2, 4,]; 33 ///For IMA and Dialogic ADPCM 34 ///Standard quality and size 35 package static immutable byte[16] ADPCM_INDEX_TABLE_4BIT = 36 [-1, -1, -1, -1, 2, 4, 6, 8, 37 -1, -1, -1, -1, 2, 4, 6, 8]; 38 ///For IMA ADPCM 39 ///Better quality, but needs more storage 40 package static immutable byte[32] ADPCM_INDEX_TABLE_5BIT = 41 [-1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 42 -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16]; 43 ///For the Yamaha ADPCM A found in YM2610 and probably other chips 44 package static immutable byte[16] Y_ADPCM_INDEX_TABLE = 45 [-1, -1, -1, -1, 2, 5, 7, 9, 46 -1, -1, -1, -1, 2, 5, 7, 9]; 47 ///Most OKI and Yamaha chips seems to use this step-table 48 package static immutable ushort[49] DIALOGIC_ADPCM_STEP_TABLE = 49 [16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 50 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 51 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 52 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552]; 53 /** 54 * Used by IMA ADPCM and its derivatives. 55 */ 56 package static immutable ushort[89] IMA_ADPCM_STEP_TABLE = 57 [7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 58 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 59 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 60 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 61 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 62 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 63 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 64 5894, 6484, 7132, 7845, 8630, 9493, 10_442, 11_487, 12_635, 13_899, 65 15_289, 16_818, 18_500, 20_350, 22_385, 24_623, 27_086, 29_794, 32_767]; 66 /** 67 * Used for decoding Mu-Law encoded PCM samples 68 */ 69 package static immutable short[256] MU_LAW_DECODER_TABLE = 70 [-32_124,-31_100,-30_076,-29_052,-28_028,-27_004,-25_980,-24_956, 71 -23_932,-22_908,-21_884,-20_860,-19_836,-18_812,-17_788,-16_764, 72 -15_996,-15_484,-14_972,-14_460,-13_948,-13_436,-12_924,-12_412, 73 -11_900,-11_388,-10_876,-10_364, -9852, -9340, -8828, -8316, 74 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, 75 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, 76 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, 77 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, 78 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, 79 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, 80 -876, -844, -812, -780, -748, -716, -684, -652, 81 -620, -588, -556, -524, -492, -460, -428, -396, 82 -372, -356, -340, -324, -308, -292, -276, -260, 83 -244, -228, -212, -196, -180, -164, -148, -132, 84 -120, -112, -104, -96, -88, -80, -72, -64, 85 -56, -48, -40, -32, -24, -16, -8, -1, 86 32_124, 31_100, 30_076, 29_052, 28_028, 27_004, 25_980, 24_956, 87 23_932, 22_908, 21_884, 20_860, 19_836, 18_812, 17_788, 16_764, 88 15_996, 15_484, 14_972, 14_460, 13_948, 13_436, 12_924, 12_412, 89 11_900, 11_388, 10_876, 10_364, 9852, 9340, 8828, 8316, 90 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, 91 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 92 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, 93 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 94 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, 95 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 96 876, 844, 812, 780, 748, 716, 684, 652, 97 620, 588, 556, 524, 492, 460, 428, 396, 98 372, 356, 340, 324, 308, 292, 276, 260, 99 244, 228, 212, 196, 180, 164, 148, 132, 100 120, 112, 104, 96, 88, 80, 72, 64, 101 56, 48, 40, 32, 24, 16, 8, 0]; 102 /** 103 * Used for decoding A-Law encoded PCM streams. 104 */ 105 package static immutable short[256] A_LAW_DECODER_TABLE = 106 [-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, 107 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, 108 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, 109 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, 110 -22_016,-20_992,-24_064,-23_040,-17_920,-16_896,-19_968,-18_944, 111 -30_208,-29_184,-32_256,-31_232,-26_112,-25_088,-28_160,-27_136, 112 -11_008,-10_496,-12_032,-11_520,-8960, -8448, -9984, -9472, 113 -15_104,-14_592,-16_128,-15_616,-13_056,-12_544,-14_080,-13_568, 114 -344, -328, -376, -360, -280, -264, -312, -296, 115 -472, -456, -504, -488, -408, -392, -440, -424, 116 -88, -72, -120, -104, -24, -8, -56, -40, 117 -216, -200, -248, -232, -152, -136, -184, -168, 118 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, 119 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, 120 -688, -656, -752, -720, -560, -528, -624, -592, 121 -944, -912, -1008, -976, -816, -784, -880, -848, 122 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 123 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 124 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, 125 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 126 22_016, 20_992, 24_064, 23_040, 17_920, 16_896, 19_968, 18_944, 127 30_208, 29_184, 32_256, 31_232, 26_112, 25_088, 28_160, 27_136, 128 11_008, 10_496, 12_032, 11_520, 8960, 8448, 9984, 9472, 129 15_104, 14_592, 16_128, 15_616, 13_056, 12_544, 14_080, 13_568, 130 344, 328, 376, 360, 280, 264, 312, 296, 131 472, 456, 504, 488, 408, 392, 440, 424, 132 88, 72, 120, 104, 24, 8, 56, 40, 133 216, 200, 248, 232, 152, 136, 184, 168, 134 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, 135 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 136 688, 656, 752, 720, 560, 528, 624, 592, 137 944, 912, 1008, 976, 816, 784, 880, 848]; 138 139 alias ADPCMStream = NibbleArray; 140 141 142 @nogc nothrow pure: 143 144 /** 145 * Mixes an audio stream to the destination. 146 */ 147 public void mixIntoStream(size_t length, float* src, float* dest, float amount = 1.0, float corr = 0.5) { 148 const __m128 amountV = __m128(amount); 149 const __m128 corrV = __m128(corr); 150 while (length) { 151 const __m128 srcV = _mm_load_ps(src); 152 __m128 destV = _mm_load_ps(dest); 153 destV += srcV * amountV; 154 destV *= corrV; 155 _mm_store_ps(dest, destV); 156 length -= 4; 157 src += 4; 158 dest += 4; 159 } 160 } 161 /** 162 * Interleaves two channels. 163 * `dest` must be as big as the length of `srcL` and `srcR`. 164 */ 165 public void interleave(size_t length, float* srcL, float* srcR, float* dest) { 166 while (length) { 167 dest[0] = *srcL; 168 dest[1] = *srcR; 169 dest += 2; 170 srcL++; 171 srcR++; 172 length--; 173 } 174 } 175 /** 176 * Converts a 32 bit extended integer stream to 32 bit floating point. 177 */ 178 public void convExIntToFlt(size_t length, int* src, float* dest) { 179 while (length) { 180 _mm_store_ps(dest, _mm_cvtepi32_ps(_mm_load_si128(cast(__m128i*)src)) * CONV_RATIO_RECIPROCAL); 181 length -= 4; 182 src += 4; 183 dest += 4; 184 } 185 } 186 /** 187 * Decodes an amount of 8 bit unsigned PCM to extended 32 bit. 188 * Amount is decided by dest.length. `src` is a full waveform. Position is stored in wp.pos. 189 */ 190 public void decode8bitPCM(const(ubyte)[] src, int[] dest, ref DecoderWorkpad wp) @safe { 191 for (size_t i ; i < dest.length ; i++) { 192 const ubyte val = src[wp.pos + i]; 193 dest[i] = ((val) | (val<<8)) + short.min; 194 } 195 wp.pos += dest.length; 196 } 197 /** 198 * Decodes an amount of 16 bit signed PCM to extended 32 bit. 199 * Amount is decided by dest.length. `src` is a full waveform. Position is stored in wp.pos. 200 */ 201 public void decode16bitPCM(const(short)[] src, int[] dest, ref DecoderWorkpad wp) @safe { 202 for (size_t i ; i < dest.length ; i++) { 203 dest[i] = src[wp.pos + i]; 204 } 205 wp.pos += dest.length; 206 } 207 /** 208 * Decodes an amount of 4 bit IMA ADPCM stream to extended 32 bit. 209 * Amount is decided by dest.length. `src` is a full waveform. Position is stored in wp.pos. 210 */ 211 public void decode4bitIMAADPCM(ADPCMStream src, int[] dest, ref DecoderWorkpad wp) @safe { 212 for (size_t i ; i < dest.length ; i++) { 213 const ubyte index = src[i]; 214 uint stepSize; 215 int d_n; 216 wp.pred += ADPCM_INDEX_TABLE_4BIT[index]; 217 clamp(wp.pred, 0, 88); 218 stepSize = IMA_ADPCM_STEP_TABLE[wp.pred]; 219 d_n = ((stepSize) * (index & 0b0100)>>2) + ((stepSize>>1) * (index & 0b0010)>>1) + ((stepSize>>2) * index & 0b0001) 220 + (stepSize>>3); 221 if(index & 0b1000) 222 d_n *= -1; 223 d_n += wp.outn1; 224 dest[i] = d_n; 225 wp.outn1 = d_n; 226 } 227 wp.pos += dest.length; 228 } 229 /** 230 * Decodes an amount of 4 bit Oki/Dialogic ADPCM stream to extended 32 bit. 231 * Amount is decided by dest.length. `src` is a full waveform. Position is stored in wp.pos. 232 */ 233 public void decode4bitDialogicADPCM(ADPCMStream src, int[] dest, ref DecoderWorkpad wp) @safe { 234 for (size_t i ; i < dest.length ; i++) { 235 const ubyte index = src[i]; 236 uint stepSize; 237 int d_n; 238 wp.pred += ADPCM_INDEX_TABLE_4BIT[index]; 239 clamp(wp.pred, 0, 48); 240 stepSize = DIALOGIC_ADPCM_STEP_TABLE[wp.pred]; 241 d_n = ((stepSize) * (index & 0b0100)>>2) + ((stepSize>>1) * (index & 0b0010)>>1) + ((stepSize>>2) * index & 0b0001) 242 + (stepSize>>3); 243 if(index & 0b1000) 244 d_n *= -1; 245 d_n += wp.outn1; 246 dest[i] = ((d_n<<4) | (d_n>>8)) + short.min; 247 wp.outn1 = d_n; 248 } 249 wp.pos += dest.length; 250 } 251 /** 252 * Decodes a Mu-Law encoded stream. 253 */ 254 public void decodeMuLawStream(const(ubyte)[]src, int[] dest, ref DecoderWorkpad wp) @safe { 255 for (size_t i ; i < dest.length ; i++) { 256 dest[i] = MU_LAW_DECODER_TABLE[src[wp.pos + i]]; 257 } 258 wp.pos += dest.length; 259 } 260 /** 261 * Decodes an A-Law encoded stream. 262 */ 263 public void decodeALawStream(const(ubyte)[]src, int[] dest, ref DecoderWorkpad wp) @safe { 264 for (size_t i ; i < dest.length ; i++) { 265 dest[i] = A_LAW_DECODER_TABLE[src[wp.pos + i]]; 266 } 267 wp.pos += dest.length; 268 } 269 /** 270 * Streches a buffer to the given amount using no interpolation. 271 * Amount decided by `dest.length`. 272 * Can be used to pitch the sample. 273 * Params: 274 * src = source of the stream. 275 * dest = destination stream, it's length is also equals to how much samples are needed. 276 * wp = wave modulation workpad, storing information such as source position. 277 * modifier = jump amount, might be moved to a template parameter later on. 278 * clamping = Used for situations where not the whole waveform is decoded. Limits buffer size in a way, that it 279 * allows for double buffered decoding by allowing it to turn around at the end of one buffer. 280 */ 281 public void stretchAudioNoIterpol(const(int)[] src, int[] dest, ref WavemodWorkpad wp, uint modifier = 0x1_00_00_00, 282 uint clamping = 0xFF) @safe { 283 //wp.lookupVal &= 0x_FF_FF_FF; 284 for (size_t i ; i < dest.length /* && wp.lookupVal>>24 < src.length */ ; i++) { 285 dest[i] = src[cast(size_t)(wp.lookupVal>>24) & clamping]; 286 wp.lookupVal += modifier; 287 } 288 } 289 /** 290 * Converts MIDI note to frequency. 291 * Params: 292 * note = MIDI note number. 293 * baseFreq = A-4 note frequency 294 */ 295 public double midiToFreq(int note, const double baseFreq = 440.0) @safe { 296 double r = note - 69; 297 r /= 12; 298 r = pow(2, r); 299 return r * baseFreq; 300 } 301 /** 302 * Converts note number to frequency. 303 * Params: 304 * note = MIDI note number. 305 * baseFreq = A-4 note frequency 306 */ 307 public double noteToFreq(double note, const double baseFreq = 440.0) @safe { 308 double r = note - 69; 309 r /= 12; 310 r = pow(2, r); 311 return r * baseFreq; 312 } 313 /** 314 * Bends the frequency by the given amount of seminotes. 315 * Params: 316 * freq = The frequency to be modified. 317 * am = The amount of seminotes. Positive means upwards, negative means downwards. 318 * Returns: The modified frequency. 319 */ 320 public double bendFreq(double freq, double am) @safe { 321 return freq * pow(2, am / 12); 322 } 323 /** 324 * Calculates biquad low-pass filter coefficients from the supplied values. 325 * 326 * fs: Sampling frequency. 327 * f0: Corner frequency. 328 * q: The Q factor of the filter. 329 */ 330 public BiquadFilterValues createLPF(float fs, float f0, float q) @safe { 331 BiquadFilterValues result; 332 const float w0 = 2 * PI * f0 / fs; 333 const float alpha = sin(w0) / (2 * q); 334 result.b1 = 1 - cos(w0); 335 result.b0 = result.b1 / 2; 336 result.b2 = result.b0; 337 result.a0 = 1 + alpha; 338 result.a1 = -2 * cos(w0); 339 result.a2 = 1 - alpha; 340 return result; 341 } 342 /** 343 * Calculates biquad high-pass filter coefficients from the supplied values. 344 * Params: 345 * fs = Sampling frequency. 346 * f0 = Corner frequency. 347 * q = The Q factor of the filter. 348 * Returns: A struct with the coefficient values for the filter. 349 */ 350 public BiquadFilterValues createHPF(float fs, float f0, float q) @safe { 351 BiquadFilterValues result; 352 const float w0 = 2 * PI * f0 / fs; 353 const float alpha = sin(w0) / (2 * q); 354 result.b1 = (1 + cos(w0)) * -1; 355 result.b0 = (1 + cos(w0)) / 2; 356 result.b2 = result.b0; 357 result.a0 = 1 + alpha; 358 result.a1 = -2 * cos(w0); 359 result.a2 = 1 - alpha; 360 return result; 361 } 362 /** 363 * Calculates biquad band pass filter (constant skirt gain, peak gain = Q) filter coefficients from the supplied values. 364 * Params: 365 * fs = Sampling frequency. 366 * f0 = Corner frequency. 367 * q = Peak gain. 368 * Returns: A struct with the coefficient values for the filter. 369 */ 370 public BiquadFilterValues createBPF0(float fs, float f0, float q) @safe { 371 BiquadFilterValues result; 372 const float w0 = 2 * PI * f0 / fs; 373 const float alpha = sin(w0) / (2 * q); 374 result.b1 = 0; 375 result.b0 = q * alpha; 376 result.b2 = result.b0 * -1; 377 result.a0 = 1 + alpha; 378 result.a1 = -2 * cos(w0); 379 result.a2 = 1 - alpha; 380 return result; 381 } 382 /** 383 * Calculates biquad band pass filter (constant 0 db peak gain) filter coefficients from the supplied values. 384 * Params: 385 * fs = Sampling frequency. 386 * f0 = Corner frequency. 387 * q = Peak gain. 388 * Returns: A struct with the coefficient values for the filter. 389 */ 390 public BiquadFilterValues createBPF1(float fs, float f0, float q) @safe { 391 BiquadFilterValues result; 392 const float w0 = 2 * PI * f0 / fs; 393 const float alpha = sin(w0) / (2 * q); 394 result.b1 = 0; 395 result.b0 = alpha; 396 result.b2 = alpha * -1; 397 result.a0 = 1 + alpha; 398 result.a1 = -2 * cos(w0); 399 result.a2 = 1 - alpha; 400 return result; 401 } 402 public BiquadFilterValues createNotchFilt(float fs, float f0, float q) @safe { 403 BiquadFilterValues result; 404 const float w0 = 2 * PI * f0 / fs; 405 const float alpha = sin(w0) / (2 * q); 406 result.b1 = 0; 407 result.b0 = alpha; 408 result.b2 = alpha * -1; 409 result.a0 = 1 + alpha; 410 result.a1 = -2 * cos(w0); 411 result.a2 = 1 - alpha; 412 return result; 413 } 414 /** 415 * Calculates the time factor for an LP6 filter. 416 * Filter formula: 417 * `y[n] = y[n-1] + (x[n] - y[n-1]) * factor` 418 * Where factor is: 419 * `1.0 - exp(-1.0 / (timeConstantInSeconds * samplerate))` 420 * Params: 421 * fs = Sampling frequency. 422 * f0 = Cutoff frequency. 423 * Returns: The `factor` value. 424 */ 425 public double calculateLP6factor(float fs, float f0) @safe { 426 return 1.0 - exp(-1.0 / ((1 / f0) * fs)); 427 } 428 /** 429 * Creates the alpha value for a HP20 filter. 430 * Filter formula: 431 * `y[n] = (y[n-1] + x[n] - x[n-1]) * alpha` 432 * Where alpha is: 433 * `1 / (1 + 2 * pi * timeConstantInSeconds * samplerate)` 434 * Params: 435 * fs = Sampling frequency. 436 * f0 = Cutoff frequency. 437 * Returns: The `alpha` value. 438 */ 439 public double calculateHP20alpha(float fs, float f0) @safe { 440 return 1 / (1 + 2 * PI * (1 / f0) * fs); 441 } 442 /** 443 * Converts MIDI 1.0 14 bit control values to MIDI 2.0 32 bit. Might not work the best with certain values. 444 * Params: 445 * msb = most significant 7 bits 446 * lsb = least significant 7 bits 447 * Returns: The 32 bit control value. 448 */ 449 public uint convertM1CtrlValToM2(ubyte msb, ubyte lsb) @safe { 450 const uint addedTotal = msb<<7 | lsb; 451 return cast(uint)(uint.max * (cast(real)(addedTotal) / (ushort.max>>2))); 452 } 453 /** 454 * Sets an array (buffer) to all zeros. 455 * Params: 456 * targetBuffer = The buffer to be reset. 457 */ 458 public void resetBuffer(T)(T[] targetBuffer) @safe { 459 static if (is(T == __m128) || is(T == __vector(float[4]))) { 460 for (size_t i ; i < targetBuffer.length ; i++) { 461 targetBuffer[i] = __m128(0); 462 } 463 } else static if (is(T == float[4]) || is(T == int[4])) { 464 for (size_t i ; i < targetBuffer.length ; i++) { 465 targetBuffer[i] = [0, 0, 0, 0]; 466 } 467 } else { 468 for (size_t i ; i < targetBuffer.length ; i++) { 469 targetBuffer[i] = 0; 470 } 471 } 472 } 473 /** 474 * Original algorithm for C++ by Martin Leitner-Ankerl (https://martin.ankerl.com/2007/10/04/optimized-pow-approximation-for-java-and-c-c/). 475 * Computes the power of `a` on the `b`th much faster than std.math.pow, at the cost of some accuracy. 476 * Good enough for envelop curve shaping. 477 */ 478 double fastPow(double a, double b) @safe { 479 union U { 480 double d; 481 int[2] x; 482 } 483 U u; 484 u.d = a; 485 u.x[1] = cast(int)(b * (u.x[1] - 1_072_632_447) + 1_072_632_447); 486 u.x[0] = 0; 487 return u.d; 488 } 489 /** 490 * Returns the Cubic Lagrange coefficients for the supplied positions 491 * Params: 492 * x = position ideally between x_n[1] and x_n[2]. 493 * x_n = the supplied positions. All values must be different, otherwise the returned value will be NaN. 494 * Returns: an array with the coefficients. 495 */ 496 float[4] getCubicLagrCoeffs(float x, float[4] x_n) @safe { 497 float[4] result; 498 result[0]= ((x - x_n[1]) * (x - x_n[2]) * (x - x_n[3])) / ((x_n[0] - x_n[1]) * (x_n[0] - x_n[2]) * (x_n[0] - x_n[3])); 499 result[1]= ((x - x_n[0]) * (x - x_n[2]) * (x - x_n[3])) / ((x_n[1] - x_n[0]) * (x_n[1] - x_n[2]) * (x_n[1] - x_n[3])); 500 result[2]= ((x - x_n[0]) * (x - x_n[1]) * (x - x_n[3])) / ((x_n[2] - x_n[0]) * (x_n[2] - x_n[1]) * (x_n[2] - x_n[3])); 501 result[3]= ((x - x_n[0]) * (x - x_n[1]) * (x - x_n[2])) / ((x_n[3] - x_n[0]) * (x_n[3] - x_n[1]) * (x_n[3] - x_n[2])); 502 return result; 503 } 504 /** 505 * Returns the Cubic Lagrange coefficients for positions -1, 0, 1, 2. 506 * Params: 507 * x = position ideally between 0 and 1 508 * Returns: an array with the coefficients. 509 */ 510 float[4] getCubicLagrCoeffs(float x) @safe { 511 float[4] result; 512 result[0] = (x * (x - 1) * (x - 2)) / -6; 513 result[1] = ((x + 1) * (x - 1) * (x - 2)) / -2; 514 result[2] = ((x + 1) * x * (x - 2)) / -2; 515 result[3] = ((x + 1) * x * (x - 1)) / 6; 516 return result; 517 } 518 double smoothstep(double a, double b, double x) @safe { 519 x = (x - a) / (b - a); 520 return x * x * (3 - 2 * x); 521 }