1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
ix!();

use crate::*;

impl SurgeSuperOscillator {
    #[inline] pub fn get_t(&self, sync: f64, detune: f64) -> (f32, f32) {
        let t: f32 = {
            if self.params[SSOParam::UniSpread].absolute {

                // Oh so this line of code. What is it doing?
                //
                //  t = storage->n2pinv_tuningctr(detune * pitchmult_inv * (1.f / CONCERT_A_HZ) + sync);
                // Lets for a moment assume std tuning. So n2pinv will give you, say, 1/32 for note 60 and 1/1 for note 0. Cool.
                // it is the inverse of frequency. That's why below with detune = +/- 1 for the extreme 2 voice case we just use it directly.
                // It is the time distance of one note.
                //
                // But in absolute mode we want to scale that note. So the calculation here (assume sync is 0 for a second) is 
                // detune * pitcmult_inv / CONCERT_A_HZ
                // pitchmult_inv =  dsamplerate_os / 8.17 * n2pinv(pitch)
                // so this is using
                // detune * 1.0 / CONCERT_A_HZ * 1.0 / 8.17 * dsamplerate * n2pinv(pitch)
                // Or: 
                // detune / n2p(pitch) * ( 1.0 / (CONCERT_A_HZ * 8.17 ) ) * dsamplerate
                //
                // So there's a couple of things wrong with that. First of all this should not be samplerate dependent.
                // Second of all, what/s up with 1.0 / ( 8.17 * CONCERT_A_HZ )
                // 
                // Well the answer is that we want the time to be pushed around in hz. So it turns out that
                // 44100 * 2 / ( CONCERT_A_HZ * 8.175 ) =~ 24.2 and 24.2 / 16 = 1.447 which is almost how much absolute is off. So
                // lets set the multiplier here so that the regtests exacty match the display frequency. That is the
                // frequency desired spread / 0.9443. 0.9443 is empirically determined by running the 2 unisoncase
                // over a bunch of tests.
                let note: f64 = 
                    detune as f64 * 
                    self.tuner.n2pinv::<f64,true>( self.pitch as f64) * 
                    16.0 / 0.9443 + sync;

                let mut t = self.tuner.n2pinv::<f64,true>(note);

                // With extended range and low frequencies we can have an implied 
                // negative frequency; cut that off by setting a lower bound here.
                if t < 0.1 { 
                    t = 0.0;
                }
                t as f32
            }
            else{
                self.tuner.n2pinv_tuningctr((detune as f64) + sync) as f32
            }
        };

        let t_inv:  f32 = rcp(t);

        (t, t_inv)
    }
}