ardour
interpolation.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include <stdint.h>
21 #include <cstdio>
22 
23 #include "ardour/interpolation.h"
24 #include "ardour/midi_buffer.h"
25 
26 using namespace ARDOUR;
27 
28 
30 LinearInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input, Sample *output)
31 {
32  // index in the input buffers
33  framecnt_t i = 0;
34 
35  double acceleration = 0;
36 
37  if (_speed != _target_speed) {
38  acceleration = _target_speed - _speed;
39  }
40 
41  for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
42  double const d = phase[channel] + outsample * (_speed + acceleration);
43  i = floor(d);
44  Sample fractional_phase_part = d - i;
45  if (fractional_phase_part >= 1.0) {
46  fractional_phase_part -= 1.0;
47  i++;
48  }
49 
50  if (input && output) {
51  // Linearly interpolate into the output buffer
52  output[outsample] =
53  input[i] * (1.0f - fractional_phase_part) +
54  input[i+1] * fractional_phase_part;
55  }
56  }
57 
58  double const distance = phase[channel] + nframes * (_speed + acceleration);
59  i = floor(distance);
60  phase[channel] = distance - i;
61  return i;
62 }
63 
65 CubicInterpolation::interpolate (int channel, framecnt_t nframes, Sample *input, Sample *output)
66 {
67  // index in the input buffers
68  framecnt_t i = 0;
69 
70  double acceleration;
71  double distance = 0.0;
72 
73  if (_speed != _target_speed) {
74  acceleration = _target_speed - _speed;
75  } else {
76  acceleration = 0.0;
77  }
78 
79  distance = phase[channel];
80 
81  if (nframes < 3) {
82  /* no interpolation possible */
83 
84  if (input && output) {
85  for (i = 0; i < nframes; ++i) {
86  output[i] = input[i];
87  }
88  }
89 
90  return nframes;
91  }
92 
93  /* keep this condition out of the inner loop */
94 
95  if (input && output) {
96 
97  Sample inm1;
98 
99  if (floor (distance) == 0.0) {
100  /* best guess for the fake point we have to add to be able to interpolate at i == 0:
101  .... maintain slope of first actual segment ...
102  */
103  inm1 = input[i] - (input[i+1] - input[i]);
104  } else {
105  inm1 = input[i-1];
106  }
107 
108  for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
109 
110  float f = floor (distance);
111  float fractional_phase_part = distance - f;
112 
113  /* get the index into the input we should start with */
114 
115  i = lrintf (f);
116 
117  /* fractional_phase_part only reaches 1.0 thanks to float imprecision. In theory
118  it should always be < 1.0. If it ever >= 1.0, then bump the index we use
119  and back it off. This is the point where we "skip" an entire sample in the
120  input, because the phase part has accumulated so much error that we should
121  really be closer to the next sample. or something like that ...
122  */
123 
124  if (fractional_phase_part >= 1.0) {
125  fractional_phase_part -= 1.0;
126  ++i;
127  }
128 
129  // Cubically interpolate into the output buffer: keep this inlined for speed and rely on compiler
130  // optimization to take care of the rest
131  // shamelessly ripped from Steve Harris' swh-plugins (ladspa-util.h)
132 
133  output[outsample] = input[i] + 0.5f * fractional_phase_part * (input[i+1] - inm1 +
134  fractional_phase_part * (4.0f * input[i+1] + 2.0f * inm1 - 5.0f * input[i] - input[i+2] +
135  fractional_phase_part * (3.0f * (input[i] - input[i+1]) - inm1 + input[i+2])));
136 
137  distance += _speed + acceleration;
138  inm1 = input[i];
139  }
140 
141  i = floor(distance);
142  phase[channel] = distance - floor(distance);
143 
144  } else {
145  /* used to calculate play-distance with acceleration (silent roll)
146  * (use same algorithm as real playback for identical rounding/floor'ing)
147  */
148  for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
149  distance += _speed + acceleration;
150  }
151  i = floor(distance);
152  }
153 
154  return i;
155 }
156 
159 {
160  assert(phase.size() == 1);
161 
162  framecnt_t i = 0;
163 
164  double acceleration;
165  double distance = 0.0;
166 
167  if (nframes < 3) {
168  return nframes;
169  }
170 
171  if (_speed != _target_speed) {
172  acceleration = _target_speed - _speed;
173  } else {
174  acceleration = 0.0;
175  }
176 
177  distance = phase[0];
178 
179  for (framecnt_t outsample = 0; outsample < nframes; ++outsample) {
180  distance += _speed + acceleration;
181  }
182 
183  if (roll) {
184  phase[0] = distance - floor(distance);
185  }
186 
187  i = floor(distance);
188 
189  return i;
190 }
framecnt_t distance(framecnt_t nframes, bool roll=true)
std::vector< double > phase
Definition: interpolation.h:39
tuple f
Definition: signals.py:35
int64_t framecnt_t
Definition: types.h:76
float Sample
Definition: types.h:54
framecnt_t interpolate(int channel, framecnt_t nframes, Sample *input, Sample *output)
Definition: amp.h:29
framecnt_t interpolate(int channel, framecnt_t nframes, Sample *input, Sample *output)