1 #include "engine/enginexfader.h"
2 
3 #include "util/math.h"
4 
5 //static
6 const char* EngineXfader::kXfaderConfigKey = "[Mixer Profile]";
7 const double EngineXfader::kTransformDefault = 1.0;
8 const double EngineXfader::kTransformMax = 1000.0;
9 const double EngineXfader::kTransformMin = 0.6;
10 
getPowerCalibration(double transform)11 double EngineXfader::getPowerCalibration(double transform) {
12     // get the transform_root of -3db (.5)
13     return pow(0.5, 1.0 / transform);
14 }
15 
getXfadeGains(double xfadePosition,double transform,double powerCalibration,double curve,bool reverse,CSAMPLE_GAIN * gain1,CSAMPLE_GAIN * gain2)16 void EngineXfader::getXfadeGains(double xfadePosition,
17         double transform,
18         double powerCalibration,
19         double curve,
20         bool reverse,
21         CSAMPLE_GAIN* gain1,
22         CSAMPLE_GAIN* gain2) {
23     if (gain1 == nullptr || gain2 == nullptr) {
24         return;
25     }
26 
27     // Slow-fade/fast-cut
28     double xfadePositionLeft = xfadePosition;
29     double xfadePositionRight = xfadePosition;
30 
31     if (curve == MIXXX_XFADER_CONSTPWR) {
32         // Apply Calibration
33         xfadePosition *= powerCalibration;
34         xfadePositionLeft = xfadePosition - powerCalibration;
35         xfadePositionRight = xfadePosition + powerCalibration;
36     }
37 
38     if (xfadePositionLeft < 0) { // on left side
39         xfadePositionLeft *= -1;
40         *gain2 = static_cast<CSAMPLE_GAIN>(1.0 - (1.0 * pow(xfadePositionLeft, transform)));
41     } else {
42         *gain2 = 1.0f;
43     }
44 
45     if(xfadePositionRight > 0) { // right side
46         *gain1 = static_cast<CSAMPLE_GAIN>(1.0 - (1.0 * pow(xfadePositionRight, transform)));
47     } else {
48         *gain1 = 1.0f;
49     }
50 
51     //prevent phase reversal
52     if (*gain1 < 0.0) {
53         *gain1 = 0.0f;
54     }
55     if (*gain2 < 0.0) {
56         *gain2 = 0.0f;
57     }
58 
59     if (curve == MIXXX_XFADER_CONSTPWR) {
60         if (*gain1 > *gain2) {
61             *gain2 = 1 - *gain1;
62         } else {
63             *gain1 = 1 - *gain2;
64         }
65 
66         // The resulting power at the crossover point depends on the correlation of the input signals
67         // In theory the gain ratio varies from 0.5 for two equal signals to sqrt(0.5) = 0.707 for totally
68         // uncorrelated signals.
69         // Since the underlying requirement for this curve is constant loudness, we did a test with 30 s
70         // snippets of various genres and ReplayGain 2.0 analysis. Almost all results where near 0.707
71         // with one exception of mixing two parts of the same track, which resulted in 0.66.
72         // Based on the testing, we normalize the gain as if the signals were uncorrelated. The
73         // correction on the following lines ensures that  gain1^2 + gain2^2 == 1.
74         CSAMPLE_GAIN gain = static_cast<CSAMPLE_GAIN>(sqrt(*gain1 * *gain1 + *gain2 * *gain2));
75         *gain1 = *gain1 / gain;
76         *gain2 = *gain2 / gain;
77     }
78 
79     if (reverse) {
80         CSAMPLE_GAIN gain_temp = *gain1;
81         *gain1 = *gain2;
82         *gain2 = gain_temp;
83     }
84 }
85