SynthLab SDK
synthfunctions.h
1 // -----------------------------------------------------------------------------
2 // RackAFX Synth Objects File: synthfunctions.h
3 //
15 // -----------------------------------------------------------------------------
16 #pragma once
17 #ifndef __synthfunctions_h__
18 #define __synthfunctions_h__
19 
20 #include "synthbase.h"
21 #include "bleptables.h"
22 
23 namespace SynthLab
24 {
39  inline void copyOutputToInput(std::shared_ptr<AudioBuffer>& source, std::shared_ptr<AudioBuffer>& destination, uint32_t channel, uint32_t samplesToCopy)
40  {
41  if (channel == MONO_TO_MONO)
42  {
43  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
44  }
45  else if (channel == MONO_TO_STEREO)
46  {
47  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
48  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
49  }
50  else
51  {
52  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
53  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
54  }
55  }
56 
70  inline void copyOutputToOutput(std::shared_ptr<AudioBuffer>& source, std::shared_ptr<AudioBuffer>& destination, uint32_t channel, uint32_t samplesToCopy)
71  {
72  if (channel == MONO_TO_MONO)
73  {
74  memcpy(destination->getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
75  }
76  else if (channel == MONO_TO_STEREO)
77  {
78  memcpy(destination->getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
79  memcpy(destination->getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
80  }
81  else
82  {
83  memcpy(destination->getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
84  memcpy(destination->getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
85  }
86  }
87 
103  inline void copyOutputToOutput(std::shared_ptr<AudioBuffer>& source, SynthProcessInfo& destination, uint32_t channel, uint32_t samplesToCopy)
104  {
105  if (channel == MONO_TO_MONO)
106  {
107  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
108  }
109  else if (channel == MONO_TO_STEREO)
110  {
111  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
112  memcpy(destination.getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
113  }
114  else
115  {
116  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
117  memcpy(destination.getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
118  }
119  }
120 
138  inline void copyBufferToInput(std::shared_ptr<AudioBuffer>& source, std::shared_ptr<AudioBuffer>& destination, uint32_t channel, uint32_t samplesToCopy)
139  {
140  if (channel == MONO_TO_MONO)
141  {
142  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
143  }
144  else if (channel == MONO_TO_STEREO)
145  {
146  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
147  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
148  }
149  else
150  {
151  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
152  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
153  }
154  }
155 
173  inline void copyAudioBufferOutputToSynthOutput(std::shared_ptr<AudioBuffer>& source, SynthProcessInfo& destination, uint32_t channel, uint32_t samplesToCopy)
174  {
175  if (channel == MONO_TO_MONO)
176  {
177  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
178  }
179  else if (channel == MONO_TO_STEREO)
180  {
181  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
182  memcpy(destination.getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
183  }
184  else
185  {
186  memcpy(destination.getOutputBuffer(LEFT_CHANNEL), source->getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
187  memcpy(destination.getOutputBuffer(RIGHT_CHANNEL), source->getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
188  }
189  }
190 
206  inline void copySynthOutputToAudioBufferInput(SynthProcessInfo& source, std::shared_ptr<AudioBuffer>& destination, uint32_t channel, uint32_t samplesToCopy)
207  {
208  if (channel == MONO_TO_MONO)
209  {
210  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source.getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
211  }
212  else if (channel == MONO_TO_STEREO)
213  {
214  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source.getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
215  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source.getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
216  }
217  else
218  {
219  memcpy(destination->getInputBuffer(LEFT_CHANNEL), source.getOutputBuffer(LEFT_CHANNEL), samplesToCopy * sizeof(float));
220  memcpy(destination->getInputBuffer(RIGHT_CHANNEL), source.getOutputBuffer(RIGHT_CHANNEL), samplesToCopy * sizeof(float));
221  }
222  }
223 
224  // --- typed enumeration helpers
234 #define enumToInt(ENUM) static_cast<int>(ENUM)
235 
246 #define compareEnumToInt(ENUM,INT) (static_cast<int>(ENUM) == (INT))
247 
259 #define compareIntToEnum(INT,ENUM) ((INT) == static_cast<int>(ENUM))
260 
272 #define convertIntToEnum(INT,ENUM) static_cast<ENUM>(INT)
273 
279  const double kCTCoefficient = 5.0 / 12.0;
280 
286  const double kCTCorrFactorZero = pow(10.0, (-1.0 / kCTCoefficient));
287 
293  const double kCTCorrFactorAnitZero = 1.0 / (1.0 - kCTCorrFactorZero);
294 
300  const double kCTCorrFactorUnity = 1.0 / (1.0 + kCTCoefficient*log10(1.0 + kCTCorrFactorZero));
301 
307  const double kCTCorrFactorAntiUnity = 1.0 / (1.0 + (-pow(10.0, (-1.0 / kCTCoefficient))));
308 
314  const double kCTCorrFactorAntiLog = kCTCoefficient*log10(1.0 + kCTCorrFactorZero);
315 
322 
333  inline double normToLogNorm(double normalizedValue)
334  {
335  return 1.0 + kCTCoefficient*log10(normalizedValue);
336  }
337 
348  inline double logNormToNorm(double logNormalizedValue)
349  {
350  return pow(10.0, (logNormalizedValue - 1.0) / kCTCoefficient);
351  }
352 
363  inline double normToAntiLogNorm(double normalizedValue)
364  {
365  if (normalizedValue == 1.0)
366  return 1.0;
367 
368  double aln = -kCTCoefficient*log10(1.0 - normalizedValue);
369  aln = fmin(1.0, aln);
370  return aln;
371  }
372 
383  inline double antiLogNormToNorm(double aLogNormalizedValue)
384  {
385  return -pow(10.0, (-aLogNormalizedValue / kCTCoefficient)) + 1.0;
386  }
387 
400  inline double getModKnobValueLinear(double normalizedValue, double min, double max)
401  {
402  return (max - min)*normalizedValue + min;
403  }
404 
418  inline double getModKnobValueLog(double normalizedValue, double min, double max)
419  {
420  normalizedValue = normToLogNorm(normalizedValue);
421  return (max - min)*normalizedValue + min;
422  }
423 
437  inline double getModKnobValueAntiLog(double normalizedValue, double min, double max)
438  {
439  normalizedValue = normToAntiLogNorm(normalizedValue);
440  return (max - min)*normalizedValue + min;
441  }
442 
443 
455  inline double msecToSamples(double sampleRate, double timeMSec)
456  {
457  return sampleRate*(timeMSec / 1000.0);
458  }
459 
469  inline void clampMaxValue(double& value, double maxValue)
470  {
471  value = fmin(value, maxValue);
472  }
473 
483  inline void clampMinValue(double& value, double minValue)
484  {
485  value = fmax(value, minValue);
486  }
487 
488 
499  inline void boundValue(double& value, double minValue, double maxValue)
500  {
501  value = fmin(value, maxValue);
502  value = fmax(value, minValue);
503  }
504 
505 
514  inline void boundValueUnipolar(double& value)
515  {
516  value = fmin(value, 1.0);
517  value = fmax(value, 0.0);
518  }
519 
528  inline void boundValueBipolar(double& value)
529  {
530  value = fmin(value, 1.0);
531  value = fmax(value, -1.0);
532  }
533 
534 
535 
544  inline void boundMIDIValueByte(uint32_t& value)
545  {
546  value = (uint32_t)fmin(value, 127);
547  value = (uint32_t)fmax(value, 0);
548  }
549 
550 
559  inline void boundMIDIValueDoubleByte(uint32_t& value)
560  {
561  value = (uint32_t)fmin(value, 16384);
562  value = (uint32_t)fmax(value, 0);
563  }
564 
565 
575  inline void boundIntValue(int& value, int min, int max)
576  {
577  value = (uint32_t)fmin(value, max);
578  value = (uint32_t)fmax(value, min);
579  }
580 
593  inline void mapDoubleValue(double& value, double min, double max, double minMap, double maxMap)
594  {
595  // --- bound to limits
596  value = fmin(value, max);
597  value = fmax(value, min);
598 
599  double mapped = ((value - min) / (max - min)) * (maxMap - minMap) + minMap;
600  value = mapped;
601  }
602 
616  inline void mapIntValue(int& value, int min, int max, int minMap, int maxMap, bool roundValue = true)
617  {
618  // --- bound to limits
619  value = (uint32_t)fmin(value, max);
620  value = (uint32_t)fmax(value, min);
621 
622  double mapped = (double(value - min) / double(max - min)) * double(maxMap - minMap) + double(minMap);
623  if (roundValue)
624  value = (int)(round(mapped));
625  else
626  value = (int)mapped;
627  }
628 
642  inline void mapUintValue(uint32_t& value, uint32_t min, uint32_t max, uint32_t minMap, uint32_t maxMap, bool roundValue = true)
643  {
644  // --- bound to limits
645  value = (uint32_t)fmin(value, max);
646  value = (uint32_t)fmax(value, min);
647 
648  double mapped = (double(value - min) / double(max - min)) * double(maxMap - minMap) + double(minMap);
649  if (roundValue)
650  value = (uint32_t)(round(mapped));
651  else
652  value = (uint32_t)mapped;
653  }
654 
670  inline uint32_t mapDoubleToUINT(double value, double min, double max, uint32_t minMap, uint32_t maxMap, bool roundValue = false)
671  {
672  // --- bound to limits
673  value = fmin(value, max);
674  value = fmax(value, min);
675 
676  // --- map to range
677  uint32_t mappedValue = 0;
678  double mapped = (double(value - min) / double(max - min)) * double(maxMap - minMap) + double(minMap);
679  if (roundValue)
680  mappedValue = (uint32_t)(round(mapped));
681  else
682  mappedValue = (uint32_t)mapped;
683 
684  return mappedValue;
685  }
686 
701  inline double mapUINTToDouble(uint32_t value, uint32_t min, uint32_t max, double minMap, double maxMap)
702  {
703  // --- bound to limits
704  value = (uint32_t)fmin(value, max);
705  value = (uint32_t)fmax(value, min);
706 
707  double mapped = (double(value - min) / double(max - min)) * double(maxMap - minMap) + double(minMap);
708  return mapped;
709  }
710 
722  inline double midi14_bitToBipolar(uint32_t midiDataLSB, uint32_t midiDataMSB)
723  {
724  // --- combine data, LSB or-ed with MSB left-shifted by 7
725  int midi14_bitValue = (int)((midiDataLSB & 0x7F) | ((midiDataMSB & 0x7F) << 7));
726 
727  // --- convert to bipolar (0x2000 = 8192)
728  return (double)(midi14_bitValue - 0x2000) / (double)(0x2000);
729  }
730 
731 
743  inline uint32_t midi14_bitToUnipolarInt(uint32_t midiDataLSB, uint32_t midiDataMSB)
744  {
745  // --- combine data, LSB or-ed with MSB left-shifted by 7
746  uint32_t midi14_bitValue = (uint32_t)((midiDataLSB & 0x7F) | ((midiDataMSB & 0x7F) << 7));
747  return midi14_bitValue;
748  }
749 
761  inline double midi14_bitToUnipolarDouble(uint32_t midiDataLSB, uint32_t midiDataMSB)
762  {
763  // --- combine data, LSB or-ed with MSB left-shifted by 7
764  uint32_t midi14_bitValue = (uint32_t)((midiDataLSB & 0x7F) | ((midiDataMSB & 0x7F) << 7));
765 
766  // --- normalize 0x4000 = 16384
767  return (double)(midi14_bitValue) / (double)(0x4000);
768  }
769 
783  inline double midi14_bitToDouble(uint32_t midiDataLSB, uint32_t midiDataMSB, double minValue, double maxValue)
784  {
785  // --- combine data, LSB or-ed with MSB left-shifted by 7
786  uint32_t midi14_bitValue = (uint32_t)((midiDataLSB & 0x7F) | ((midiDataMSB & 0x7F) << 7));
787 
788  // --- normalize 0x4000 = 16384
789  double value = (double)(midi14_bitValue) / (double)(0x4000);
790 
791  mapDoubleValue(value, 0.0, 1.0, minValue, maxValue);
792  return value;
793  }
794 
807  inline void unipolarIntToMIDI14_bit(uint32_t unipolarValue, uint32_t& midiDataLSB, uint32_t& midiDataMSB)
808  {
809  // --- convert to 16-bit unsigned short
810  unsigned short shValue = (unsigned short)unipolarValue;
811  unsigned short shd1 = shValue & 0x007F;
812 
813  // --- shift back by 1
814  unsigned short shd2 = shValue << 1;
815 
816  // --- split into MSB, LSB
817  shd2 = shd2 & 0x7F00;
818 
819  // --- shift MSB back to fill LSB position
820  shd2 = shd2 >> 8;
821 
822  // --- copy into unsigned ints, fill lower portions
823  midiDataLSB = shd1;
824  midiDataMSB = shd2;
825  }
826 
827 
842  inline void bipolarIntToMIDI14_bit(int32_t biPolarValue, int32_t minValue, int32_t maxValue, uint32_t& midiDataLSB, uint32_t& midiDataMSB)
843  {
844  // --- convert bipolar value to 14-bit value
845  mapIntValue(biPolarValue, minValue, maxValue, 0, 16383);
846 
847  // --- convert to 16-bit unsigned short
848  unsigned short shValue = (unsigned short)biPolarValue;
849  unsigned short shd1 = shValue & 0x007F;
850 
851  // --- shift back by 1
852  unsigned short shd2 = shValue << 1;
853 
854  // --- split into MSB, LSB
855  shd2 = shd2 & 0x7F00;
856 
857  // --- shift MSB back to fill LSB position
858  shd2 = shd2 >> 8;
859 
860  // --- copy into unsigned ints, fill lower portions
861  midiDataLSB = shd1;
862  midiDataMSB = shd2;
863  }
864 
865 
878  inline void unipolarDoubleToMIDI14_bit(double unipolarValue, uint32_t& midiDataLSB, uint32_t& midiDataMSB)
879  {
880  // --- should never happen, but needed
881  boundValue(unipolarValue, 0.0, 1.0);
882 
883  // --- convert to 16-bit unsigned short
884  unsigned short shValue = (unsigned short)(unipolarValue * (double)(0x4000));
885  unsigned short shd1 = shValue & 0x007F;
886 
887  // --- shift back by 1
888  unsigned short shd2 = shValue << 1;
889 
890  // --- split into MSB, LSB
891  shd2 = shd2 & 0x7F00;
892 
893  // --- shift MSB back to fill LSB position
894  shd2 = shd2 >> 8;
895 
896  // --- copy into unsigned ints, fill lower portions
897  midiDataLSB = shd1;
898  midiDataMSB = shd2;
899  }
900 
901 
913  inline double midiPitchBendToBipolar(uint32_t midiData1, uint32_t midiData2)
914  {
915  int midiPitchBendValue = (int)((midiData1 & 0x7F) | ((midiData2 & 0x7F) << 7));
916  return (double)(midiPitchBendValue - 0x2000) / (double)(0x2000);
917  }
918 
919 
931  inline double doUnipolarModulationFromMin(double unipolarModulatorValue, double minValue, double maxValue)
932  {
933  // --- UNIPOLAR bound
934  boundValue(unipolarModulatorValue, 0.0, 1.0);
935 
936  // --- modulate from minimum value upwards
937  return unipolarModulatorValue*(maxValue - minValue) + minValue;
938  }
939 
951  inline double doUnipolarModulationFromMax(double unipolarModulatorValue, double minValue, double maxValue)
952  {
953  // --- UNIPOLAR bound
954  boundValue(unipolarModulatorValue, 0.0, 1.0);
955 
956  // --- modulate from maximum value downwards
957  return maxValue - (1.0 - unipolarModulatorValue)*(maxValue - minValue);
958  }
959 
971  inline double doBipolarModulation(double bipolarModulatorValue, double minValue, double maxValue)
972  {
973  // --- BIPOLAR bound
974  boundValueBipolar(bipolarModulatorValue);
975 
976  // --- calculate range and midpoint
977  double halfRange = (maxValue - minValue) / 2.0;
978  double midpoint = halfRange + minValue;
979 
980  return bipolarModulatorValue*(halfRange)+midpoint;
981  }
982 
996  inline double splitBipolar(double value)
997  {
998  return value >= 0.5 ? 2.0*value - 1.0 : 1.0 - 2.0*value;
999  }
1000 
1001 
1011  inline double bipolar(double value)
1012  {
1013  return 2.0*value - 1.0;
1014  }
1015 
1024  inline void bipolarXForm(double& value)
1025  {
1026  value = 2.0*value - 1.0;
1027  }
1028 
1038  inline double unipolar(double value)
1039  {
1040  return 0.5*value + 0.5;
1041  }
1042 
1051  inline void unipolarXForm(double& value)
1052  {
1053  value = 0.5*value + 0.5;
1054  }
1055 
1065  inline double raw2dB(double raw)
1066  {
1067  return 20.0*log10(raw);
1068  }
1069 
1079  inline double dB2Raw(double dB)
1080  {
1081  return pow(10.0, (dB / 20.0));
1082  }
1083 
1093  inline double peakGainFor_Q(double Q)
1094  {
1095  // --- no resonance at or below unity
1096  if (Q <= 0.707) return 1.0;
1097  return (Q*Q) / (pow((Q*Q - 0.25), 0.5));
1098  }
1099 
1109  inline double dBPeakGainFor_Q(double Q)
1110  {
1111  return raw2dB(peakGainFor_Q(Q));
1112  }
1113 
1114  // --- for phase distortion // modulatedShape = parameters->shape + modulationInputs[kAuxBipolarMod_1]
1115  inline double applyPhaseDistortion(double mcounter, double x_break, double y_break = 0.5)
1116  {
1117  // --- limit to [0.1, 0.9] to prevent jagged slopes/aliasing
1118  mapDoubleValue(x_break, 0.0, 1.0, 0.1, 0.9);
1119 
1120  // --- calc 2 slopes
1121  double m1 = y_break / x_break;
1122  double m2 = (1.0 - y_break) / (1.0 - x_break);
1123 
1124  // --- only can happen if m1 = m2 = 1.0
1125  if (m2 == m1)
1126  return mcounter;
1127 
1128  // --- apply distortion
1129  if (mcounter <= x_break)
1130  return m1*mcounter;
1131  else
1132  return (mcounter - x_break)*m2 + y_break;
1133 
1134  return mcounter;
1135  }
1136 
1145  inline double sgn(double xn)
1146  {
1147  return (xn > 0) - (xn < 0);
1148  }
1149 
1160  inline double calcWSGain(double xn, double saturation, double asymmetry)
1161  {
1162  double g = ((xn >= 0.0 && asymmetry > 0.0) || (xn < 0.0 && asymmetry < 0.0)) ? saturation * (1.0 + 4.0*fabs(asymmetry)) : saturation;
1163  return g;
1164  }
1165 
1175  inline double atanWaveShaper(double xn, double saturation)
1176  {
1177  if (saturation == 0) return xn;
1178  return atan(saturation*xn) / atan(saturation);
1179  }
1180 
1190  inline double tanhWaveShaper(double xn, double saturation)
1191  {
1192  if (saturation == 0) return xn;
1193  return tanh(saturation*xn) / tanh(saturation);
1194  }
1195 
1205  inline double softClipWaveShaper(double xn, double saturation)
1206  {
1207  if (saturation == 0) return xn;
1208 
1209  // --- un-normalized soft clipper from Reiss book
1210  return sgn(xn)*(1.0 - exp(-fabs(saturation*xn)));
1211  }
1212 
1222  inline double fuzzExp1WaveShaper(double xn, double saturation, double asymmetry)
1223  {
1224  if (saturation == 0) return xn;
1225 
1226  // --- setup gain
1227  double wsGain = calcWSGain(xn, saturation, asymmetry);
1228  return sgn(xn)*(1.0 - exp(-fabs(wsGain*xn))) / (1.0 - exp(-wsGain));
1229  }
1230 
1231 
1242  inline void copyStingList(std::vector<std::string>& source, std::vector<std::string>& destination)
1243  {
1244  destination.clear();
1245  uint32_t count = source.size();
1246  for (uint32_t i = 0; i < count; i++)
1247  {
1248  std::string str = source[i];
1249 
1250  destination.push_back(str);
1251  }
1252  }
1253 
1266  inline std::string concatStrings(std::string s1, std::string s2)
1267  {
1268  std::string ret = s1;
1269  ret.append(s2);
1270  return ret;
1271  }
1272 
1285  inline void ReplaceSubStrWithStr(std::string& str, const std::string& from, const std::string& to)
1286  {
1287  size_t start_pos = 0;
1288  while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
1289  str.replace(start_pos, from.length(), to);
1290  start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
1291  }
1292  }
1293 
1304  inline void stripLastFolderFromPath(std::string& str)
1305  {
1306  str = str.substr(0, str.find_last_of("\\/"));
1307  }
1308 
1319  inline void getPluginContainerFolder(std::string& str)
1320  {
1321  for(uint32_t i=0; i<3; i++)
1323  }
1324 
1339  inline double doLinearInterpolation(double x1, double x2, double y1, double y2, double x)
1340  {
1341  double denom = x2 - x1;
1342  if (denom == 0)
1343  return y1; // --- should not ever happen
1344 
1345  // --- calculate decimal position of x
1346  double dx = (x - x1) / (x2 - x1);
1347 
1348  // --- use weighted sum method of interpolating
1349  return dx*y2 + (1 - dx)*y1;
1350  }
1351 
1364  inline double doLinearInterpolation(double y1, double y2, double fractional_X)
1365  {
1366  // --- check invalid condition
1367  if (fractional_X >= 1.0) return y2;
1368 
1369  // --- use weighted sum method of interpolating
1370  return fractional_X*y2 + (1.0 - fractional_X)*y1;
1371  }
1372 
1385  inline double doLagrangeInterpolation(double* x, double* y, int n, double xbar)
1386  {
1387  int i, j;
1388  double fx = 0.0;
1389  double l = 1.0;
1390  for (i = 0; i<n; i++)
1391  {
1392  l = 1.0;
1393  for (j = 0; j<n; j++)
1394  {
1395  if (j != i)
1396  l *= (xbar - x[j]) / (x[i] - x[j]);
1397  }
1398  fx += l*y[i];
1399  }
1400  return (fx);
1401  }
1402 
1403 
1414  //
1415  // <----- NOTE: This function was removed because of the insane size of the lookup table (16k)
1416  // <----- If you want to use it, #include "pitchshifttable.h and then uncomment this function
1417  //
1418  //inline double pitchShiftTableLookup(double semitones)
1419  //{
1420  // double index = kPitchShiftTableCenter + (semitones*kPitchShiftTableCenterSemis);
1421  // if (index >= kPitchShiftTableEnd) return pitchShiftTable[kPitchShiftTableEnd];
1422  // int intPart = (int)index;
1423  // return doLinearInterpolation(0.0, 1.0, pitchShiftTable[intPart], pitchShiftTable[intPart + 1], index - intPart);
1424  //}
1425 
1426 
1441  inline uint32_t midiNoteNumberFromOscFrequency(double oscillatorFrequency, double frequencyA440 = 440.0)
1442  {
1443  // --- ceil will round up
1444  double midiNote = ceil(12.0*log2(oscillatorFrequency / frequencyA440) + 69.0); //--- 69 = MIDI note # for A-440
1445 
1446  // --- grab int part
1447  uint32_t renderMidiNoteNumber = (uint32_t)(midiNote);
1448 
1449  // --- bound to 0 -> 127
1450  boundMIDIValueByte(renderMidiNoteNumber);
1451 
1452  return renderMidiNoteNumber;
1453  }
1454 
1469  inline double midiNoteNumberToOscFrequency(uint32_t midiNoteNumber, double frequencyA440 = 440.0)
1470  {
1471  // --- https://newt.phys.unsw.edu.au/jw/notes.html
1472  double pitch = pow(2.0, (((double)midiNoteNumber - 69.0) / 12.0))*frequencyA440;
1473 
1474  return pitch;
1475  }
1476 
1489  inline double calculateWaveTablePhaseInc(double oscFrequency, double sampleRate, uint32_t wavetableLength)
1490  {
1491  // --- for wavetables, inc = (kWaveTableLength)*(fo/fs)
1492  return wavetableLength*(oscFrequency / sampleRate);
1493  }
1494 
1506  inline bool checkAndWrapWaveTableIndex(double& index, uint32_t tableLength)
1507  {
1508  if (index > tableLength)
1509  {
1510  index = fmod(index, tableLength);
1511  return true;
1512  }
1513  else if (index < 0.0)
1514  {
1515  index = tableLength + fmod(index - tableLength, tableLength);
1516  return true;
1517  }
1518 
1519  return false;
1520  }
1521 
1533  inline int countTrailingZero(int x)
1534  {
1535  // Map a bit value mod 37 to its position
1536  static const int lookup[] = { 32, 0, 1,
1537  26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11,
1538  0, 13, 4, 7, 17, 0, 25, 22, 31, 15, 29,
1539  10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19,
1540  18 };
1541 
1542  // Only difference between (x and -x) is
1543  // the value of signed magnitude(leftmostbit)
1544  // negative numbers signed bit is 1
1545  return lookup[(-x & x) % 37];
1546  }
1547 
1559  inline uint64_t countTrailingZeros_x64(uint64_t x)
1560  {
1561  uint64_t count = 0;
1562  while ((x & 1) == 0)
1563  {
1564  x = x >> 1;
1565  count++;
1566  }
1567  return count;
1568  }
1569 
1582  inline void calculatePanValues(double bipolarModulator, double& leftPanValue, double& rightPanValue)
1583  {
1584  leftPanValue = cos((kPiOverFour)*(bipolarModulator + 1.0));
1585  rightPanValue = sin((kPiOverFour)*(bipolarModulator + 1.0));
1586 
1587  leftPanValue = fmax(leftPanValue, (double)0.0);
1588  leftPanValue = fmin(leftPanValue, (double)1.0);
1589  rightPanValue = fmax(rightPanValue, (double)0.0);
1590  rightPanValue = fmin(rightPanValue, (double)1.0);
1591  }
1592 
1605  inline void calculateConstPwrMixValues(double bipolarModulator, double& mixValueA, double& mixValueB)
1606  {
1607  calculatePanValues(bipolarModulator, mixValueA, mixValueB);
1608  }
1609 
1610 
1627  inline double crossfade(XFadeType xfadeType, double inputA, double inputB, double xFrac)
1628  {
1629  double output = 0.0;
1630 
1631  // --- calculate gains
1632  // --- constant power (same as pan calc)
1633  double gainA = 1.0;
1634  double gainB = 0.0;
1635  calculateConstPwrMixValues(bipolar(xFrac), gainA, gainB);
1636 
1637  if (xfadeType == XFadeType::kConstantPower)
1638  output = inputA*gainA + inputB*gainB;
1639  else if (xfadeType == XFadeType::kSquareLaw)
1640  output = inputA*(1.0 - xFrac*xFrac) + inputB*(1.0 - (xFrac - 1.0)*(xFrac - 1.0)); // A gain = 1 - x^2, B gain = 1 - ((x-1)^2)
1641  else // linear
1642  output = inputA*(1.0 - xFrac + inputB*(xFrac));
1643 
1644  return output;
1645  }
1646 
1647 
1659  inline double semitonesBetweenFrequencies(double startFrequency, double endFrequency)
1660  {
1661  return log2(endFrequency / startFrequency)*12.0;
1662  }
1663 
1670  enum class NoteDuration {
1671  k32ndTriplet, k32nd, k16thTriplet, kDot32nd,
1672  k16th, k8thTriplet, kDot16th,
1673  k8th, kQuarterTriplet, kDot8th,
1674  kQuarter, kHalfTriplet, kDotQuarter,
1675  kHalf, kWholeTriplet, kDotHalf,
1676  kWhole, kDotWhole,
1677  kOff,
1678  kNumNoteDurations
1679  };
1680 
1700  static const double noteDurationTable[int(NoteDuration::kNumNoteDurations)] = {
1701  0.0833, /* k32ndTriplet */
1702 
1703  0.125, /* k32nd */
1704  0.1667, /* k16thTriplet */
1705  0.1875, /* kDot32nd */
1706 
1707  0.25, /* k16th */
1708  0.333, /* k8thTriplet */
1709  0.375, /* kDot16th */
1710 
1711  0.5, /* k8th */
1712  0.667, /* kQuartTriplet */
1713  0.75, /* kDot8th */
1714 
1715  1.0, /* kQuart */
1716  1.333, /* kHalfTriplet */
1717  1.5, /* kDotQuart */
1718 
1719  2.0, /* kHalf */
1720  2.667, /* kWholeTriplet */
1721  3.0, /* kDotHalf */
1722 
1723  4.0, /* kWhole */
1724  6.0, /* kDotWhole */
1725 
1726  0.0 }; /* off */
1727 
1740  inline double getTimeFromTempo(double BPM, NoteDuration duration, bool returnMilliseconds = false)
1741  {
1742  if (duration == NoteDuration::kOff)
1743  {
1744  if (returnMilliseconds)
1745  return 1.0;
1746  else
1747  return 0.001;
1748  }
1749 
1750  // milliseconds from BPM
1751  double mSec = 60000.0 / BPM;
1752 
1753  // --- scale by table entry
1754  double time = 0.0;
1755  if (returnMilliseconds)
1756  time = (noteDurationTable[enumToInt(duration)] * mSec);
1757  else
1758  time = (noteDurationTable[enumToInt(duration)] * mSec) / 1000.0;
1759 
1760  return time;
1761  }
1762 
1778  inline double getTimeFromTempo(double BPM, double normalizedNoteMult)
1779  {
1780  if (normalizedNoteMult < 0.01)
1781  return 0.0;
1782 
1783  // --- micro lookup table of rhythmic multipliers
1784  static const double lookup[] = { 4.0, 2.0, 1.5, 1.0, 0.75, 0.5, 0.375, 0.25 };
1785  uint32_t index = mapDoubleToUINT(normalizedNoteMult, 0.0, 1.0, 0, 7);
1786  double mSec = 60000.0 / BPM;
1787  return (lookup[index] * mSec) / 1000.0;
1788  }
1789 
1802  inline double quantizeBipolarValue(double d, uint32_t qLevels)
1803  {
1804  uint32_t u = mapDoubleToUINT(d, -1.0, 1.0, 0, qLevels, true);
1805  return mapUINTToDouble(u, 0, qLevels, -1.0, 1.0);
1806  }
1807 
1819  inline uint64_t doubleToUint64(double d)
1820  {
1821  uint64_t retValue = 0;
1822  memcpy(&retValue, &d, sizeof(uint64_t));
1823  return retValue;
1824  }
1825 
1837  inline double uint64ToDouble(uint64_t u)
1838  {
1839  double retValue = 0.0;
1840  memcpy(&retValue, &u, sizeof(uint64_t));
1841  return retValue;
1842  }
1843 
1855  inline uint32_t floatToUint32(float d)
1856  {
1857  uint32_t retValue = 0;
1858  memcpy(&retValue, &d, sizeof(uint32_t));
1859  return retValue;
1860  }
1861 
1873  inline float uint32ToFloat(uint32_t u)
1874  {
1875  float retValue = 0.0;
1876  memcpy(&retValue, &u, sizeof(uint32_t));
1877  return retValue;
1878  }
1879 
1880 
1894  inline bool inRange(double low, double high, double x)
1895  {
1896  return ((x - high)*(x - low) <= 0.0);
1897  }
1898 
1912  inline double wrapMax(double x, double max)
1913  {
1914  /* integer math: `(max + x % max) % max` */
1915  return fmod(max + fmod(x, max), max);
1916  }
1917 
1932  inline double wrapMinMax(double x, double min, double max)
1933  {
1934  return min + wrapMax(x - min, max - min);
1935  }
1936 
1949  inline std::vector<std::string> charArrayToStringVector(const char** charArray, uint32_t size, std::string ignoreString = "")
1950  {
1951  std::vector<std::string> outputVector;
1952  for (uint32_t i = 0; i < size; i++)
1953  {
1954  // const char* cc = charArray[i];
1955  std::string str(charArray[i]);
1956 
1957  if (str.compare(ignoreString) != 0)
1958  outputVector.push_back(str);
1959  }
1960 
1961  return outputVector;
1962  }
1963 
1977  inline bool appendCharArrayToStringVector(const char** charArray, uint32_t size, std::vector<std::string>& outputVector, std::string ignoreString)
1978  {
1979  // std::vector<std::string> outputVector;
1980  if (size <= 0)
1981  return false;
1982 
1983  for (uint32_t i = 0; i < size; i++)
1984  {
1985  // const char* cc = charArray[i];
1986  std::string str(charArray[i]);
1987  if(str.compare(ignoreString) != 0)
1988  outputVector.push_back(str);
1989  }
1990 
1991  return true;
1992  }
1993 
1994 
1995 
2007  inline double mmaMIDItoAtten(uint32_t midiValue)
2008  {
2009  if (midiValue == 0)
2010  return 0.0; // --- floor
2011 
2012  return ((double)midiValue*(double)midiValue) / (127.0*127.0);
2013  }
2014 
2027  struct VectorXFadeData
2028  {
2029  double vectorA = 0.25;
2030  double vectorB = 0.25;
2031  double vectorC = 0.25;
2032  double vectorD = 0.25;
2033 
2034  // --- unipolar
2035  double vectorAC = 0.5;
2036  double vectorBD = 0.5;
2037  };
2038 
2039 
2054  inline VectorXFadeData calculateVectorMix(double joystick_X, double joystick_Y,
2055  double origin_X = 0.0, double origin_Y = 0.0)
2056  {
2057  VectorXFadeData vectorCoeffs;
2058  double x = (joystick_X - joystick_Y) / 2.0;
2059  double y = (joystick_X + joystick_Y) / 2.0;
2060 
2061  // --- these are 0->1 unipolar
2062  vectorCoeffs.vectorAC = (x + 1.0) / 2.0;
2063  vectorCoeffs.vectorBD = (y + 1.0) / 2.0;
2064 
2065  // --- offset by origin
2066  x += origin_X;
2067  y += origin_Y;
2068 
2069  x *= 127.0;
2070  y *= 127.0;
2071 
2072  boundValue(x, -128.0, 127.0);/* Limit range to [-128, 127] */
2073  boundValue(y, -128.0, 127.0);/* Limit range to [-128, 127] */
2074 
2075  // --- offset for center of [0, 255]
2076  x += 127;
2077  y += 127;
2078 
2079  // --- the Korg/Sequential Circuits VS Equations
2080  vectorCoeffs.vectorB = x*y / 645.0; /* Calculate individual wave % */
2081  vectorCoeffs.vectorC = x*(255.0 - y) / 645.0; /* 645=(255^2/100)*127/128 */
2082  vectorCoeffs.vectorD = (255.0 - x)*(255.0 - y) / 645.0;
2083  vectorCoeffs.vectorA = 100.0 - vectorCoeffs.vectorB - vectorCoeffs.vectorC - vectorCoeffs.vectorD;
2084 
2085  // --- convert from percent
2086  vectorCoeffs.vectorA /= 100.0;
2087  vectorCoeffs.vectorB /= 100.0;
2088  vectorCoeffs.vectorC /= 100.0;
2089  vectorCoeffs.vectorD /= 100.0;
2090 
2091  // --- bound to [0, 1] from rounding/truncation
2092  boundValue(vectorCoeffs.vectorA, 0.0, 1.0);
2093  boundValue(vectorCoeffs.vectorB, 0.0, 1.0);
2094  boundValue(vectorCoeffs.vectorC, 0.0, 1.0);
2095  boundValue(vectorCoeffs.vectorD, 0.0, 1.0);
2096 
2097  return vectorCoeffs;
2098  }
2099 
2111  inline double quadraticSine(double angle)
2112  {
2113  double d = fabs(angle);
2114  double sgn = d == 0 ? 1.0 : angle / d;
2115  return (4.0 * angle) / (kPiSqared)*(kPi - sgn*angle);
2116  }
2117 
2129  const double D = 5.0*kPiSqared;
2130  inline double BhaskaraISine(double angle)
2131  {
2132  double d = fabs(angle);
2133  double sgn = d == 0 ? 1.0 : angle / d;
2134  return 16.0*angle*(kPi - sgn*angle) / (D - sgn*4.0*angle*(kPi - sgn*angle));
2135  }
2136 
2148  const double B = 4.0 / kPi;
2149  const double C = -4.0 / (kPiSqared);
2150  const double P = 0.225;
2151  inline double parabolicSine(double angle)
2152  {
2153  double y = B * angle + C * angle * fabs(angle);
2154  return P * (y * fabs(y) - y) + y;
2155  }
2156 
2157 
2173  inline double calculatePitchBend(std::shared_ptr<MidiInputData> midiInputData)
2174  {
2175  // --- calculate MIDI pitch bend range
2176  double midiPitchBendRange = midiInputData->getGlobalMIDIData(kMIDIMasterPBSensCoarse) +
2177  (midiInputData->getGlobalMIDIData(kMIDIMasterPBSensFine) / 100.0);
2178 
2179  // --- calculate MIDI pitch bend (USER)
2180  double midiPitchBend = midiPitchBendRange * midiPitchBendToBipolar(midiInputData->getGlobalMIDIData(kMIDIPitchBendDataLSB),
2181  midiInputData->getGlobalMIDIData(kMIDIPitchBendDataMSB));
2182 
2183  return midiPitchBend;
2184  }
2185 
2201  inline double calculatePitchBend(IMidiInputData* midiInputData)
2202  {
2203  // --- calculate MIDI pitch bend range
2204  double midiPitchBendRange = midiInputData->getGlobalMIDIData(kMIDIMasterPBSensCoarse) +
2205  (midiInputData->getGlobalMIDIData(kMIDIMasterPBSensFine) / 100.0);
2206 
2207  // --- calculate MIDI pitch bend (USER)
2208  double midiPitchBend = midiPitchBendRange * midiPitchBendToBipolar(midiInputData->getGlobalMIDIData(kMIDIPitchBendDataLSB),
2209  midiInputData->getGlobalMIDIData(kMIDIPitchBendDataMSB));
2210 
2211  return midiPitchBend;
2212  }
2213 
2227  inline double calculateMasterTuning(IMidiInputData* midiInputData)
2228  {
2229  // --- coarse (semitones): -64 to +63 maps-> 0, 127 (7-bit)
2230  int mtCoarse = midiInputData->getGlobalMIDIData(kMIDIMasterTuneCoarseMSB);
2231  mapIntValue(mtCoarse, 0, 127, -64, +63, false); // false = no rounding
2232 
2233  // --- fine (cents): -100 to +100 as MIDI 14-bit
2234  double mtFine = midi14_bitToDouble(midiInputData->getGlobalMIDIData(kMIDIMasterTuneFineLSB),
2235  midiInputData->getGlobalMIDIData(kMIDIMasterTuneFineMSB), -100.0, 100.0);
2236 
2237  // --- this gives proper int.fraction value
2238  return (double)mtCoarse + ((double)mtFine / 100.0);
2239  }
2240 
2255  inline uint32_t calculateNumTables(uint32_t seedMIDINote, uint32_t tableIntervalSemitones)
2256  {
2257  uint32_t count = 0;
2258  uint32_t nextMIDINote = seedMIDINote;
2259  if (seedMIDINote > 127) return 0;
2260  if (seedMIDINote == 127) return 1;
2261  while (nextMIDINote < 128)
2262  {
2263  nextMIDINote += tableIntervalSemitones;
2264  count++;
2265  }
2266  return count;
2267  }
2268 
2272  static uint32_t xformLUTLen = 512;
2273 
2277  static uint64_t concaveLUT[512] = { 0x3EA15515C0000000, 0x3F3727CC40000000, 0x3F47294020000000, 0x3F51623480000000, 0x3F5732B360000000, 0x3F5D061FA0000000, 0x3F616E3E00000000, 0x3F645AE5E0000000, 0x3F674908E0000000, 0x3F6A38A860000000, 0x3F6D29C620000000, 0x3F700E31C0000000, 0x3F71884100000000, 0x3F730311A0000000, 0x3F747EA460000000, 0x3F75FAFA20000000, 0x3F77781380000000, 0x3F78F5F160000000, 0x3F7A749480000000, 0x3F7BF3FDA0000000, 0x3F7D742DC0000000, 0x3F7EF52580000000, 0x3F803B72E0000000, 0x3F80FCB7C0000000, 0x3F81BE61A0000000, 0x3F828070E0000000, 0x3F8342E620000000, 0x3F8405C1C0000000, 0x3F84C90400000000, 0x3F858CAD80000000, 0x3F8650BE80000000, 0x3F871537A0000000, 0x3F87DA1920000000, 0x3F889F63A0000000, 0x3F89651760000000, 0x3F8A2B34E0000000, 0x3F8AF1BC80000000, 0x3F8BB8AEE0000000, 0x3F8C800C60000000, 0x3F8D47D560000000, 0x3F8E100A60000000, 0x3F8ED8ABE0000000, 0x3F8FA1BA60000000, 0x3F90359B20000000, 0x3F909A8FE0000000, 0x3F90FFBBE0000000, 0x3F91651F40000000, 0x3F91CABA40000000, 0x3F92308D20000000, 0x3F92969840000000, 0x3F92FCDB80000000, 0x3F93635780000000, 0x3F93CA0C60000000, 0x3F9430FA40000000, 0x3F94982180000000, 0x3F94FF8240000000, 0x3F95671D00000000, 0x3F95CEF1C0000000, 0x3F963700E0000000, 0x3F969F4AA0000000, 0x3F9707CF20000000, 0x3F97708EE0000000, 0x3F97D98A00000000, 0x3F9842C0C0000000, 0x3F98AC3380000000, 0x3F9915E260000000, 0x3F997FCDA0000000, 0x3F99E9F5A0000000, 0x3F9A545AC0000000, 0x3F9ABEFD00000000, 0x3F9B29DCE0000000, 0x3F9B94FA80000000, 0x3F9C005660000000, 0x3F9C6BF080000000, 0x3F9CD7C960000000, 0x3F9D43E120000000, 0x3F9DB03840000000, 0x3F9E1CCEC0000000, 0x3F9E89A520000000, 0x3F9EF6BBC0000000, 0x3F9F6412A0000000, 0x3F9FD1AA40000000, 0x3FA01FC180000000, 0x3FA056CE80000000, 0x3FA08DFC40000000, 0x3FA0C54B00000000, 0x3FA0FCBAE0000000, 0x3FA1344C20000000, 0x3FA16BFEA0000000, 0x3FA1A3D2E0000000, 0x3FA1DBC8C0000000, 0x3FA213E0A0000000, 0x3FA24C1A80000000, 0x3FA28476A0000000, 0x3FA2BCF520000000, 0x3FA2F59620000000, 0x3FA32E59E0000000, 0x3FA36740A0000000, 0x3FA3A04A60000000, 0x3FA3D97740000000, 0x3FA412C7A0000000, 0x3FA44C3B80000000, 0x3FA485D320000000, 0x3FA4BF8EC0000000, 0x3FA4F96E60000000, 0x3FA5337240000000, 0x3FA56D9AA0000000, 0x3FA5A7E7A0000000, 0x3FA5E25960000000, 0x3FA61CF040000000, 0x3FA657AC20000000, 0x3FA6928D60000000, 0x3FA6CD9440000000, 0x3FA708C0E0000000, 0x3FA7441340000000, 0x3FA77F8BE0000000, 0x3FA7BB2AC0000000, 0x3FA7F6F020000000, 0x3FA832DC20000000, 0x3FA86EEF20000000, 0x3FA8AB2920000000, 0x3FA8E78A60000000, 0x3FA9241340000000, 0x3FA960C3A0000000, 0x3FA99D9C00000000, 0x3FA9DA9C60000000, 0x3FAA17C520000000, 0x3FAA551660000000, 0x3FAA929040000000, 0x3FAAD03320000000, 0x3FAB0DFF40000000, 0x3FAB4BF480000000, 0x3FAB8A1380000000, 0x3FABC85C40000000, 0x3FAC06CF00000000, 0x3FAC456C00000000, 0x3FAC843360000000, 0x3FACC32580000000, 0x3FAD024280000000, 0x3FAD418AC0000000, 0x3FAD80FE40000000, 0x3FADC09D60000000, 0x3FAE006860000000, 0x3FAE405F60000000, 0x3FAE8082C0000000, 0x3FAEC0D2A0000000, 0x3FAF014F60000000, 0x3FAF41F920000000, 0x3FAF82D020000000, 0x3FAFC3D4C0000000, 0x3FB0028380000000, 0x3FB02333C0000000, 0x3FB043FB20000000, 0x3FB064D9C0000000, 0x3FB085CFC0000000, 0x3FB0A6DD40000000, 0x3FB0C80280000000, 0x3FB0E93F80000000, 0x3FB10A9480000000, 0x3FB12C0180000000, 0x3FB14D86C0000000, 0x3FB16F2460000000, 0x3FB190DA60000000, 0x3FB1B2A900000000, 0x3FB1D49080000000, 0x3FB1F690E0000000, 0x3FB218AA40000000, 0x3FB23ADCC0000000, 0x3FB25D28A0000000, 0x3FB27F8E20000000, 0x3FB2A20D20000000, 0x3FB2C4A5E0000000, 0x3FB2E758A0000000, 0x3FB30A2580000000, 0x3FB32D0C80000000, 0x3FB3500E00000000, 0x3FB3732A00000000, 0x3FB39660A0000000, 0x3FB3B9B240000000, 0x3FB3DD1EE0000000, 0x3FB400A6A0000000, 0x3FB42449C0000000, 0x3FB4480880000000, 0x3FB46BE2E0000000, 0x3FB48FD900000000, 0x3FB4B3EB40000000, 0x3FB4D819A0000000, 0x3FB4FC6480000000, 0x3FB520CBC0000000, 0x3FB5454FE0000000, 0x3FB569F0C0000000, 0x3FB58EAEC0000000, 0x3FB5B38A00000000, 0x3FB5D882C0000000, 0x3FB5FD9900000000, 0x3FB622CD20000000, 0x3FB6481F40000000, 0x3FB66D8F80000000, 0x3FB6931E40000000, 0x3FB6B8CB80000000, 0x3FB6DE9780000000, 0x3FB7048280000000, 0x3FB72A8CA0000000, 0x3FB750B600000000, 0x3FB776FF20000000, 0x3FB79D67E0000000, 0x3FB7C3F0C0000000, 0x3FB7EA99A0000000, 0x3FB8116300000000, 0x3FB8384D00000000, 0x3FB85F57C0000000, 0x3FB88683A0000000, 0x3FB8ADD0A0000000, 0x3FB8D53F40000000, 0x3FB8FCCF80000000, 0x3FB92481A0000000, 0x3FB94C5600000000, 0x3FB9744CC0000000, 0x3FB99C6600000000, 0x3FB9C4A240000000, 0x3FB9ED0180000000, 0x3FBA158420000000, 0x3FBA3E2A60000000, 0x3FBA66F460000000, 0x3FBA8FE260000000, 0x3FBAB8F4C0000000, 0x3FBAE22BC0000000, 0x3FBB0B8780000000, 0x3FBB350860000000, 0x3FBB5EAE80000000, 0x3FBB887A60000000, 0x3FBBB26C00000000, 0x3FBBDC83E0000000, 0x3FBC06C200000000, 0x3FBC312700000000, 0x3FBC5BB2E0000000, 0x3FBC866600000000, 0x3FBCB140A0000000, 0x3FBCDC4320000000, 0x3FBD076DA0000000, 0x3FBD32C0A0000000, 0x3FBD5E3C40000000, 0x3FBD89E0E0000000, 0x3FBDB5AEE0000000, 0x3FBDE1A680000000, 0x3FBE0DC7E0000000, 0x3FBE3A13A0000000, 0x3FBE6689E0000000, 0x3FBE932B00000000, 0x3FBEBFF760000000, 0x3FBEECEF20000000, 0x3FBF1A12C0000000, 0x3FBF4762A0000000, 0x3FBF74DF00000000, 0x3FBFA28840000000, 0x3FBFD05EC0000000, 0x3FBFFE62C0000000, 0x3FC0164A60000000, 0x3FC02D7A80000000, 0x3FC044C1E0000000, 0x3FC05C20E0000000, 0x3FC0739780000000, 0x3FC08B2600000000, 0x3FC0A2CCA0000000, 0x3FC0BA8B60000000, 0x3FC0D262C0000000, 0x3FC0EA52C0000000, 0x3FC1025B80000000, 0x3FC11A7D60000000, 0x3FC132B880000000, 0x3FC14B0D20000000, 0x3FC1637B60000000, 0x3FC17C03A0000000, 0x3FC194A5E0000000, 0x3FC1AD6280000000, 0x3FC1C639C0000000, 0x3FC1DF2BA0000000, 0x3FC1F838A0000000, 0x3FC21160C0000000, 0x3FC22AA460000000, 0x3FC24403C0000000, 0x3FC25D7F00000000, 0x3FC2771660000000, 0x3FC290CA40000000, 0x3FC2AA9AC0000000, 0x3FC2C48840000000, 0x3FC2DE92C0000000, 0x3FC2F8BAE0000000, 0x3FC3130080000000, 0x3FC32D6440000000, 0x3FC347E620000000, 0x3FC3628680000000, 0x3FC37D45A0000000, 0x3FC39823E0000000, 0x3FC3B32160000000, 0x3FC3CE3EA0000000, 0x3FC3E97BA0000000, 0x3FC404D8E0000000, 0x3FC42056C0000000, 0x3FC43BF540000000, 0x3FC457B500000000, 0x3FC4739620000000, 0x3FC48F98E0000000, 0x3FC4ABBDE0000000, 0x3FC4C80520000000, 0x3FC4E46F20000000, 0x3FC500FC40000000, 0x3FC51DACA0000000, 0x3FC53A80E0000000, 0x3FC5577920000000, 0x3FC57495E0000000, 0x3FC591D760000000, 0x3FC5AF3E00000000, 0x3FC5CCCA40000000, 0x3FC5EA7C60000000, 0x3FC60854C0000000, 0x3FC62653C0000000, 0x3FC6447A00000000, 0x3FC662C7A0000000, 0x3FC6813D20000000, 0x3FC69FDAE0000000, 0x3FC6BEA160000000, 0x3FC6DD9100000000, 0x3FC6FCAA40000000, 0x3FC71BED60000000, 0x3FC73B5B20000000, 0x3FC75AF3A0000000, 0x3FC77AB780000000, 0x3FC79AA740000000, 0x3FC7BAC360000000, 0x3FC7DB0C40000000, 0x3FC7FB8260000000, 0x3FC81C2640000000, 0x3FC83CF860000000, 0x3FC85DF960000000, 0x3FC87F29C0000000, 0x3FC8A089E0000000, 0x3FC8C21A60000000, 0x3FC8E3DBE0000000, 0x3FC905CF00000000, 0x3FC927F420000000, 0x3FC94A4BE0000000, 0x3FC96CD6E0000000, 0x3FC98F95C0000000, 0x3FC9B28920000000, 0x3FC9D5B180000000, 0x3FC9F90FC0000000, 0x3FCA1CA440000000, 0x3FCA406FC0000000, 0x3FCA647300000000, 0x3FCA88AEA0000000, 0x3FCAAD2360000000, 0x3FCAD1D1E0000000, 0x3FCAF6BAE0000000, 0x3FCB1BDF00000000, 0x3FCB413F20000000, 0x3FCB66DC20000000, 0x3FCB8CB680000000, 0x3FCBB2CF40000000, 0x3FCBD92720000000, 0x3FCBFFBEE0000000, 0x3FCC269760000000, 0x3FCC4DB180000000, 0x3FCC750E40000000, 0x3FCC9CAE40000000, 0x3FCCC492A0000000, 0x3FCCECBC40000000, 0x3FCD152BE0000000, 0x3FCD3DE2C0000000, 0x3FCD66E1C0000000, 0x3FCD9029E0000000, 0x3FCDB9BC20000000, 0x3FCDE39980000000, 0x3FCE0DC340000000, 0x3FCE383A40000000, 0x3FCE62FFE0000000, 0x3FCE8E1500000000, 0x3FCEB97AE0000000, 0x3FCEE532C0000000, 0x3FCF113DE0000000, 0x3FCF3D9D60000000, 0x3FCF6A52A0000000, 0x3FCF975EE0000000, 0x3FCFC4C380000000, 0x3FCFF281C0000000, 0x3FD0104DA0000000, 0x3FD0278880000000, 0x3FD03EF280000000, 0x3FD0568C40000000, 0x3FD06E5680000000, 0x3FD0865200000000, 0x3FD09E7FA0000000, 0x3FD0B6E040000000, 0x3FD0CF74A0000000, 0x3FD0E83DA0000000, 0x3FD1013C20000000, 0x3FD11A7100000000, 0x3FD133DD60000000, 0x3FD14D8200000000, 0x3FD1676000000000, 0x3FD1817860000000, 0x3FD19BCC00000000, 0x3FD1B65C20000000, 0x3FD1D129C0000000, 0x3FD1EC3600000000, 0x3FD2078200000000, 0x3FD2230F20000000, 0x3FD23EDE60000000, 0x3FD25AF100000000, 0x3FD2774880000000, 0x3FD293E600000000, 0x3FD2B0CB00000000, 0x3FD2CDF8E0000000, 0x3FD2EB7100000000, 0x3FD3093500000000, 0x3FD3274640000000, 0x3FD345A680000000, 0x3FD3645740000000, 0x3FD3835A40000000, 0x3FD3A2B120000000, 0x3FD3C25DE0000000, 0x3FD3E26240000000, 0x3FD402C040000000, 0x3FD42379A0000000, 0x3FD44490C0000000, 0x3FD4660760000000, 0x3FD487E000000000, 0x3FD4AA1CA0000000, 0x3FD4CCBFE0000000, 0x3FD4EFCBE0000000, 0x3FD5134360000000, 0x3FD53728E0000000, 0x3FD55B7F20000000, 0x3FD58048E0000000, 0x3FD5A58900000000, 0x3FD5CB4280000000, 0x3FD5F178A0000000, 0x3FD6182E80000000, 0x3FD63F67A0000000, 0x3FD6672780000000, 0x3FD68F71C0000000, 0x3FD6B84A40000000, 0x3FD6E1B4E0000000, 0x3FD70BB5C0000000, 0x3FD7365160000000, 0x3FD7618C20000000, 0x3FD78D6AC0000000, 0x3FD7B9F240000000, 0x3FD7E727A0000000, 0x3FD8151060000000, 0x3FD843B200000000, 0x3FD87312A0000000, 0x3FD8A33860000000, 0x3FD8D429C0000000, 0x3FD905EDA0000000, 0x3FD9388B20000000, 0x3FD96C09E0000000, 0x3FD9A071C0000000, 0x3FD9D5CB40000000, 0x3FDA0C1F20000000, 0x3FDA4376E0000000, 0x3FDA7BDC60000000, 0x3FDAB55A00000000, 0x3FDAEFFAE0000000, 0x3FDB2BCAC0000000, 0x3FDB68D640000000, 0x3FDBA72A60000000, 0x3FDBE6D580000000, 0x3FDC27E6A0000000, 0x3FDC6A6DC0000000, 0x3FDCAE7C40000000, 0x3FDCF42440000000, 0x3FDD3B79A0000000, 0x3FDD8491A0000000, 0x3FDDCF8300000000, 0x3FDE1C6640000000, 0x3FDE6B5600000000, 0x3FDEBC6F00000000, 0x3FDF0FD040000000, 0x3FDF659BA0000000, 0x3FDFBDF620000000, 0x3FE00C8400000000, 0x3FE03B7EA0000000, 0x3FE06C0320000000, 0x3FE09E2C60000000, 0x3FE0D217A0000000, 0x3FE107E5C0000000, 0x3FE13FBB20000000, 0x3FE179C060000000, 0x3FE1B62340000000, 0x3FE1F51720000000, 0x3FE236D660000000, 0x3FE27BA3A0000000, 0x3FE2C3CAE0000000, 0x3FE30FA420000000, 0x3FE35F9560000000, 0x3FE3B416A0000000, 0x3FE40DB4E0000000, 0x3FE46D1900000000, 0x3FE4D30EA0000000, 0x3FE5408E80000000, 0x3FE5B6CD00000000, 0x3FE6374F20000000, 0x3FE6C408A0000000, 0x3FE75F8B60000000, 0x3FE80D50E0000000, 0x3FE8D23740000000, 0x3FE9B55BE0000000, 0x3FEAC1C0A0000000, 0x3FEC09C720000000, 0x3FEDAFBBC0000000, 0x3FF0000000000000 };
2278 
2282  static uint64_t reverseconcaveLUT[512] = { 0x0, 0x3F861DE634288F06, 0x3F95FF72EB93B40D, 0x3FA068E9A6C42F3E, 0x3FA5C333990D3199, 0x3FAB0EC05385D1FD, 0x3FB025DC360B2CDB, 0x3FB2BD220472BF0F, 0x3FB54D4570C60DD3, 0x3FB7D65A2022D0D8, 0x3FBA5873818E9C2B, 0x3FBCD3A4CE8BD413, 0x3FBF48010BAD074C, 0x3FC0DACD84935995, 0x3FC20E42B1AFBB3E, 0x3FC33E6941BF5B9E, 0x3FC46B4A4FFCDFE7, 0x3FC594EEDE8FAB8B, 0x3FC6BB5FD6D0EC70, 0x3FC7DEA6098FE8AC, 0x3FC8FECA2F55906E, 0x3FCA1BD4E8A755B8, 0x3FCB35CEBE494C11, 0x3FCC4CC0217F921A, 0x3FCD60B16C4F071C, 0x3FCE71AAE1BD4E53, 0x3FCF7FB4AE1021F1, 0x3FD0456B7385FBEE, 0x3FD0C98CC618FCE6, 0x3FD14C42437EA975, 0x3FD1CD8FD58FEA41, 0x3FD24D795B5EF9E0, 0x3FD2CC02A9551128, 0x3FD3492F894FC1B9, 0x3FD3C503BABDFFC6, 0x3FD43F82F2BCDBD6, 0x3FD4B8B0DC33ED7A, 0x3FD5309117F16FB9, 0x3FD5A7273CC6101A, 0x3FD61C76D7A07120, 0x3FD690836BA860F3, 0x3FD703507259C530, 0x3FD774E15B9F3C90, 0x3FD7E5398DEC772A, 0x3FD8545C6658464B, 0x3FD8C24D38B66465, 0x3FD92F0F4FB0F621, 0x3FD99AA5ECE1C522, 0x3FDA051448EB3555, 0x3FDA6E5D9390F58A, 0x3FDAD684F3D06C10, 0x3FDB3D8D87F8E00E, 0x3FDBA37A65C36052, 0x3FDC084E9A6A6854, 0x3FDC6C0D2AC1441C, 0x3FDCCEB9134B33BD, 0x3FDD305548524F20, 0x3FDD90E4B5FE2ABF, 0x3FDDF06A406A3E08, 0x3FDE4EE8C3BC0C1A, 0x3FDEAC6314390F75, 0x3FDF08DBFE5C6949, 0x3FDF645646EC5524, 0x3FDFBED4AB0F6177, 0x3FE00C2CF030B6DA, 0x3FE038744A843752, 0x3FE06441B7E47CC4, 0x3FE08F96880D4B54, 0x3FE0BA74071DEDF8, 0x3FE0E4DB7DA32817, 0x3FE10ECE30A10BC7, 0x3FE1384D619CB4F4, 0x3FE1615A4EA5E9C0, 0x3FE189F63260A056, 0x3FE1B222440E6A95, 0x3FE1D9DFB797C7B8, 0x3FE2012FBD955C61, 0x3FE2281383591142, 0x3FE24E8C32F7189D, 0x3FE2749AF34EDB00, 0x3FE29A40E813CB56, 0x3FE2BF7F31D622BD, 0x3FE2E456EE0B8449, 0x3FE308C9371788F9, 0x3FE32CD724543423, 0x3FE35081CA1A509F, 0x3FE373CA39C9B6E6, 0x3FE396B181D17C63, 0x3FE3B938ADB80C49, 0x3FE3DB60C6232A0A, 0x3FE3FD2AD0DFDDD5, 0x3FE41E97D0EA4B29, 0x3FE43FA8C67571F0, 0x3FE4605EAEF2DA27, 0x3FE480BA851A2A74, 0x3FE4A0BD40F0A9D3, 0x3FE4C067D7D0AC9A, 0x3FE4DFBB3C70ED06, 0x3FE4FEB85EEBCF91, 0x3FE51D602CC69343, 0x3FE53BB390F86E3F, 0x3FE559B373F196AE, 0x3FE57760BBA23855, 0x3FE594BC4B8156FF, 0x3FE5B1C704939DF3, 0x3FE5CE81C5721CA2, 0x3FE5EAED6A50F0D2, 0x3FE6070ACD05DE68, 0x3FE622DAC50ED512, 0x3FE63E5E279863EC, 0x3FE65995C7841B79, 0x3FE67482756EDDEF, 0x3FE68F24FFB71E33, 0x3FE6A97E32830D99, 0x3FE6C38ED7C6B8A6, 0x3FE6DD57B74A12F7, 0x3FE6F6D996AEF284, 0x3FE710153976FA73, 0x3FE7290B6109758E, 0x3FE741BCCCB920AD, 0x3FE75A2A39C9E525, 0x3FE772546376836A, 0x3FE78A3C02F62E2F, 0x3FE7A1E1CF8215F7, 0x3FE7B9467E5AE576, 0x3FE7D06AC2CE2ED3, 0x3FE7E74F4E3BC9F2, 0x3FE7FDF4D01B23FF, 0x3FE8145BF6008052, 0x3FE82A856BA22ADD, 0x3FE84071DADD9C52, 0x3FE85621EBBC9014, 0x3FE86B96447A0C32, 0x3FE880CF89875B81, 0x3FE895CE5D90FA07, 0x3FE8AA93618373CF, 0x3FE8BF1F3490365F, 0x3FE8D372743254E0, 0x3FE8E78DBC333F2C, 0x3FE8FB71A6AF6BD6, 0x3FE90F1ECC1AF572, 0x3FE92295C3462B08, 0x3FE935D721621410, 0x3FE948E37A04E7EF, 0x3FE95BBB5F2E7932, 0x3FE96E5F614C9495, 0x3FE980D00F3F540A, 0x3FE9930DF65D65CB, 0x3FE9A519A27847B2, 0x3FE9B6F39DE076E2, 0x3FE9C89C716993EB, 0x3FE9DA14A46E7B8A, 0x3FE9EB5CBCD55416, 0x3FE9FC753F138FD7, 0x3FEA0D5EAE31E440, 0x3FEA1E198BD03649, 0x3FEA2EA658297BFA, 0x3FEA3F0592179342, 0x3FEA4F37B7170E3E, 0x3FEA5F3D434AF50A, 0x3FEA6F16B1807D3E, 0x3FEA7EC47B32B727, 0x3FEA8E47188E30EB, 0x3FEA9D9F00748F98, 0x3FEAACCCA8801E5F, 0x3FEABBD0850753F7, 0x3FEACAAB09204E48, 0x3FEAD95CA6A44491, 0x3FEAE7E5CE32EFFB, 0x3FEAF646EF35EADA, 0x3FEB048077E4069F, 0x3FEB1292D544989A, 0x3FEB207E7332BDA6, 0x3FEB2E43BC6094D4, 0x3FEB3BE31A5A7144, 0x3FEB495CF58A0312, 0x3FEB56B1B53977AE, 0x3FEB63E1BF969188, 0x3FEB70ED79B5B73C, 0x3FEB7DD54794FA51, 0x3FEB8A998C1F15A4, 0x3FEB973AA92E6392, 0x3FEBA3B8FF8FCC00, 0x3FEBB014EF05AA45, 0x3FEBBC4ED64AAB2C, 0x3FEBC8671314A300, 0x3FEBD45E02175BD2, 0x3FEBE033FF075C00, 0x3FEBEBE9649CA51D, 0x3FEBF77E8C956B45, 0x3FEC02F3CFB8C4F6, 0x3FEC0E4985D95389, 0x3FEC198005D7E453, 0x3FEC2497A5A60A87, 0x3FEC2F90BA48B1F7, 0x3FEC3A6B97DAAAB9, 0x3FEC4528918F2DC7, 0x3FEC4FC7F9B45ABA, 0x3FEC5A4A21B5AE9A, 0x3FEC64AF5A1E73F7, 0x3FEC6EF7F29C2C39, 0x3FEC79243A00F25C, 0x3FEC83347E45D711, 0x3FEC8D290C8D3661, 0x3FEC9702312506E4, 0x3FECA0C03789229D, 0x3FECAA636A658987, 0x3FECB3EC13989DED, 0x3FECBD5A7C355A9B, 0x3FECC6AEEC8582F0, 0x3FECCFE9AC0BCCF9, 0x3FECD90B01860580, 0x3FECE21332EF2E4E, 0x3FECEB0285819688, 0x3FECF3D93DB8ED4A, 0x3FECFC979F544E8E, 0x3FED053DED584A75, 0x3FED0DCC6A10E6E9, 0x3FED164357139BCD, 0x3FED1EA2F54149A3, 0x3FED26EB84C82AD5, 0x3FED2F1D4525BFA7, 0x3FED37387528B4D2, 0x3FED3F3D52F2C4F1, 0x3FED472C1BFA94B3, 0x3FED4F050D0D89FD, 0x3FED56C862519DEB, 0x3FED5E76574729D8, 0x3FED660F26CAAF6F, 0x3FED6D930B169BD3, 0x3FED75023DC505E8, 0x3FED7C5CF7D167D9, 0x3FED83A3719A53D5, 0x3FED8AD5E2E32421, 0x3FED91F482D5A67F, 0x3FED98FF8803C2FA, 0x3FED9FF728691E2F, 0x3FEDA6DB996CB70D, 0x3FEDADAD0FE28029, 0x3FEDB46BC00CF4A4, 0x3FEDBB17DD9EA8B9, 0x3FEDC1B19BBBD5FC, 0x3FEDC8392CFBE35C, 0x3FEDCEAEC36AE8E2, 0x3FEDD512908B2F48, 0x3FEDDB64C556AB7D, 0x3FEDE1A5924075FA, 0x3FEDE7D527363E28, 0x3FEDEDF3B3A1B9B7, 0x3FEDF401666A1003, 0x3FEDF9FE6DF5419C, 0x3FEDFFEAF8298BDF, 0x3FEE05C7326EC8C8, 0x3FEE0B9349AFCAFA, 0x3FEE114F6A5BB601, 0x3FEE16FBC06752E8, 0x3FEE1C98774E6123, 0x3FEE2225BA14E3D8, 0x3FEE27A3B3486B93, 0x3FEE2D128D015C6D, 0x3FEE327270E430B3, 0x3FEE37C38822B817, 0x3FEE3D05FB7D5366, 0x3FEE4239F3442CEA, 0x3FEE475F97586D64, 0x3FEE4C770F2D6DB4, 0x3FEE518081C9E53D, 0x3FEE567C15C91503, 0x3FEE5B69F15BEF94, 0x3FEE604A3A4A3DC3, 0x3FEE651D15F3C039, 0x3FEE69E2A9514DEC, 0x3FEE6E9B18F5EF81, 0x3FEE7346890FF7A3, 0x3FEE77E51D6A184B, 0x3FEE7C76F96C7526, 0x3FEE80FC401DB2E4, 0x3FEE8575142403BE, 0x3FEE89E197C63100, 0x3FEE8E41ECECA1C9, 0x3FEE929635225EE8, 0x3FEE96DE919613FA, 0x3FEE9B1B231B0DBF, 0x3FEE9F4C0A2A35B3, 0x3FEEA37166E30AEF, 0x3FEEA78B590C9862, 0x3FEEAB9A00166865, 0x3FEEAF9D7B1975A7, 0x3FEEB395E8D9198C, 0x3FEEB78367C3F7F6, 0x3FEEBB6615F4E887, 0x3FEEBF3E1133DD5B, 0x3FEEC30B76F6C754, 0x3FEEC6CE646277E1, 0x3FEECA86F64B8065, 0x3FEECE3549370F2C, 0x3FEED1D9795BCA06, 0x3FEED573A2A2A68A, 0x3FEED903E0A7BFFD, 0x3FEEDC8A4EBB2AF4, 0x3FEEE00707E1C6AE, 0x3FEEE37A26D60C25, 0x3FEEE6E3C608DAF4, 0x3FEEEA43FFA243FC, 0x3FEEED9AED8251DD, 0x3FEEF0E8A941CF53, 0x3FEEF42D4C330B5C, 0x3FEEF768EF629B53, 0x3FEEFA9BAB981AED, 0x3FEEFDC59956EA2A, 0x3FEF00E6D0DEE934, 0x3FEF03FF6A2D3240, 0x3FEF070F7CFCD164, 0x3FEF0A1720C77A88, 0x3FEF0D166CC63D4B, 0x3FEF100D77F23702, 0x3FEF12FC590542D3, 0x3FEF15E3267AA7DE, 0x3FEF18C1F68FC596, 0x3FEF1B98DF44BE2E, 0x3FEF1E67F65D1F41, 0x3FEF212F5160889F, 0x3FEF23EF059B5153, 0x3FEF26A7281F2ADF, 0x3FEF2957CDC3C2BE, 0x3FEF2C010B276222, 0x3FEF2EA2F4AF8BFB, 0x3FEF313D9E89994E, 0x3FEF33D11CAB53DD, 0x3FEF365D82D38F23, 0x3FEF38E2E48ABFA9, 0x3FEF3B61552390C3, 0x3FEF3DD8E7BB78A7, 0x3FEF4049AF3B4AEF, 0x3FEF42B3BE57C98D, 0x3FEF451727923426, 0x3FEF4773FD38D5EC, 0x3FEF49CA516791EB, 0x3FEF4C1A36086DD6, 0x3FEF4E63BCD41B57, 0x3FEF50A6F7527FE0, 0x3FEF52E3F6DB3B10, 0x3FEF551ACC962B97, 0x3FEF574B897BF2BB, 0x3FEF59763E567668, 0x3FEF5B9AFBC161E4, 0x3FEF5DB9D22AA514, 0x3FEF5FD2D1D2F26E, 0x3FEF61E60ACE3B87, 0x3FEF63F38D042C57, 0x3FEF65FB6830A517, 0x3FEF67FDABE432E0, 0x3FEF69FA678486F7, 0x3FEF6BF1AA4CECCE, 0x3FEF6DE3834EBEC4, 0x3FEF6FD00171D9A6, 0x3FEF71B733750EEB, 0x3FEF739927EE95B8, 0x3FEF7575ED4C7AB1, 0x3FEF774D91D50E91, 0x3FEF792023A75393, 0x3FEF7AEDB0BB69AF, 0x3FEF7CB646E2F9AA, 0x3FEF7E79F3C99F08, 0x3FEF8038C4F550C8, 0x3FEF81F2C7C6C914, 0x3FEF83A80979EBC8, 0x3FEF855897262BE0, 0x3FEF87047DBEEFD3, 0x3FEF88ABCA13F4D1, 0x3FEF8A4E88D1B0FD, 0x3FEF8BECC681B48A, 0x3FEF8D868F8B09D7, 0x3FEF8F1BF032947E, 0x3FEF90ACF49B6F5D, 0x3FEF9239A8C7499F, 0x3FEF93C21896C2C2, 0x3FEF95464FC9C5A0, 0x3FEF96C659FFE27F, 0x3FEF984242B8A826, 0x3FEF99BA1553FC00, 0x3FEF9B2DDD12714C, 0x3FEF9C9DA5159F59, 0x3FEF9E09786076D9, 0x3FEF9F7161D79648, 0x3FEFA0D56C419D67, 0x3FEFA235A2477FD8, 0x3FEFA3920E74D6D0, 0x3FEFA4EABB3831EC, 0x3FEFA63FB2E36724, 0x3FEFA790FFABE1E9, 0x3FEFA8DEABAAF15C, 0x3FEFAA28C0DE15BD, 0x3FEFAB6F49274CFA, 0x3FEFACB24E4D5E71, 0x3FEFADF1D9FC25DC, 0x3FEFAF2DF5C4DD73, 0x3FEFB066AB1E6742, 0x3FEFB19C036595B2, 0x3FEFB2CE07DD734E, 0x3FEFB3FCC1AF89BD, 0x3FEFB52839EC2800, 0x3FEFB650798AA7E6, 0x3FEFB7758969B2CA, 0x3FEFB897724F858B, 0x3FEFB9B63CEA33CF, 0x3FEFBAD1F1CFEA89, 0x3FEFBBEA997F31CE, 0x3FEFBD003C5F2DE8, 0x3FEFBE12E2BFDFC4, 0x3FEFBF2294DA64A8, 0x3FEFC02F5AD13538, 0x3FEFC1393CB063D2, 0x3FEFC240426DDA3A, 0x3FEFC34473E9969C, 0x3FEFC445D8EDE7EF, 0x3FEFC544792FA9A4, 0x3FEFC6405C4E7EB8, 0x3FEFC73989D50C2A, 0x3FEFC830093932BD, 0x3FEFC923E1DC4832, 0x3FEFCA151B0B4FD1, 0x3FEFCB03BBFF3264, 0x3FEFCBEFCBDCF58D, 0x3FEFCCD951B5F293, 0x3FEFCDC054880C7D, 0x3FEFCEA4DB3DE5BD, 0x3FEFCF86ECAF1523, 0x3FEFD0668FA05A58, 0x3FEFD143CAC3D1BB, 0x3FEFD21EA4B927B4, 0x3FEFD2F7240DCB7B, 0x3FEFD3CD4F3D214E, 0x3FEFD4A12CB0B420, 0x3FEFD572C2C066C1, 0x3FEFD64217B2A47C, 0x3FEFD70F31BC912D, 0x3FEFD7DA170238DA, 0x3FEFD8A2CD96BEC1, 0x3FEFD9695B7C8BEA, 0x3FEFDA2DC6A57D32, 0x3FEFDAF014F310E1, 0x3FEFDBB04C3693BB, 0x3FEFDC6E72314D94, 0x3FEFDD2A8C94AD74, 0x3FEFDDE4A1027533, 0x3FEFDE9CB50CE4A3, 0x3FEFDF52CE36E44A, 0x3FEFE006F1F42F9D, 0x3FEFE0B925A97EC6, 0x3FEFE1696EACB002, 0x3FEFE217D244F082, 0x3FEFE2C455AAE4DD, 0x3FEFE36EFE08D11D, 0x3FEFE417D07AC049, 0x3FEFE4BED20EABA0, 0x3FEFE56407C4A144, 0x3FEFE607768EEA9E, 0x3FEFE6A92352323C, 0x3FEFE74912E5A959, 0x3FEFE7E74A132CF2, 0x3FEFE883CD976A81, 0x3FEFE91EA2220442, 0x3FEFE9B7CC55B529, 0x3FEFEA4F50C8745F, 0x3FEFEAE534039872, 0x3FEFEB797A83FA12, 0x3FEFEC0C28BA167E, 0x3FEFEC9D430A3183, 0x3FEFED2CCDCC772D, 0x3FEFEDBACD4D1D0F, 0x3FEFEE4745CC8333, 0x3FEFEED23B7F54B2, 0x3FEFEF5BB28EA7F3, 0x3FEFEFE3AF181E89, 0x3FEFF06A352E04C1, 0x3FEFF0EF48D770D9, 0x3FEFF172EE1061DE, 0x3FEFF1F528C9DE33, 0x3FEFF275FCEA11CA, 0x3FEFF2F56E4C6C09, 0x3FEFF37380C1BD52, 0x3FEFF3F03810544C, 0x3FEFF46B97F41ACB, 0x3FEFF4E5A41EB271, 0x3FEFF55E603790FC, 0x3FEFF5D5CFDC1C4D, 0x3FEFF64BF69FC618, 0x3FEFF6C0D80C274C, 0x3FEFF73477A11B37, 0x3FEFF7A6D8D4DA4F, 0x3FEFF817FF1414C3, 0x3FEFF887EDC20CB7, 0x3FEFF8F6A838B039, 0x3FEFF96431C8B2F4, 0x3FEFF9D08DB9A79B, 0x3FEFFA3BBF4A1906, 0x3FEFFAA5C9AFA312, 0x3FEFFB0EB0170B41, 0x3FEFFB7675A45905, 0x3FEFFBDD1D72EDDB, 0x3FEFFC42AA959D19, 0x3FEFFCA72016C377, 0x3FEFFD0A80F85E67, 0x3FEFFD6CD034231D, 0x3FEFFDCE10BB955B, 0x3FEFFE2E45781E09, 0x3FEFFE8D714B217B, 0x3FEFFEEB970E158D, 0x3FEFFF48B992977A, 0x3FEFFFA4DBA28173, 0x3FF0000000000000 };
2283 
2287  static uint64_t convexLUT[512] = { 0x0, 0x3FB2822A7CC37D8D, 0x3FBFB1CF9E824103, 0x3FC4F901E8A698B8, 0x3FC92A94BE9D4F66, 0x3FCCB727636A0498, 0x3FCFCAC0B9947039, 0x3FD140EB812E6589, 0x3FD277F0D31D94D6, 0x3FD39163E675CA3C, 0x3FD4926819A1D19A, 0x3FD57EE53381135E, 0x3FD659E4E9B75C07, 0x3FD725D022782DEF, 0x3FD7E498722A7473, 0x3FD897D50605CD27, 0x3FD940D74BBC9DE8, 0x3FD9E0BA0444DA3E, 0x3FDA786C796F67D5, 0x3FDB08BAF7D0C66C, 0x3FDB92555037B921, 0x3FDC15D3E730545D, 0x3FDC93BBB1024244, 0x3FDD0C815D9E9E61, 0x3FDD808BE56E26DA, 0x3FDDF0369B03AAAD, 0x3FDE5BD2DC8C453D, 0x3FDEC3A9793F2ACF, 0x3FDF27FBDA409FAB, 0x3FDF8904FAE02449, 0x3FDFE6FA3974C27D, 0x3FE02106040DF61E, 0x3FE04D33418D5FEB, 0x3FE07818F8BB8078, 0x3FE0A1C999BAE7F5, 0x3FE0CA5610FCC896, 0x3FE0F1CDF09530B5, 0x3FE1183F9431F140, 0x3FE13DB84084B2F9, 0x3FE162443ECCB6F1, 0x3FE185EEF50FA96D, 0x3FE1A8C2FB795264, 0x3FE1CACA2F46A9D3, 0x3FE1EC0DC391079E, 0x3FE20C9650411F98, 0x3FE22C6BDF66B091, 0x3FE24B95F928D4AB, 0x3FE26A1BAE7B632A, 0x3FE28803A2BF8BF2, 0x3FE2A55414708B4C, 0x3FE2C212E4F8DD55, 0x3FE2DE459FC88F6C, 0x3FE2F9F180C21575, 0x3FE3151B7A1049B7, 0x3FE32FC83975E3FB, 0x3FE349FC2D24AFC2, 0x3FE363BB88290CBA, 0x3FE37D0A4674C43F, 0x3FE395EC3092F275, 0x3FE3AE64DF0DA0F0, 0x3FE3C677BD8CB5E1, 0x3FE3DE280DB4FFE3, 0x3FE3F578E9CD6736, 0x3FE40C6D472FA596, 0x3FE42307F88952C1, 0x3FE4394BAFF1924D, 0x3FE44F3B00D73D5A, 0x3FE464D861CAFDE5, 0x3FE47A262E287846, 0x3FE48F26A7A1505F, 0x3FE4A3DBF7AC91D0, 0x3FE4B84830DCC3E9, 0x3FE4CC6D501EBAA1, 0x3FE4E04D3DE303CB, 0x3FE4F3E9CF33A3CB, 0x3FE50744C6B7ACCA, 0x3FE51A5FD5A617FE, 0x3FE52D3C9CA92899, 0x3FE53FDCACB382DB, 0x3FE5524187C80817, 0x3FE5646CA1B570E7, 0x3FE5765F60C689A9, 0x3FE5881B1E67E25C, 0x3FE599A127C3B16B, 0x3FE5AAF2BE5499A2, 0x3FE5BC11186FF4D7, 0x3FE5CCFD61C83849, 0x3FE5DDB8BBE7FBAC, 0x3FE5EE443EA6214D, 0x3FE5FEA0F89393D0, 0x3FE60ECFEF630546, 0x3FE61ED2204B130A, 0x3FE62EA880632A8D, 0x3FE63E53FCFB8442, 0x3FE64DD57BF083AC, 0x3FE65D2DDBF9C5DA, 0x3FE66C5DF4F52258, 0x3FE67B66982DDDBF, 0x3FE68A4890A04893, 0x3FE69904A33A0139, 0x3FE6A79B8F170BC3, 0x3FE6B60E0DBBEF0F, 0x3FE6C45CD34D0363, 0x3FE6D2888EC31BCB, 0x3FE6E091EA1DB0B9, 0x3FE6EE798A92AFD4, 0x3FE6FC4010BC12B7, 0x3FE709E618C35BEF, 0x3FE7176C3A8B17D1, 0x3FE724D309D67CA2, 0x3FE7321B166F4401, 0x3FE73F44EC49D5CA, 0x3FE74C5113A7DB29, 0x3FE7594011394F55, 0x3FE76612663C21E4, 0x3FE772C8909A7DAC, 0x3FE77F630B07C5E4, 0x3FE78BE24D1C5A39, 0x3FE79846CB703193, 0x3FE7A490F7B45A44, 0x3FE7B0C140CB6DAF, 0x3FE7BCD812E1047A, 0x3FE7C8D5D78037B9, 0x3FE7D4BAF5A93ACD, 0x3FE7E087D1E618F8, 0x3FE7EC3CCE5EA129, 0x3FE7F7DA4AEB89D1, 0x3FE80360A528D61E, 0x3FE80ED03887856D, 0x3FE81A295E5E954F, 0x3FE8256C6DFB5E10, 0x3FE83099BCB1512C, 0x3FE83BB19DE920E6, 0x3FE846B4632F57A8, 0x3FE851A25C426593, 0x3FE85C7BD7202A56, 0x3FE86741201300FD, 0x3FE871F281BE533A, 0x3FE87C90452AB94D, 0x3FE8871AB1D1AB82, 0x3FE891920DA8C9E7, 0x3FE89BF69D2CBEBD, 0x3FE8A648A36BBFD3, 0x3FE8B088620FB2D4, 0x3FE8BAB61967F869, 0x3FE8C4D20872E1CB, 0x3FE8CEDC6CE6D441, 0x3FE8D8D5833B1DDE, 0x3FE8E2BD86B07EAB, 0x3FE8EC94B1596937, 0x3FE8F65B3C21FD6F, 0x3FE900115ED7C089, 0x3FE909B75031148F, 0x3FE9134D45D47211, 0x3FE91CD3745F6661, 0x3FE9264A0F6D589D, 0x3FE92FB1499E17BF, 0x3FE93909549C33B3, 0x3FE9425261232393, 0x3FE94B8C9F053ABF, 0x3FE954B83D316EDB, 0x3FE95DD569B8F03E, 0x3FE966E451D496AE, 0x3FE96FE521EA23CB, 0x3FE978D805915CE9, 0x3FE981BD2798FDA4, 0x3FE98A94B20B84AE, 0x3FE9935ECE33DC26, 0x3FE99C1BA4A1DEC6, 0x3FE9A4CB5D2EBB26, 0x3FE9AD6E1F013633, 0x3FE9B6041091CE22, 0x3FE9BE8D57AEBECE, 0x3FE9C70A197FE8A8, 0x3FE9CF7A7A8A9B35, 0x3FE9D7DE9EB54400, 0x3FE9E036A94B0317, 0x3FE9E882BCFF25C3, 0x3FE9F0C2FBF08884, 0x3FE9F8F787ACE106, 0x3FEA01208133F0EE, 0x3FEA093E08FAA230, 0x3FEA11503EEE0DBA, 0x3FEA195742766D20, 0x3FEA21533279F7F6, 0x3FEA29442D5FAD83, 0x3FEA312A51120B6F, 0x3FEA3905BB01B203, 0x3FEA40D68827F68B, 0x3FEA489CD5096483, 0x3FEA5058BDB82DED, 0x3FEA580A5DD68B8D, 0x3FEA5FB1D0990D57, 0x3FEA674F30C8DBAF, 0x3FEA6EE298C5E9DF, 0x3FEA766C22891A4A, 0x3FEA7DEBE7A654AE, 0x3FEA8562014E8EFD, 0x3FEA8CCE8851C927, 0x3FEA94319520FC38, 0x3FEA9B8B3FCFFD30, 0x3FEAA2DBA01753EA, 0x3FEAAA22CD56067A, 0x3FEAB160DE93594B, 0x3FEAB895EA808457, 0x3FEABFC2077A5DC9, 0x3FEAC6E54B8AFA53, 0x3FEACDFFCC6B439C, 0x3FEAD5119F8484D9, 0x3FEADC1AD9F1EE20, 0x3FEAE31B90820E78, 0x3FEAEA13D7B8450F, 0x3FEAF103C3CE29CB, 0x3FEAF7EB68B4ED73, 0x3FEAFECADA16B1A9, 0x3FEB05A22B57D8F7, 0x3FEB0C716F984F26, 0x3FEB1338B9B4CA03, 0x3FEB19F81C4802E4, 0x3FEB20AFA9ABE912, 0x3FEB275F73FACD3D, 0x3FEB2E078D10863F, 0x3FEB34A8068B8F4E, 0x3FEB3B40F1CE1FD1, 0x3FEB41D25FFF3D01, 0x3FEB485C620BC57C, 0x3FEB4EDF08A776FC, 0x3FEB555A644DEE51, 0x3FEB5BCE8543A1C8, 0x3FEB623B7B96D622, 0x3FEB68A157208E48, 0x3FEB6F00278575CD, 0x3FEB7557FC36C66F, 0x3FEB7BA8E47328BC, 0x3FEB81F2EF478FDF, 0x3FEB88362B9010DE, 0x3FEB8E72A7F8B53E, 0x3FEB94A872FE4945, 0x3FEB9AD79AEF25EE, 0x3FEBA1002DEBF6AA, 0x3FEBA72239E87B04, 0x3FEBAD3DCCAC444C, 0x3FEBB352F3D36F61, 0x3FEBB961BCCF5AA0, 0x3FEBBF6A34E75832, 0x3FEBC56C69395CAB, 0x3FEBCB6866BAAA2D, 0x3FEBD15E3A387815, 0x3FEBD74DF058974D, 0x3FEBDD37959A1353, 0x3FEBE31B3655D017, 0x3FEBE8F8DEBF24AC, 0x3FEBEED09AE472F0, 0x3FEBF4A276AFBC43, 0x3FEBFA6E7DE73345, 0x3FEC0034BC2DCAC8, 0x3FEC05F53D03C1F9, 0x3FEC0BB00BC72DD3, 0x3FEC116533B47FE8, 0x3FEC1714BFE70A9E, 0x3FEC1CBEBB5982D3, 0x3FEC226330E67F23, 0x3FEC28022B48F4A7, 0x3FEC2D9BB51CB170, 0x3FEC332FD8DED4A2, 0x3FEC38BEA0EE4461, 0x3FEC3E48178C2170, 0x3FEC43CC46DC38C5, 0x3FEC494B38E572F0, 0x3FEC4EC4F7924172, 0x3FEC54398CB10A1F, 0x3FEC59A901F49076, 0x3FEC5F1360F45D1C, 0x3FEC6478B32D2366, 0x3FEC69D902012519, 0x3FEC6F3456B89451, 0x3FEC748ABA81F3AA, 0x3FEC79DC367274B0, 0x3FEC7F28D386549B, 0x3FEC84709AA13767, 0x3FEC89B3948E814D, 0x3FEC8EF1CA01AEA1, 0x3FEC942B4396AA2E, 0x3FEC996009D2220A, 0x3FEC9E902521DAE3, 0x3FECA3BB9DDD01EA, 0x3FECA8E27C447D3F, 0x3FECAE04C8833B0A, 0x3FECB3228AAE7F25, 0x3FECB83BCAC62F82, 0x3FECBD5090B51F2D, 0x3FECC260E4515818, 0x3FECC76CCD5C639B, 0x3FECCC74538391C1, 0x3FECD1777E603F4D, 0x3FECD67655781AB3, 0x3FECDB70E03D67C2, 0x3FECE067260F4248, 0x3FECE5592E39DF8B, 0x3FECEA46FFF6CEB1, 0x3FECEF30A26D3814, 0x3FECF4161CB21B8D, 0x3FECF8F775C88DB0, 0x3FECFDD4B4A1F416, 0x3FED02ADE01E4099, 0x3FED0782FF0C2BA7, 0x3FED0C5418296D96, 0x3FED11213222F718, 0x3FED15EA539528B6, 0x3FED1AAF830C0973, 0x3FED1F70C7037C8B, 0x3FED242E25E7764F, 0x3FED28E7A6143032, 0x3FED2D9D4DD65C01, 0x3FED324F236B5645, 0x3FED36FD2D0157E1, 0x3FED3BA770B7A6E1, 0x3FED404DF49EC68C, 0x3FED44F0BEB8A6AE, 0x3FED498FD4F8D22E, 0x3FED4E2B3D449CDE, 0x3FED52C2FD7350A4, 0x3FED57571B4E59E4, 0x3FED5BE79C917342, 0x3FED607486EAD0B7, 0x3FED64FDDFFB49F8, 0x3FED6983AD56843D, 0x3FED6E05F4831B65, 0x3FED7284BAFACA77, 0x3FED7700062A9387, 0x3FED7B77DB72E703, 0x3FED7FEC4027CA67, 0x3FED845D3990FE5D, 0x3FED88CACCEA244D, 0x3FED8D34FF62E353, 0x3FED919BD61F0CBF, 0x3FED95FF5636BFF1, 0x3FED9A5F84B68DC0, 0x3FED9EBC669F9B4F, 0x3FEDA31600E7C46B, 0x3FEDA76C5879BD5D, 0x3FEDABBF72353446, 0x3FEDB00F52EEF1F8, 0x3FEDB45BFF70FA5A, 0x3FEDB8A57C7AAC51, 0x3FEDBCEBCEC0E139, 0x3FEDC12EFAEE0BDF, 0x3FEDC56F05A25712, 0x3FEDC9ABF373C3C4, 0x3FEDCDE5C8EE46B9, 0x3FEDD21C8A93E5CA, 0x3FEDD6503CDCD4C3, 0x3FEDDA80E43791D0, 0x3FEDDEAE8509018F, 0x3FEDE2D923AC8AB0, 0x3FEDE700C474313A, 0x3FEDEB256BA8B16D, 0x3FEDEF471D899A46, 0x3FEDF365DE4D679B, 0x3FEDF781B2219BE7, 0x3FEDFB9A9D2AD9B5, 0x3FEDFFB0A384FCAF, 0x3FEE03C3C9433256, 0x3FEE07D412701267, 0x3FEE0BE1830DB6E8, 0x3FEE0FEC1F15D3DE, 0x3FEE13F3EA79CEB5, 0x3FEE17F8E922D556, 0x3FEE1BFB1EF1F4E9, 0x3FEE1FFA8FC0304D, 0x3FEE23F73F5E9642, 0x3FEE27F131965743, 0x3FEE2BE86A28DB1D, 0x3FEE2FDCECCFD62F, 0x3FEE33CEBD3D5E74, 0x3FEE37BDDF1C0030, 0x3FEE3BAA560ED26B, 0x3FEE3F9425B18B1A, 0x3FEE437B51989307, 0x3FEE475FDD51197A, 0x3FEE4B41CC612798, 0x3FEE4F212247B38E, 0x3FEE52FDE27CB36A, 0x3FEE56D810712FC9, 0x3FEE5AAFAF8F5635, 0x3FEE5E84C33A8B56, 0x3FEE62574ECF7CDB, 0x3FEE662755A4332A, 0x3FEE69F4DB0822E1, 0x3FEE6DBFE2443E0D, 0x3FEE71886E9B0534, 0x3FEE754E83489820, 0x3FEE79122382C682, 0x3FEE7CD352792048, 0x3FEE8092135505D1, 0x3FEE844E6939B7E7, 0x3FEE880857446781, 0x3FEE8BBFE08C455E, 0x3FEE8F7508229159, 0x3FEE9327D112A9A8, 0x3FEE96D83E6219D2, 0x3FEE9A865310A983, 0x3FEE9E3212186B2A, 0x3FEEA1DB7E6DCA73, 0x3FEEA5829AFF9A83, 0x3FEEA9276AB72417, 0x3FEEACC9F078336B, 0x3FEEB06A2F2125FF, 0x3FEEB408298AF82C, 0x3FEEB7A3E289528A, 0x3FEEBB3D5CEA9738, 0x3FEEBED49B77EEEE, 0x3FEEC269A0F555F2, 0x3FEEC5FC7021A8DD, 0x3FEEC98D0BB6B13C, 0x3FEECD1B76693209, 0x3FEED0A7B2E8F3FD, 0x3FEED431C3E0D1C5, 0x3FEED7B9ABF6C3FE, 0x3FEEDB3F6DCBED23, 0x3FEEDEC30BFCA549, 0x3FEEE244892085BC, 0x3FEEE5C3E7CA7478, 0x3FEEE9412A88AF7B, 0x3FEEECBC53E4D804, 0x3FEEF0356663FD9B, 0x3FEEF3AC6486A905, 0x3FEEF72150C8E71C, 0x3FEEFA942DA25376, 0x3FEEFE04FD8622FC, 0x3FEF0173C2E32E58, 0x3FEF04E08023FC4D, 0x3FEF084B37AECBE3, 0x3FEF0BB3EBE59E86, 0x3FEF0F1A9F2641F6, 0x3FEF127F53CA5A2A, 0x3FEF15E20C276B07, 0x3FEF1942CA8EE208, 0x3FEF1CA1914E1FC3, 0x3FEF1FFE62AE814E, 0x3FEF235940F56994, 0x3FEF26B22E644A88, 0x3FEF2A092D38AE3A, 0x3FEF2D5E3FAC3FDA, 0x3FEF30B167F4D49F, 0x3FEF3402A8447492, 0x3FEF375202C96338, 0x3FEF3A9F79AE283C, 0x3FEF3DEB0F1997E2, 0x3FEF4134C52EDB7B, 0x3FEF447C9E0D79AC, 0x3FEF47C29BD15EB2, 0x3FEF4B06C092E47C, 0x3FEF4E490E66DAC1, 0x3FEF5189875E8EE6, 0x3FEF54C82D87D3F0, 0x3FEF580502ED0A39, 0x3FEF5B4009952734, 0x3FEF5E794383BD00, 0x3FEF61B0B2B901F4, 0x3FEF64E65931D813, 0x3FEF681A38E7D46B, 0x3FEF6B4C53D1465E, 0x3FEF6E7CABE13EDB, 0x3FEF71AB4307977E, 0x3FEF74D81B30F9A0, 0x3FEF78033646E554, 0x3FEF7B2C962FB84F, 0x3FEF7E543CCEB4BD, 0x3FEF817A2C040808, 0x3FEF849E65ACD180, 0x3FEF87C0EBA32905, 0x3FEF8AE1BFBE258D, 0x3FEF8E00E3D1E3A1, 0x3FEF911E59AF8BC5, 0x3FEF943A232558D5, 0x3FEF975441FE9E48, 0x3FEF9A6CB803CE6A, 0x3FEF9D8386FA807F, 0x3FEFA098B0A576DA, 0x3FEFA3AC36C4A4E6, 0x3FEFA6BE1B153517, 0x3FEFA9CE5F518ED1, 0x3FEFACDD05315C3F, 0x3FEFAFEA0E69901B, 0x3FEFB2F57CAC6B64, 0x3FEFB5FF51A98307, 0x3FEFB9078F0DC578, 0x3FEFBC0E36838041, 0x3FEFBF1349B26578, 0x3FEFC216CA3F9136, 0x3FEFC518B9CD8EEE, 0x3FEFC81919FC5EC8, 0x3FEFCB17EC697ADF, 0x3FEFCE1532AFDC7F, 0x3FEFD110EE680144, 0x3FEFD40B2127F042, 0x3FEFD703CC833F0F, 0x3FEFD9FAF20B16BF, 0x3FEFDCF0934E38E6, 0x3FEFDFE4B1D90478, 0x3FEFE2D74F357AA7, 0x3FEFE5C86CEB43B2, 0x3FEFE8B80C7FB3AD, 0x3FEFEBA62F75CF34, 0x3FEFEE92D74E5017, 0x3FEFF17E0587A9FE, 0x3FEFF467BB9E0EF9, 0x3FEFF74FFB0B7409, 0x3FEFFA36C54795A1, 0x3FEFFD1C1BC7FC14, 0x3FF0000000000000 };
2288 
2292  static uint64_t reverseconvexLUT[512] = { 0x0, 0x3F06C9175FA32C60, 0x3F16E8CDAD10AC81, 0x3F21468F1EA72923, 0x3F2728EB4DE855DE, 0x3F2D1BA87E1F7028, 0x3F318F7A23551FD1, 0x3F34997E5EE716EB, 0x3F37ABF83D0CC24D, 0x3F3AC6FF49E444B1, 0x3F3DEAAB5317370F, 0x3F408B8A34488E4F, 0x3F4226296E9BE843, 0x3F43C53FA3D2FA6E, 0x3F4568D94173B577, 0x3F471102D79BE93A, 0x3F48BDC91961912D, 0x3F4A6F38DD342A9B, 0x3F4C255F1D3F19A6, 0x3F4DE048F7CD2139, 0x3F4FA003AFACEF68, 0x3F50B24E564B60CB, 0x3F519710BDC991D2, 0x3F527E4FE7B16689, 0x3F536812C073CFB4, 0x3F54546047C76431, 0x3F55433F90DE0659, 0x3F5634B7C29B1DE2, 0x3F5728D017CA68EC, 0x3F581F8FDF5766C9, 0x3F5918FE7C855B0E, 0x3F5A15236727EE0C, 0x3F5B14062BDC6A5D, 0x3F5C15AE6C4399B2, 0x3F5D1A23DF3C436E, 0x3F5E216E511E4C4C, 0x3F5F2B95A3F67CDD, 0x3F601C50E7E1768E, 0x3F60A44D71580BF9, 0x3F612DC480AB4CC7, 0x3F61B8BA337CCC98, 0x3F624532B2E2F055, 0x3F62D3323388D1D5, 0x3F6362BCF5CE7C2D, 0x3F63F3D745E981CB, 0x3F6486857C05ED38, 0x3F651ACBFC678DC8, 0x3F65B0AF378BA083, 0x3F664833AA4AD6EA, 0x3F66E15DDDFBBD23, 0x3F677C3268957EAB, 0x3F6818B5ECD30CC5, 0x3F68B6ED1A56A65A, 0x3F6956DCADCDC2C9, 0x3F69F8897115610B, 0x3F6A9BF83B5EBAF5, 0x3F6B412DF1545FDD, 0x3F6BE82F853FB5DB, 0x3F6C9101F72EE339, 0x3F6D3BAA551B21EF, 0x3F6DE82DBB0F7D8C, 0x3F6E9691534FFCFE, 0x3F6F46DA56813957, 0x3F6FF90E0BD062CE, 0x3F705698E48DDA96, 0x3F70B1A5798DAE52, 0x3F710DAF7EC56680, 0x3F716AB9B5A94598, 0x3F71C8C6E75935AA, 0x3F7227D9E4B622A6, 0x3F7287F586778F49, 0x3F72E91CAD4166BE, 0x3F734B5241BA0AB4, 0x3F73AE9934A09ED9, 0x3F7412F47EE392A7, 0x3F74786721B76957, 0x3F74DEF426ADC1F0, 0x3F75469E9FCC9F1E, 0x3F75AF69A7A5EFA1, 0x3F761958616F589C, 0x3F76846DF91A41F3, 0x3F76F0ADA36C2591, 0x3F775E1A9E17226B, 0x3F77CCB82FD2D3DD, 0x3F783C89A8756E39, 0x3F78AD92610D2124, 0x3F791FD5BBF9C0DF, 0x3F7993572506B679, 0x3F7A081A118538C4, 0x3F7A7E220066CE09, 0x3F7AF5727A581763, 0x3F7B6E0F11DBE6EE, 0x3F7BE7FB6366A136, 0x3F7C633B1579EAE0, 0x3F7CDFD1D8C0A37E, 0x3F7D5DC3682B2E0C, 0x3F7DDD13890C0845, 0x3F7E5DC60B34B1BB, 0x3F7EDFDEC912E310, 0x3F7F6361A7CE16B3, 0x3F7FE852976563AC, 0x3F80375AC966D5F0, 0x3F807B4750080EF8, 0x3F80BFF0E8348600, 0x3F810559A0338C60, 0x3F814B838C055D6F, 0x3F819270C5730C30, 0x3F81DA236C1E9D2B, 0x3F82229DA5934D5E, 0x3F826BE19D56064D, 0x3F82B5F184F5FFD9, 0x3F8300CF941D907D, 0x3F834C7E08A32C50, 0x3F8398FF269A9345, 0x3F83E65538662F67, 0x3F8434828EC8A332, 0x3F84838980F688F3, 0x3F84D36C6CA8639A, 0x3F85242DB62CC158, 0x3F8575CFC87A90C4, 0x3F85C8551543A904, 0x3F861BC0150785B4, 0x3F867013472636BE, 0x3F86C55131F384E7, 0x3F871B7C62CA4BD4, 0x3F8772976E2009D7, 0x3F87CAA4EF98A61E, 0x3F8823A78A1A6DE6, 0x3F887DA1E7E24988, 0x3F88D896BA98299B, 0x3F893488BB63ACE6, 0x3F89917AAB00FFED, 0x3F89EF6F51D5F689, 0x3F8A4E6980076037, 0x3F8AAE6C0D8E97D8, 0x3F8B0F79DA4F4F5D, 0x3F8B7195CE2D9814, 0x3F8BD4C2D9242897, 0x3F8C3903F35AE056, 0x3F8C9E5C1D3D8A05, 0x3F8D04CE5F92DD3E, 0x3F8D6C5DCB93C080, 0x3F8DD50D7B02CB8A, 0x3F8E3EE090440B3E, 0x3F8EA9DA367507D9, 0x3F8F15FDA1850DEC, 0x3F8F834E0E4DBAEC, 0x3F8FF1CEC2ABCDED, 0x3F9030C186CC1EEC, 0x3F90693723A0CA96, 0x3F90A249E892CA23, 0x3F90DBFB8B158D9D, 0x3F91164DC55E2DD6, 0x3F9151425670A9C9, 0x3F918CDB022D48EA, 0x3F91C919915E2290, 0x3F9205FFD1C4CB25, 0x3F92438F96282771, 0x3F9281CAB6626647, 0x3F92C0B30F6F2119, 0x3F93004A8379A3EA, 0x3F934092F9EB5D12, 0x3F93818E5F7A7513, 0x3F93C33EA6388F05, 0x3F9405A5C5A1B240, 0x3F9448C5BAAB5D64, 0x3F948CA087D3C365, 0x3F94D138353132E5, 0x3F95168ED081A89E, 0x3F955CA66D3A8D13, 0x3F95A38124989DF1, 0x3F95EB2115B003E4, 0x3F963388657C9523, 0x3F967CB93EF24538, 0x3F96C6B5D30DC29D, 0x3F97118058E5427A, 0x3F975D1B0DB97B32, 0x3F97A9883506CE4D, 0x3F97F6CA1896A203, 0x3F9844E30890EB18, 0x3F9893D55B8DE78F, 0x3F98E3A36EA80AD6, 0x3F99344FA58E1BA6, 0x3F9985DC6A95844C, 0x3F99D84C2ECCD62D, 0x3F9A2BA16A0E8093, 0x3F9A7FDE9B13BBB3, 0x3F9AD5064787A82F, 0x3F9B2B1AFC1AA41C, 0x3F9B821F4C95D5A5, 0x3F9BDA15D3EEEC0D, 0x3F9C3301345C17CC, 0x3F9C8CE417683A2C, 0x3F9CE7C12E074D32, 0x3F9D439B30AB041D, 0x3F9DA074DF57A593, 0x3F9DFE5101B91FA0, 0x3F9E5D3267385686, 0x3F9EBD1BE710AEDA, 0x3F9F1E106065D373, 0x3F9F8012BA59B80D, 0x3F9FE325E422D954, 0x3FA023A66A915D4C, 0x3FA05645467E5125, 0x3FA0897109D64ACE, 0x3FA0BD2B3CCF4A38, 0x3FA0F1756BE30AC6, 0x3FA1265127DAE224, 0x3FA15BC005DBC047, 0x3FA191C39F7250BA, 0x3FA1C85D929F3DAB, 0x3FA1FF8F81E3951D, 0x3FA2375B144D50AC, 0x3FA26FC1F5840026, 0x3FA2A8C5D5D59758, 0x3FA2E2686A435F96, 0x3FA31CAB6C8F0D3D, 0x3FA357909B47F9A2, 0x3FA39319B9D881E0, 0x3FA3CF4890938ABE, 0x3FA40C1EECC22A4B, 0x3FA4499EA0B1778F, 0x3FA487C983C0808D, 0x3FA4C6A1726E6733, 0x3FA506284E68A584, 0x3FA5465FFE9979A5, 0x3FA5874A6F3679D9, 0x3FA5C8E991CF5114, 0x3FA60B3F5D5CA4CA, 0x3FA64E4DCE4F2400, 0x3FA69216E69EC05C, 0x3FA6D69CADDA1182, 0x3FA71BE13135E36B, 0x3FA761E6839CEFF4, 0x3FA7A8AEBDBFC420, 0x3FA7F03BFE24D1BB, 0x3FA838906938AD9E, 0x3FA881AE295E7B38, 0x3FA8CB976F0085D0, 0x3FA9164E70A107E2, 0x3FA961D56AEB2138, 0x3FA9AE2EA0C3FC67, 0x3FA9FB5C5B5C23C4, 0x3FAA4960EA4106B9, 0x3FAA983EA36EAFCA, 0x3FAAE7F7E361AC22, 0x3FAB388F0D2924B2, 0x3FAB8A068A7929B2, 0x3FABDC60CBBD314B, 0x3FAC2FA0482AC991, 0x3FAC83C77DD47E8B, 0x3FACD8D8F1BCF4C1, 0x3FAD2ED72FEA392C, 0x3FAD85C4CB7946CB, 0x3FADDDA45EB1C276, 0x3FAE36788B19EDC8, 0x3FAE9043F98AD17D, 0x3FAEEB095A449FEF, 0x3FAF46CB65035058, 0x3FAFA38CD913737C, 0x3FB000A83EB3A109, 0x3FB0300C9055F31F, 0x3FB05FF4CCAF7FE2, 0x3FB0906262F23249, 0x3FB0C156C64E0EB8, 0x3FB0F2D36DFC5029, 0x3FB124D9D54AA414, 0x3FB1576B7BA685B7, 0x3FB18A89E4A8B8F0, 0x3FB1BE369820E51E, 0x3FB1F2732221501C, 0x3FB22741130ABA3B, 0x3FB25CA1FF985AD7, 0x3FB2929780EBFEAE, 0x3FB2C923349A478F, 0x3FB30046BCB70E88, 0x3FB33803BFE1E82F, 0x3FB3705BE952CC06, 0x3FB3A950E8E6DEEC, 0x3FB3E2E4732D6153, 0x3FB41D184174C135, 0x3FB457EE11D7D0BB, 0x3FB49367A74B2160, 0x3FB4CF86C9AA8480, 0x3FB50C4D45C6B13B, 0x3FB549BCED7310A5, 0x3FB587D79793B013, 0x3FB5C69F202B5A60, 0x3FB606156869D872, 0x3FB6463C56BA5968, 0x3FB68715D6D202C1, 0x3FB6C8A3D9BEA952, 0x3FB70AE855F5B2E4, 0x3FB74DE547632193, 0x3FB7919CAF78C8AB, 0x3FB7D610953DAC54, 0x3FB81B43055D8B8A, 0x3FB86136123895B1, 0x3FB8A7EBD3F34BB5, 0x3FB8EF6668868D87, 0x3FB937A7F3CFD3FA, 0x3FB980B29FA19836, 0x3FB9CA889BD3E875, 0x3FBA152C1E552B27, 0x3FBA609F633B1091, 0x3FBAACE4ACD3B3C8, 0x3FBAF9FE43B6EB12, 0x3FBB47EE76D7C8DC, 0x3FBB96B79B964CF3, 0x3FBBE65C0DD14775, 0x3FBC36DE2FF86D1B, 0x3FBC88406B1E9E36, 0x3FBCDA852F0C6044, 0x3FBD2DAEF2528B28, 0x3FBD81C0325D2A28, 0x3FBDD6BB738691BD, 0x3FBE2CA3412AAA30, 0x3FBE837A2DBA7042, 0x3FBEDB42D2CFABC2, 0x3FBF33FFD140DD67, 0x3FBF8DB3D13563B0, 0x3FBFE8618239D84D, 0x3FC02205CDAA52EB, 0x3FC0505A6D8D6B8B, 0x3FC07F3003E28FFD, 0x3FC0AE87F7A290B6, 0x3FC0DE63B3AD73FB, 0x3FC10EC4A6D5534D, 0x3FC13FAC43E956E8, 0x3FC1711C01C0CFFF, 0x3FC1A3155B4671B3, 0x3FC1D599CF83A96F, 0x3FC208AAE1AC16BA, 0x3FC23C4A19292311, 0x3FC2707901A5B9DF, 0x3FC2A5392B1A2148, 0x3FC2DA8C29D7F3B6, 0x3FC3107396963AEE, 0x3FC346F10E7DACA8, 0x3FC37E0633350968, 0x3FC3B5B4AAED9D93, 0x3FC3EDFE206FE581, 0x3FC426E443285495, 0x3FC46068C7344014, 0x3FC49A8D656EEDB8, 0x3FC4D553DB7EC6DC, 0x3FC510BDEBE2B021, 0x3FC54CCD5DFF8681, 0x3FC58983FE2DC19E, 0x3FC5C6E39DC73C53, 0x3FC604EE1335235E, 0x3FC643A539FE0B06, 0x3FC6830AF2D42BD5, 0x3FC6C32123A3C707, 0x3FC703E9B7A1B2F2, 0x3FC745669F5A1015, 0x3FC78799D0BF26D9, 0x3FC7CA8547386F02, 0x3FC80E2B03B1C0A2, 0x3FC8528D0CAAAFA7, 0x3FC897AD6E4611D6, 0x3FC8DD8E3A59B050, 0x3FC92431887E2475, 0x3FC96B99761EE136, 0x3FC9B3C8268A68D0, 0x3FC9FCBFC302AFD5, 0x3FCA46827ACDADA4, 0x3FCA911283461B37, 0x3FCADC7217EC6041, 0x3FCB28A37A77AFC0, 0x3FCB75A8F2E753DA, 0x3FCBC384CF942A36, 0x3FCC1239654250A3, 0x3FCC61C90F330351, 0x3FCCB2362F36AC7A, 0x3FCD03832DBF2682, 0x3FCD55B279F230C0, 0x3FCDA8C689BC17E4, 0x3FCDFCC1D9E291F6, 0x3FCE51A6EE17CF35, 0x3FCEA778510DBFA9, 0x3FCEFE3894898EB4, 0x3FCF55EA51775488, 0x3FCFAE9027FDFEB7, 0x3FD004165FC9B800, 0x3FD0316163886C1C, 0x3FD05F2A7A63A258, 0x3FD08D73034A3512, 0x3FD0BC3C60FBD40F, 0x3FD0EB87FA13A3A0, 0x3FD11B573912F928, 0x3FD14BAB8C6C35B7, 0x3FD17C86668DBEA3, 0x3FD1ADE93DED14E3, 0x3FD1DFD58D120B19, 0x3FD2124CD2A21AF6, 0x3FD24550916BDA11, 0x3FD278E250728EB3, 0x3FD2AD039AF9E4CA, 0x3FD2E1B60091C399, 0x3FD316FB1522441E, 0x3FD34CD470F7C90C, 0x3FD38343B0CF3825, 0x3FD3BA4A75E255DC, 0x3FD3F1EA65F4432D, 0x3FD42A252B5E1E5C, 0x3FD462FC751BC6B9, 0x3FD49C71F6D8C419, 0x3FD4D68768FD51FE, 0x3FD5113E88BB8F57, 0x3FD54C99181CD2A4, 0x3FD58898DE0F2382, 0x3FD5C53FA672D978, 0x3FD6028F422860DE, 0x3FD64089871E25F1, 0x3FD67F30505EA6C9, 0x3FD6BE857E1EAC56, 0x3FD6FE8AF5CBAB18, 0x3FD73F42A21A4BAF, 0x3FD780AE73151C1F, 0x3FD7C2D05E2B69AB, 0x3FD805AA5E404456, 0x3FD8493E73B9ABE7, 0x3FD88D8EA48FE76E, 0x3FD8D29CFC5D0737, 0x3FD9186B8C6C9235, 0x3FD95EFC6BCB5EBF, 0x3FD9A651B75797BA, 0x3FD9EE6D91D0EE0B, 0x3FDA375223E8F76C, 0x3FDA81019C53BA84, 0x3FDACB7E2FD86955, 0x3FDB16CA196249FC, 0x3FDB62E79A11CEC3, 0x3FDBAFD8F94DDD78, 0x3FDBFDA084D5473C, 0x3FDC4C4090D0708D, 0x3FDC9BBB77E32AD4, 0x3FDCEC139B3EBF4E, 0x3FDD3D4B62B42C80, 0x3FDD8F653CC69613, 0x3FDDE2639EBDE870, 0x3FDE364904B9AFCE, 0x3FDE8B17F1C4240F, 0x3FDEE0D2EFE56953, 0x3FDF377C90370677, 0x3FDF8F176AF79159, 0x3FDFE7A61F9E924B, 0x3FE02095AA784F42, 0x3FE04DD4DC89D56D, 0x3FE07B9200D1CB59, 0x3FE0A9CE75E37845, 0x3FE0D88B9E21F9F0, 0x3FE107CADFCAE0FC, 0x3FE1378DA500EA9E, 0x3FE167D55BD6D86F, 0x3FE198A3765A6620, 0x3FE1C9F96A9F5DF2, 0x3FE1FBD8B2CACBD4, 0x3FE22E42CD1E4FD7, 0x3FE261393C038FF7, 0x3FE294BD8617C9F7, 0x3FE2C8D136378539, 0x3FE2FD75DB8A6555, 0x3FE332AD098F1D6D, 0x3FE36878582784EF, 0x3FE39ED963A4CDCB, 0x3FE3D5D1CCD3DCDA, 0x3FE40D633909C468, 0x3FE4458F523061B8, 0x3FE47E57C6D31D65, 0x3FE4B7BE4A2BCF86, 0x3FE4F1C4942FC76E, 0x3FE52C6C619CF7F2, 0x3FE567B774074821, 0x3FE5A3A791E60942, 0x3FE5E03E86A19213, 0x3FE61D7E22A1001D, 0x3FE65B683B581F21, 0x3FE699FEAB55776C, 0x3FE6D9435250830E, 0x3FE7193815380ADF, 0x3FE759DEDE40AB42, 0x3FE79B399CF3818C, 0x3FE7DD4A463D0207, 0x3FE82012D47BF783, 0x3FE863954790AC69, 0x3FE8A7D3A4EC3E38, 0x3FE8ECCFF7A01B77, 0x3FE9328C506DACFB, 0x3FE9790AC5D62A8F, 0x3FE9C04D742A9BE4, 0x3FEA08567D9C05D2, 0x3FEA51280A4BC4E4, 0x3FEA9AC4485C151A, 0x3FEAE52D6C00C806, 0x3FEB3065AF902915, 0x3FEB7C6F53941130, 0x3FEBC94C9EDB2998, 0x3FEC16FFDE8A5F16, 0x3FEC658B662E857B, 0x3FECB4F18FCE2C7A, 0x3FED0534BBFBA5E1, 0x3FED565751E73E45, 0x3FEDA85BBF71A81C, 0x3FEDFB44793E9A64, 0x3FEE4F13FAC7A2DE, 0x3FEEA3CCC66F2CE6, 0x3FEEF9716593BD0A, 0x3FEF500468A3625F, 0x3FEFA788672F5DC0, 0x3FF0000000000000 };
2293 
2305  inline double readHexLUT(static uint64_t* table, double xn)
2306  {
2307  double index = xn * (xformLUTLen - 1);
2308  uint32_t readIndex = uint32_t(xn);
2309  double fracPart = xn - readIndex;
2310  uint32_t nextReadIndex = readIndex + 1; // will never wrap because of if (xn >= 1.0) return 1.0;
2311  return doLinearInterpolation(uint64ToDouble(table[readIndex]), uint64ToDouble(table[nextReadIndex]), fracPart);
2312  }
2313 
2326  inline double concaveXForm(double xn, bool useLUT = false)
2327  {
2328  if (xn >= 1.0) return 1.0;
2329  if (xn <= 0.0) return 0.0;
2330 
2331  double transformed = 0.0;
2332  if (useLUT)
2333  {
2334  transformed = readHexLUT(&concaveLUT[0], xn);
2335  }
2336  else
2338 
2339  boundValue(transformed, 0.0, +1.0);
2340  return transformed;
2341  }
2342 
2355  inline double bipolarConcaveXForm(double xn, bool useLUT = false)
2356  {
2357  if (xn >= 0.0)
2358  return concaveXForm(xn);
2359  else
2360  return -concaveXForm(-xn);
2361 
2362  return xn;
2363  }
2364 
2377  inline double reverseConcaveXForm(double xn, bool useLUT = false)
2378  {
2379  double transformed = (kCTCorrFactorAntiUnity)*(-pow(10.0, (-xn / kCTCoefficient)) + 1.0);
2380  boundValue(transformed, 0.0, +1.0);
2381  return transformed;
2382  }
2383 
2396  inline double bipolarReverseConcaveXForm(double xn, bool useLUT = false)
2397  {
2398  if (xn >= 0.0)
2399  {
2400  return reverseConcaveXForm(xn);
2401  }
2402  else
2403  {
2404  return -reverseConcaveXForm(-xn);
2405  }
2406  return xn;
2407  }
2408 
2421  inline double convexXForm(double xn, bool useLUT = false)
2422  {
2423  if (xn <= 0.0) return 0.0;
2424  double transformed = kCTCorrFactorUnity*(1.0 + kCTCoefficient*log10(xn + kCTCorrFactorZero));
2425  boundValue(transformed, 0.0, +1.0);
2426  return transformed;
2427  }
2428 
2441  inline double bipolarConvexXForm(double xn, bool useLUT = false)
2442  {
2443  if (xn >= 0.0)
2444  {
2445  return convexXForm(xn);
2446  }
2447  else
2448  {
2449  return -convexXForm(-xn);
2450  }
2451  return xn;
2452  }
2453 
2466  inline double reverseConvexXForm(double xn, bool useLUT = false)
2467  {
2468  double transformed = kCTCorrFactorAnitZero * (pow(10.0, (xn - 1) / kCTCoefficient) - kCTCorrFactorZero);
2469  boundValue(transformed, -1.0, +1.0);
2470  return transformed;
2471  }
2472 
2485  inline double bipolarReverseConvexXForm(double xn, bool useLUT = false)
2486  {
2487  if (xn >= 0.0)
2488  {
2489  return reverseConvexXForm(xn);
2490  }
2491  else
2492  {
2493  return -reverseConvexXForm(-xn);
2494  }
2495  return xn;
2496  }
2497 
2511  inline double doPolyBLEP_2(double mcounter, double phaseInc, double height, bool risingEdge)
2512  {
2513  // --- return value
2514  double blepCorrection = 0.0;
2515 
2516  // --- LEFT side of discontinuity
2517  // -1 < t < 0
2518  if (mcounter > 1.0 - phaseInc)
2519  {
2520  // --- calculate distance
2521  double t = (mcounter - 1.0) / phaseInc;
2522 
2523  // --- calculate residual
2524  blepCorrection = height*(t*t + 2.0*t + 1.0);
2525  }
2526  // --- RIGHT side of discontinuity
2527  // 0 <= t < 1
2528  else if (mcounter < phaseInc)
2529  {
2530  // --- calculate distance
2531  double t = mcounter / phaseInc;
2532 
2533  // --- calculate residual
2534  blepCorrection = height*(2.0*t - t*t - 1.0);
2535  }
2536 
2537  // --- subtract for falling, add for rising edge
2538  if (!risingEdge)
2539  blepCorrection *= -1.0;
2540 
2541  return blepCorrection;
2542  }
2543 
2562  inline double doBLEP_N(double tableLength, double modCounter, double phaseInc, double height,
2563  bool risingEdge, double pointsPerSide, bool interpolate = false)
2564  {
2565  const double* blepTable = nullptr;
2566  if (pointsPerSide == 1)
2567  blepTable = &dBLEPTable[0];
2568  else
2569  blepTable = &dBLEPTable_8_BLKHAR[0];
2570 
2571  if (!blepTable) return 0.0;
2572 
2573  // return value
2574  double blepCorrection = 0.0;
2575 
2576  // t = the distance from the discontinuity
2577  double t = 0.0;
2578 
2579  // --- find the center of table (discontinuity location)
2580  double tableCenter = tableLength / 2.0 - 1;
2581 
2582  // LEFT side of edge
2583  // -1 < t < 0
2584  for (int i = 1; i <= (uint32_t)pointsPerSide; i++)
2585  {
2586  if (modCounter > 1.0 - (double)i*phaseInc)
2587  {
2588  // --- calculate distance
2589  t = (modCounter - 1.0) / (pointsPerSide*phaseInc);
2590 
2591  // --- get index
2592  float index = (1.0 + t)*tableCenter;
2593 
2594  // --- truncation
2595  if (!interpolate)
2596  {
2597  if ((int)index < tableLength)
2598  blepCorrection = blepTable[(int)index];
2599  }
2600  else if ((int)index < tableLength && (int)index + 1 < tableLength)
2601  {
2602  float index = (1.0 + t)*tableCenter;
2603  float frac = index - int(index);
2604  blepCorrection = doLinearInterpolation(0, 1, blepTable[(int)index], blepTable[(int)index + 1], frac);
2605  }
2606 
2607  // --- subtract for falling, add for rising edge
2608  if (!risingEdge)
2609  blepCorrection *= -1.0;
2610 
2611  return height*blepCorrection;
2612  }
2613  }
2614 
2615  // RIGHT side of discontinuity
2616  // 0 <= t < 1
2617  for (int i = 1; i <= (uint32_t)pointsPerSide; i++)
2618  {
2619  if (modCounter < (double)i*phaseInc)
2620  {
2621  // calculate distance
2622  t = modCounter / (pointsPerSide*phaseInc);
2623 
2624  // --- get index
2625  float index = t*tableCenter + (tableCenter + 1.0);
2626 
2627  // truncation
2628  if (!interpolate)
2629  {
2630  if ((int)index < tableLength)
2631  blepCorrection = blepTable[(int)index];
2632  }
2633  else if ((int)index < tableLength && (int)index + 1 < tableLength)
2634  {
2635  float frac = index - int(index);
2636  if ((int)index + 1 >= tableLength)
2637  blepCorrection = doLinearInterpolation(0, 1, blepTable[(int)index], blepTable[0], frac);
2638  else
2639  blepCorrection = doLinearInterpolation(0, 1, blepTable[(int)index], blepTable[(int)index + 1], frac);
2640  }
2641 
2642  // subtract for falling, add for rising edge
2643  if (!risingEdge)
2644  blepCorrection *= -1.0;
2645 
2646  return height*blepCorrection;
2647  }
2648  }
2649  return 0.0;
2650  }
2651 
2652 } // namespace
2653 
2654 #endif
std::string concatStrings(std::string s1, std::string s2)
Concatenate two strings.
Definition: synthfunctions.h:1277
#define enumToInt(ENUM)
macro helper to cast a typed enum to an int
Definition: synthfunctions.h:234
double normToAntiLogNorm(double normalizedValue)
normalized to anti-log normalized version
Definition: synthfunctions.h:374
double sgn(double xn)
calculates sgn( ) of input
Definition: synthfunctions.h:1156
float * getOutputBuffer(uint32_t channel)
Get a naked pointer to an audio OUTPUT buffer by channel.
Definition: synthbase.cpp:162
uint32_t mapDoubleToUINT(double value, double min, double max, uint32_t minMap, uint32_t maxMap, bool roundValue=false)
map double on a range of (min, max) to a uint32_t on the range of (minMap, maxMap) ...
Definition: synthfunctions.h:681
const double D
produces the Bhaskara&#39;s sine approximation
Definition: synthfunctions.h:2140
double getModKnobValueAntiLog(double normalizedValue, double min, double max)
maps a mod-knob value on the range of [0.0, 1.0] to a number on the range [min, max] anti-logarithmic...
Definition: synthfunctions.h:448
void unipolarXForm(double &value)
identical to unipolar( ) but returns value with pass-by-reference argument
Definition: synthfunctions.h:1062
bool inRange(double low, double high, double x)
tests a number to see if it is withing a certain range
Definition: synthfunctions.h:1905
double calculatePitchBend(IMidiInputData *midiInputData)
Second method to calculate a pitch bend multiplier value based on the global MIDI input values: ...
Definition: synthfunctions.h:2212
uint32_t midi14_bitToUnipolarInt(uint32_t midiDataLSB, uint32_t midiDataMSB)
Converts MIDI data bytes 1 and 2 (14-bit) into a unipolar value 0 -> 16383.
Definition: synthfunctions.h:754
const double kCTCoefficient
concave and/or convex transform correction factor
Definition: synthfunctions.h:290
void boundValueBipolar(double &value)
Bound a value to [-1, +1].
Definition: synthfunctions.h:539
uint64_t doubleToUint64(double d)
maps a double value into a uint64 value without casting or mangling bits
Definition: synthfunctions.h:1830
void copyOutputToOutput(std::shared_ptr< AudioBuffer > &source, SynthProcessInfo &destination, uint32_t channel, uint32_t samplesToCopy)
copies an output audio buffer to the SynthProcessInfo audio output buffer
Definition: synthfunctions.h:103
const double kPi
pi to 80 decimal places
Definition: synthconstants.h:522
void mapIntValue(int &value, int min, int max, int minMap, int maxMap, bool roundValue=true)
map int on a range of (min, max) to the same int on the range of (minMap, maxMap) ...
Definition: synthfunctions.h:627
double raw2dB(double raw)
calculates dB for given input
Definition: synthfunctions.h:1076
VectorXFadeData calculateVectorMix(double joystick_X, double joystick_Y, double origin_X=0.0, double origin_Y=0.0)
converts a joystick (x,y) position into the four mixing coefficients plus the X/Y axis shaodows ...
Definition: synthfunctions.h:2065
uint32_t floatToUint32(float d)
maps a float value to a uint32_t value without casting or mangling bits
Definition: synthfunctions.h:1866
double doUnipolarModulationFromMin(double unipolarModulatorValue, double minValue, double maxValue)
Perform unipolar modulation from a min value up to a max value using a unipolar modulator value...
Definition: synthfunctions.h:942
const double kCTCorrFactorAntiUnity
inverse concave/convex transform correction factor at x = 1
Definition: synthfunctions.h:318
void calculatePanValues(double bipolarModulator, double &leftPanValue, double &rightPanValue)
calculates the left and right pan values from a bipolar (-1 -> 1) value
Definition: synthfunctions.h:1593
void boundMIDIValueDoubleByte(uint32_t &value)
Bound a value to min and max limits.
Definition: synthfunctions.h:570
uint64_t countTrailingZeros_x64(uint64_t x)
count trailing zeros in a binary number, return in unsigned int
Definition: synthfunctions.h:1570
double uint64ToDouble(uint64_t u)
maps a uint64 value to a double value without casting or mangling bits
Definition: synthfunctions.h:1848
void bipolarIntToMIDI14_bit(int32_t biPolarValue, int32_t minValue, int32_t maxValue, uint32_t &midiDataLSB, uint32_t &midiDataMSB)
Converts int value on the range [minValue, maxValue] into 14-bit MIDI bytes, pass by reference...
Definition: synthfunctions.h:853
void boundValueUnipolar(double &value)
Bound a value to [0, +1].
Definition: synthfunctions.h:525
const double kCTCorrFactorZero
concave/convex transform correction factor at x = 0
Definition: synthfunctions.h:297
void copyStingList(std::vector< std::string > &source, std::vector< std::string > &destination)
Copies one vector of strings to another.
Definition: synthfunctions.h:1253
void bipolarXForm(double &value)
identical to bipolar( ) but returns value with pass-by-reference argument
Definition: synthfunctions.h:1035
double tanhWaveShaper(double xn, double saturation)
calculates hyptan waveshaper
Definition: synthfunctions.h:1201
int countTrailingZero(int x)
count trailing zeros in a binary number
Definition: synthfunctions.h:1544
double splitBipolar(double value)
maps a unipolar value across two unipolar values, from middle
Definition: synthfunctions.h:1007
double semitonesBetweenFrequencies(double startFrequency, double endFrequency)
calculates the number of semitones between a start and end frequency
Definition: synthfunctions.h:1670
double doPolyBLEP_2(double mcounter, double phaseInc, double height, bool risingEdge)
Calculates the 2nd order polynomial BLEP correction factor.
Definition: synthfunctions.h:2522
double concaveXForm(double xn, bool useLUT=false)
Perform the MMA concave tranform on a unipolar value.
Definition: synthfunctions.h:2337
const double kCTCorrFactorUnity
concave/convex transform correction factor at x = 1
Definition: synthfunctions.h:311
bool checkAndWrapWaveTableIndex(double &index, uint32_t tableLength)
check and do modulo (fmod) wrap of a wavetable index value
Definition: synthfunctions.h:1517
Definition: synthengine.cpp:16
double dBPeakGainFor_Q(double Q)
calculates the peak magnitude in dB for a given Q
Definition: synthfunctions.h:1120
double calcWSGain(double xn, double saturation, double asymmetry)
calculates gain of a waveshaper
Definition: synthfunctions.h:1171
void copyAudioBufferOutputToSynthOutput(std::shared_ptr< AudioBuffer > &source, SynthProcessInfo &destination, uint32_t channel, uint32_t samplesToCopy)
copies an output audio buffer to the SynthProcessInfo audio output buffer
Definition: synthfunctions.h:173
double bipolarReverseConcaveXForm(double xn, bool useLUT=false)
Perform the MMA reverse concave tranform on a bipolar value.
Definition: synthfunctions.h:2407
double normToLogNorm(double normalizedValue)
normalized to Log-normalized version
Definition: synthfunctions.h:344
void boundMIDIValueByte(uint32_t &value)
Bound a value to 0 and 127 limits.
Definition: synthfunctions.h:555
double doLinearInterpolation(double y1, double y2, double fractional_X)
performs linear interpolation of fractional x distance between two adjacent (x,y) points; returns int...
Definition: synthfunctions.h:1375
double wrapMinMax(double x, double min, double max)
wraps a value around a maximum value enough times that it falls within the maximum boundary ...
Definition: synthfunctions.h:1943
NoteDuration
emumearation of musical durations, shortest to longest
Definition: synthfunctions.h:1681
double bipolarConvexXForm(double xn, bool useLUT=false)
Perform the MMA convex tranform on a bipolar value.
Definition: synthfunctions.h:2452
void copySynthOutputToAudioBufferInput(SynthProcessInfo &source, std::shared_ptr< AudioBuffer > &destination, uint32_t channel, uint32_t samplesToCopy)
Complementary function that moves audio from the SynthProcessInfo output into an audio buffer...
Definition: synthfunctions.h:206
const double B
highest accurace sinudoid approximation function
Definition: synthfunctions.h:2159
double midi14_bitToDouble(uint32_t midiDataLSB, uint32_t midiDataMSB, double minValue, double maxValue)
Converts MIDI data bytes 1 and 2 (14-bit) into a double value on the range [minValue, maxValue].
Definition: synthfunctions.h:794
float uint32ToFloat(uint32_t u)
maps a uint32_t value to a float value without casting or mangling bits
Definition: synthfunctions.h:1884
void unipolarIntToMIDI14_bit(uint32_t unipolarValue, uint32_t &midiDataLSB, uint32_t &midiDataMSB)
Converts value from 0 -> 16383 into 14-bit MIDI bytes, pass by reference.
Definition: synthfunctions.h:818
void calculateConstPwrMixValues(double bipolarModulator, double &mixValueA, double &mixValueB)
converts bipolar (-1 -> 1) value into a pair of constant power mixing coefficients ...
Definition: synthfunctions.h:1616
double unipolar(double value)
calculates the unipolar [0.0, +1.0] value FROM a bipolar [-1.0, +1.0] value
Definition: synthfunctions.h:1049
double mapUINTToDouble(uint32_t value, uint32_t min, uint32_t max, double minMap, double maxMap)
map uint32_t on a range of (min, max) to a double on the range of (minMap, maxMap) ...
Definition: synthfunctions.h:712
const double kCTCorrFactorAntiLog
concave/convex transform correction factor
Definition: synthfunctions.h:325
std::vector< std::string > charArrayToStringVector(const char **charArray, uint32_t size, std::string ignoreString="")
Converts an old fasioned array of char* strings to a vector of std::strings.
Definition: synthfunctions.h:1960
double doLagrangeInterpolation(double *x, double *y, int n, double xbar)
implements n-order Lagrange Interpolation
Definition: synthfunctions.h:1396
double logNormToNorm(double logNormalizedValue)
log-normalized to normalized version
Definition: synthfunctions.h:359
double quantizeBipolarValue(double d, uint32_t qLevels)
Quantizes a double value into some number of quantization levels.
Definition: synthfunctions.h:1813
double getTimeFromTempo(double BPM, double normalizedNoteMult)
converts a BPM value and a normalized note multiplier on the range [0, 1] to a note duration multipli...
Definition: synthfunctions.h:1789
double midi14_bitToUnipolarDouble(uint32_t midiDataLSB, uint32_t midiDataMSB)
Converts MIDI data bytes 1 and 2 (14-bit) into a unipolar double value 0.0 -> 1.0.
Definition: synthfunctions.h:772
double quadraticSine(double angle)
produces the quadratic sine approximation
Definition: synthfunctions.h:2122
double atanWaveShaper(double xn, double saturation)
calculates arctangent waveshaper
Definition: synthfunctions.h:1186
const double kCTCorrFactorAnitZero
inverse concave/convex transform factor at x = 0
Definition: synthfunctions.h:304
double calculateWaveTablePhaseInc(double oscFrequency, double sampleRate, uint32_t wavetableLength)
calculates the phase-increment for a wavetable for a target oscillator frequency
Definition: synthfunctions.h:1500
void getPluginContainerFolder(std::string &str)
Helper to get the outer plugin folder with the inner folder path.
Definition: synthfunctions.h:1330
const double kCTCorrFactorAntiLogScale
concave/convex transform scaling factor
Definition: synthfunctions.h:332
double readHexLUT(static uint64_t *table, double xn)
Read a table that has been encoded as uint64_t HEX values.
Definition: synthfunctions.h:2305
double getModKnobValueLog(double normalizedValue, double min, double max)
maps a mod-knob value on the range of [0.0, 1.0] to a number on the range [min, max] logarithmically ...
Definition: synthfunctions.h:429
double reverseConcaveXForm(double xn, bool useLUT=false)
Perform the MMA reverse concave tranform on a unipolar value.
Definition: synthfunctions.h:2388
double bipolarReverseConvexXForm(double xn, bool useLUT=false)
Perform the MMA reverse convex tranform on a bipolar value.
Definition: synthfunctions.h:2496
uint32_t midiNoteNumberFromOscFrequency(double oscillatorFrequency, double frequencyA440=440.0)
use lookup table to find pitch shift multipliers, uses linear interpolation
Definition: synthfunctions.h:1452
const double kPiSqared
Definition: synthconstants.h:554
void mapUintValue(uint32_t &value, uint32_t min, uint32_t max, uint32_t minMap, uint32_t maxMap, bool roundValue=true)
map unsigned int on a range of (min, max) to the same unsigned int on the range of (minMap...
Definition: synthfunctions.h:653
void clampMaxValue(double &value, double maxValue)
Bound a value to max limits.
Definition: synthfunctions.h:480
bool appendCharArrayToStringVector(const char **charArray, uint32_t size, std::vector< std::string > &outputVector, std::string ignoreString)
Appends an old fasioned array of char* strings to a vector of std::strings.
Definition: synthfunctions.h:1988
This structure holds all of the information needed to for the plugin framework to send MIDI informati...
Definition: synthbase.h:1326
void boundIntValue(int &value, int min, int max)
Bound a value to min and max limits.
Definition: synthfunctions.h:586
double doBLEP_N(double tableLength, double modCounter, double phaseInc, double height, bool risingEdge, double pointsPerSide, bool interpolate=false)
Calculates the BLEP correction factor for 1, 2, 3 or 4 points of correction on each side of the wavef...
Definition: synthfunctions.h:2573
double softClipWaveShaper(double xn, double saturation)
calculates hyptan waveshaper
Definition: synthfunctions.h:1216
double peakGainFor_Q(double Q)
calculates the peak magnitude for a given Q
Definition: synthfunctions.h:1104
double midiPitchBendToBipolar(uint32_t midiData1, uint32_t midiData2)
Converts MIDI data bytes 1 and 2 into a bipolar [-1, +1] value.
Definition: synthfunctions.h:924
uint32_t calculateNumTables(uint32_t seedMIDINote, uint32_t tableIntervalSemitones)
Calculates the number of wavetables needed to cover the MIDI keyboard starting from a seed note...
Definition: synthfunctions.h:2266
double bipolarConcaveXForm(double xn, bool useLUT=false)
Perform the MMA concave tranform on a bipolar value.
Definition: synthfunctions.h:2366
double calculateMasterTuning(IMidiInputData *midiInputData)
Method to calculate a tuning (pitch bend) multiplier value based on the global MIDI input values: ...
Definition: synthfunctions.h:2238
void copyBufferToInput(std::shared_ptr< AudioBuffer > &source, std::shared_ptr< AudioBuffer > &destination, uint32_t channel, uint32_t samplesToCopy)
copies an output audio buffer to an input audio buffer
Definition: synthfunctions.h:138
double msecToSamples(double sampleRate, double timeMSec)
convert a time in milliseconds to a floating point sample count
Definition: synthfunctions.h:466
void clampMinValue(double &value, double minValue)
Bound a value to min limits.
Definition: synthfunctions.h:494
void ReplaceSubStrWithStr(std::string &str, const std::string &from, const std::string &to)
Helper to relace strings within a std::string object.
Definition: synthfunctions.h:1296
XFadeType
Definition: synthconstants.h:81
const double dBLEPTable_8_BLKHAR[4096]
Definition: bleptables.h:52
double getModKnobValueLinear(double normalizedValue, double min, double max)
maps a mod-knob value on the range of [0.0, 1.0] to a number on the range [min, max] ...
Definition: synthfunctions.h:411
double midi14_bitToBipolar(uint32_t midiDataLSB, uint32_t midiDataMSB)
Converts MIDI data bytes 1 and 2 (14-bit) into a bipolar [-1, +1] value.
Definition: synthfunctions.h:733
const double kPiOverFour
Definition: synthconstants.h:556
double fuzzExp1WaveShaper(double xn, double saturation, double asymmetry)
calculates fuzz exp1 waveshaper
Definition: synthfunctions.h:1233
void unipolarDoubleToMIDI14_bit(double unipolarValue, uint32_t &midiDataLSB, uint32_t &midiDataMSB)
Converts double value on the range [0, 1] into 14-bit MIDI bytes, pass by reference.
Definition: synthfunctions.h:889
double wrapMax(double x, double max)
wraps a value around a maximum value enough times that it falls within the maximum boundary ...
Definition: synthfunctions.h:1923
double doBipolarModulation(double bipolarModulatorValue, double minValue, double maxValue)
Perform bipolar modulation about a center that his halfway between the min and max values...
Definition: synthfunctions.h:982
double crossfade(XFadeType xfadeType, double inputA, double inputB, double xFrac)
crossfade two values And B together by some fractional amount
Definition: synthfunctions.h:1638
double bipolar(double value)
calculates the bipolar [-1.0, +1.0] value FROM a unipolar [0.0, +1.0] value
Definition: synthfunctions.h:1022
const double dBLEPTable[4096]
Definition: bleptables.h:22
double antiLogNormToNorm(double aLogNormalizedValue)
anti-log normalized to normalized version
Definition: synthfunctions.h:394
void mapDoubleValue(double &value, double min, double max, double minMap, double maxMap)
map double on a range of (min, max) to the same double on the range of (minMap, maxMap) ...
Definition: synthfunctions.h:604
double mmaMIDItoAtten(uint32_t midiValue)
calculates the raw attenuation according to MMA DLS spec midiValue = the MIDI (0 -> 127) value to con...
Definition: synthfunctions.h:2018
double reverseConvexXForm(double xn, bool useLUT=false)
Perform the MMA reverse convex tranform on a unipolar value.
Definition: synthfunctions.h:2477
double midiNoteNumberToOscFrequency(uint32_t midiNoteNumber, double frequencyA440=440.0)
converts a MIDI note number into a corresponding oscillator frequency in Hz
Definition: synthfunctions.h:1480
double convexXForm(double xn, bool useLUT=false)
Perform the MMA convex tranform on a unipolar value.
Definition: synthfunctions.h:2432
void boundValue(double &value, double minValue, double maxValue)
Bound a value to min and max limits.
Definition: synthfunctions.h:510
void copyOutputToInput(std::shared_ptr< AudioBuffer > &source, std::shared_ptr< AudioBuffer > &destination, uint32_t channel, uint32_t samplesToCopy)
copies an output audio buffer to an input audio buffer
Definition: synthfunctions.h:39
void stripLastFolderFromPath(std::string &str)
Helper to strip the last folder path from a given path.
Definition: synthfunctions.h:1315
double dB2Raw(double dB)
converts dB to raw value
Definition: synthfunctions.h:1090
double doUnipolarModulationFromMax(double unipolarModulatorValue, double minValue, double maxValue)
Perform unipolar modulation from a max value down to a min value using a unipolar modulator value...
Definition: synthfunctions.h:962