if a request to reset the speed to zero as the default arrives when stopped, reset...
[ardour.git] / libs / ardour / interpolation.cc
1 #include <stdint.h>
2 #include <cstdio>
3
4 #include "ardour/interpolation.h"
5
6 using namespace ARDOUR;
7
8
9 framecnt_t
10 LinearInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input, Sample *output)
11 {
12         // index in the input buffers
13         framecnt_t i = 0;
14
15         double acceleration = 0;
16
17         if (_speed != _target_speed) {
18                 acceleration = _target_speed - _speed;
19         }
20
21         for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
22                 double const d = phase[channel] + outsample * (_speed + acceleration);
23                 i = floor(d);
24                 Sample fractional_phase_part = d - i;
25                 if (fractional_phase_part >= 1.0) {
26                         fractional_phase_part -= 1.0;
27                         i++;
28                 }
29
30                 if (input && output) {
31                 // Linearly interpolate into the output buffer
32                         output[outsample] =
33                                 input[i] * (1.0f - fractional_phase_part) +
34                                 input[i+1] * fractional_phase_part;
35                 }
36         }
37
38         double const distance = phase[channel] + nframes * (_speed + acceleration);
39         i = floor(distance);
40         phase[channel] = distance - i;
41         return i;
42 }
43
44 framecnt_t
45 CubicInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input, Sample *output)
46 {
47     // index in the input buffers
48     framecnt_t   i = 0;
49
50     double acceleration;
51     double distance = 0.0;
52
53     if (_speed != _target_speed) {
54         acceleration = _target_speed - _speed;
55     } else {
56             acceleration = 0.0;
57     }
58
59     distance = phase[channel];
60
61     if (nframes < 3) {
62             /* no interpolation possible */
63
64             for (i = 0; i < nframes; ++i) {
65                     output[i] = input[i];
66             }
67
68             return nframes;
69     }
70
71     /* keep this condition out of the inner loop */
72
73     if (input && output) {
74
75             Sample inm1;
76
77             if (floor (distance) == 0.0) {
78                     /* best guess for the fake point we have to add to be able to interpolate at i == 0:
79                        .... maintain slope of first actual segment ...
80                     */
81                     inm1 = input[i] - (input[i+1] - input[i]);
82             } else {
83                     inm1 = input[i-1];
84             }
85
86             for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
87
88                     float f = floor (distance);
89                     float fractional_phase_part = distance - f;
90
91                     /* get the index into the input we should start with */
92
93                     i = lrintf (f);
94
95                     /* fractional_phase_part only reaches 1.0 thanks to float imprecision. In theory
96                        it should always be < 1.0. If it ever >= 1.0, then bump the index we use
97                        and back it off. This is the point where we "skip" an entire sample in the
98                        input, because the phase part has accumulated so much error that we should
99                        really be closer to the next sample. or something like that ...
100                     */
101
102                     if (fractional_phase_part >= 1.0) {
103                             fractional_phase_part -= 1.0;
104                             ++i;
105                     }
106
107                     // Cubically interpolate into the output buffer: keep this inlined for speed and rely on compiler
108                     // optimization to take care of the rest
109                     // shamelessly ripped from Steve Harris' swh-plugins (ladspa-util.h)
110
111                     output[outsample] = input[i] + 0.5f * fractional_phase_part * (input[i+1] - inm1 +
112                                                           fractional_phase_part * (4.0f * input[i+1] + 2.0f * inm1 - 5.0f * input[i] - input[i+2] +
113                                                                 fractional_phase_part * (3.0f * (input[i] - input[i+1]) - inm1 + input[i+2])));
114
115                     distance += _speed + acceleration;
116                     inm1 = input[i];
117             }
118
119     } else {
120
121             /* not sure that this is ever utilized - it implies that one of the input/output buffers is missing */
122
123             for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
124                     distance += _speed + acceleration;
125             }
126     }
127
128     i = floor(distance);
129     phase[channel] = distance - floor(distance);
130
131     return i;
132 }