Gain performance improvements (don't waste time applying gain when not necessary).
[ardour.git] / libs / ardour / amp.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3     
4     This program is free software; you can redistribute it and/or modify it
5     under the terms of the GNU General Public License as published by the Free
6     Software Foundation; either version 2 of the License, or (at your option)
7     any later version.
8     
9     This program is distributed in the hope that it will be useful, but WITHOUT
10     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12     for more details.
13     
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <ardour/amp.h>
20
21 #include <algorithm>
22 #include <cmath>
23 #include <ardour/buffer_set.h>
24 #include <ardour/buffer.h>
25
26 namespace ARDOUR {
27
28
29 /** Apply a declicked gain to the audio buffers of @a bufs */
30 void
31 Amp::run (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
32 {
33         if (nframes == 0)
34                 return;
35
36         if (bufs.count().get(DataType::AUDIO) == 0)
37                 return;
38
39         // assert(bufs.buffer_capacity(DataType::AUDIO) >= nframes);
40
41         // if we don't need to declick, defer to apply_simple_gain
42         if (initial == target) {
43                 if (target == 0.0) {
44                         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
45                                 memset (i->data(), 0, sizeof (Sample) * nframes);
46                         }
47                 } else if (target != 1.0) {
48                         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
49                                 apply_gain_to_buffer (i->data(), nframes, target);
50                         }
51                 }
52                 return;
53         }
54
55         const nframes_t declick = std::min ((nframes_t)128, nframes);
56         gain_t         delta;
57         double         fractional_shift = -1.0/declick;
58         double         fractional_pos;
59         gain_t         polscale = invert_polarity ? -1.0f : 1.0f;
60
61         if (target < initial) {
62                 /* fade out: remove more and more of delta from initial */
63                 delta = -(initial - target);
64         } else {
65                 /* fade in: add more and more of delta from initial */
66                 delta = target - initial;
67         }
68
69         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
70                 Sample* const buffer = i->data();
71
72                 fractional_pos = 1.0;
73
74                 for (nframes_t nx = 0; nx < declick; ++nx) {
75                         buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
76                         fractional_pos += fractional_shift;
77                 }
78                 
79                 /* now ensure the rest of the buffer has the target value applied, if necessary. */
80                 
81                 if (declick != nframes) {
82
83                         if (invert_polarity) {
84                                 target = -target;
85                         }
86
87                         if (target == 0.0) {
88                                 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
89                         } else if (target != 1.0) {
90                                 apply_gain_to_buffer (&buffer[declick], nframes - declick, target);
91                         }
92                 }
93         }
94 }
95
96 void
97 Amp::apply_simple_gain (BufferSet& bufs, nframes_t nframes, gain_t target)
98 {
99 }
100
101
102 } // namespace ARDOUR