cfa20afe3b0d0dd9601f55f9bcd25fdf4bdbd577
[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, jack_nframes_t nframes, gain_t initial, gain_t target, bool invert_polarity)
32 {
33         if (bufs.count().get(DataType::AUDIO) == 0)
34                 return;
35
36         assert(bufs.buffer_capacity(DataType::AUDIO) >= nframes);
37
38         // if we don't need to declick, defer to apply_simple_gain
39         if (initial == target) {
40                 apply_simple_gain(bufs, nframes, invert_polarity ? target : -target);
41         }
42
43         const jack_nframes_t declick = std::min ((jack_nframes_t)128, nframes);
44         gain_t         delta;
45         double         fractional_shift = -1.0/declick;
46         double         fractional_pos;
47         gain_t         polscale = invert_polarity ? -1.0f : 1.0f;
48
49         if (nframes == 0)
50                 return;
51
52         if (target < initial) {
53                 /* fade out: remove more and more of delta from initial */
54                 delta = -(initial - target);
55         } else {
56                 /* fade in: add more and more of delta from initial */
57                 delta = target - initial;
58         }
59
60         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
61                 Sample* const buffer = i->data(nframes);
62
63                 fractional_pos = 1.0;
64
65                 for (jack_nframes_t nx = 0; nx < declick; ++nx) {
66                         buffer[nx] *= polscale * (initial + (delta * (0.5 + 0.5 * cos (M_PI * fractional_pos))));
67                         fractional_pos += fractional_shift;
68                 }
69                 
70                 /* now ensure the rest of the buffer has the target value applied, if necessary. */
71                 
72                 if (declick != nframes) {
73
74                         if (invert_polarity) {
75                                 target = -target;
76                         }
77
78                         if (target == 0.0) {
79                                 memset (&buffer[declick], 0, sizeof (Sample) * (nframes - declick));
80                         } else if (target != 1.0) {
81                                 for (jack_nframes_t nx = declick; nx < nframes; ++nx) {
82                                         buffer[nx] *= target;
83                                 }
84                         }
85                 }
86         }
87 }
88
89 void
90 Amp::apply_simple_gain (BufferSet& bufs, jack_nframes_t nframes, gain_t target)
91 {
92         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i) {
93                 i->apply_gain(target, nframes);
94         }
95 }
96
97
98 } // namespace ARDOUR