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