Supporters update.
[dcpomatic.git] / src / lib / audio_buffers.cc
1 /*
2     Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "audio_buffers.h"
23 #include "dcpomatic_assert.h"
24 #include "maths_util.h"
25 #include "scope_guard.h"
26 #include <cassert>
27 #include <cstring>
28 #include <cmath>
29
30
31 using std::shared_ptr;
32 using std::make_shared;
33
34
35 /** Construct a silent AudioBuffers */
36 AudioBuffers::AudioBuffers (int channels, int frames)
37 {
38         allocate (channels, frames);
39 }
40
41
42 /** Copy constructor.
43  *  @param other Other AudioBuffers; data is copied.
44  */
45 AudioBuffers::AudioBuffers (AudioBuffers const & other)
46 {
47         allocate (other.channels(), other.frames());
48         copy_from (&other, other.frames(), 0, 0);
49 }
50
51
52 AudioBuffers::AudioBuffers (std::shared_ptr<const AudioBuffers> other)
53 {
54         allocate (other->channels(), other->frames());
55         copy_from (other.get(), other->frames(), 0, 0);
56 }
57
58
59 AudioBuffers::AudioBuffers (std::shared_ptr<const AudioBuffers> other, int frames_to_copy, int read_offset)
60 {
61         allocate (other->channels(), frames_to_copy);
62         copy_from (other.get(), frames_to_copy, read_offset, 0);
63 }
64
65
66 AudioBuffers &
67 AudioBuffers::operator= (AudioBuffers const & other)
68 {
69         if (this == &other) {
70                 return *this;
71         }
72
73         allocate (other.channels(), other.frames());
74         copy_from (&other, other.frames(), 0, 0);
75
76         return *this;
77 }
78
79
80 void
81 AudioBuffers::allocate (int channels, int frames)
82 {
83         DCPOMATIC_ASSERT (frames >= 0);
84         DCPOMATIC_ASSERT (channels > 0);
85
86         ScopeGuard sg = [this]() { update_data_pointers(); };
87
88         _data.resize(channels);
89         for (int channel = 0; channel < channels; ++channel) {
90                 _data[channel].resize(frames);
91         }
92 }
93
94
95 /** @param channel Channel index.
96  *  @return Buffer for this channel.
97  */
98 float*
99 AudioBuffers::data (int channel)
100 {
101         DCPOMATIC_ASSERT (channel >= 0 && channel < channels());
102         return _data[channel].data();
103 }
104
105
106 /** @param channel Channel index.
107  *  @return Buffer for this channel.
108  */
109 float const*
110 AudioBuffers::data (int channel) const
111 {
112         DCPOMATIC_ASSERT (channel >= 0 && channel < channels());
113         return _data[channel].data();
114 }
115
116
117 /** Set the number of frames in these AudioBuffers */
118 void
119 AudioBuffers::set_frames (int frames)
120 {
121         allocate(_data.size(), frames);
122 }
123
124
125 /** Make all frames silent */
126 void
127 AudioBuffers::make_silent ()
128 {
129         for (int channel = 0; channel < channels(); ++channel) {
130                 make_silent (channel);
131         }
132 }
133
134
135 /** Make all samples on a given channel silent */
136 void
137 AudioBuffers::make_silent (int channel)
138 {
139         DCPOMATIC_ASSERT (channel >= 0 && channel < channels());
140
141         /* This isn't really allowed, as all-bits-0 is not guaranteed to mean a 0 float,
142            but it seems that we can get away with it.
143         */
144         memset (data(channel), 0, frames() * sizeof(float));
145 }
146
147
148 /** Make some frames silent.
149  *  @param from Start frame.
150  */
151 void
152 AudioBuffers::make_silent (int from, int frames_to_silence)
153 {
154         DCPOMATIC_ASSERT ((from + frames_to_silence) <= frames());
155
156         for (int channel = 0; channel < channels(); ++channel) {
157                 /* This isn't really allowed, as all-bits-0 is not guaranteed to mean a 0 float,
158                    but it seems that we can get away with it.
159                 */
160                 memset (data(channel) + from, 0, frames_to_silence * sizeof(float));
161         }
162 }
163
164
165 /** Copy data from another AudioBuffers to this one.  All channels are copied.
166  *  @param from AudioBuffers to copy from; must have the same number of channels as this.
167  *  @param frames_to_copy Number of frames to copy.
168  *  @param read_offset Offset to read from in `from'.
169  *  @param write_offset Offset to write to in `to'.
170  */
171 void
172 AudioBuffers::copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset)
173 {
174         if (frames_to_copy == 0) {
175                 /* Prevent the asserts from firing if there is nothing to do */
176                 return;
177         }
178
179         DCPOMATIC_ASSERT (from);
180         DCPOMATIC_ASSERT (from->channels() == channels());
181         DCPOMATIC_ASSERT (read_offset >= 0 && (read_offset + frames_to_copy) <= from->frames());
182         DCPOMATIC_ASSERT (write_offset >= 0 && (write_offset + frames_to_copy) <= frames());
183
184         for (int channel = 0; channel < channels(); ++channel) {
185                 memcpy (data(channel) + write_offset, from->data(channel) + read_offset, frames_to_copy * sizeof(float));
186         }
187 }
188
189
190 /** Move audio data around.
191  *  @param frames_to_move Number of frames to move.
192  *  @param from Offset to move from.
193  *  @param to Offset to move to.
194  */
195 void
196 AudioBuffers::move (int frames_to_move, int from, int to)
197 {
198         if (frames_to_move == 0) {
199                 return;
200         }
201
202         DCPOMATIC_ASSERT (from >= 0);
203         DCPOMATIC_ASSERT (from < frames());
204         DCPOMATIC_ASSERT (to >= 0);
205         DCPOMATIC_ASSERT (to < frames());
206         DCPOMATIC_ASSERT (frames_to_move > 0);
207         DCPOMATIC_ASSERT (frames_to_move <= frames());
208         DCPOMATIC_ASSERT ((from + frames_to_move) <= frames());
209         DCPOMATIC_ASSERT ((to + frames_to_move) <= frames());
210
211         for (int channel = 0; channel < channels(); ++channel) {
212                 memmove (data(channel) + to, data(channel) + from, frames_to_move * sizeof(float));
213         }
214 }
215
216
217 /** Add data from from `from', `from_channel' to our channel `to_channel'.
218  *  @param from Buffers to copy data from.
219  *  @param from_channel Channel index to read in \p from.
220  *  @param to_channel Channel index to accumulate into.
221  *  @param gain Linear gain to apply to the data before it is added.
222  */
223 void
224 AudioBuffers::accumulate_channel (AudioBuffers const * from, int from_channel, int to_channel, float gain)
225 {
226         int const N = frames ();
227         DCPOMATIC_ASSERT (from->frames() == N);
228         DCPOMATIC_ASSERT (to_channel <= channels());
229
230         auto s = from->data (from_channel);
231         auto d = data(to_channel);
232
233         for (int i = 0; i < N; ++i) {
234                 *d++ += (*s++) * gain;
235         }
236 }
237
238
239 /** Mix some other buffers with these ones.  The AudioBuffers must have the same number of channels.
240  *  @param from Audio buffers to get data from.
241  *  @param frames Number of frames to mix.
242  *  @param read_offset Offset within `from' to read from.
243  *  @param write_offset Offset within this to mix into.
244  */
245 void
246 AudioBuffers::accumulate_frames (AudioBuffers const * from, int frames, int read_offset, int write_offset)
247 {
248         DCPOMATIC_ASSERT (channels() == from->channels());
249         DCPOMATIC_ASSERT (read_offset >= 0);
250         DCPOMATIC_ASSERT (write_offset >= 0);
251
252         auto from_data = from->data ();
253         for (int i = 0; i < channels(); ++i) {
254                 for (int j = 0; j < frames; ++j) {
255                         _data[i][j + write_offset] += from_data[i][j + read_offset];
256                 }
257         }
258 }
259
260
261 /** @param dB gain in dB */
262 void
263 AudioBuffers::apply_gain (float dB)
264 {
265         auto const linear = db_to_linear (dB);
266
267         for (int i = 0; i < channels(); ++i) {
268                 for (int j = 0; j < frames(); ++j) {
269                         _data[i][j] *= linear;
270                 }
271         }
272 }
273
274
275 /** @return AudioBuffers object containing only the given channel from this AudioBuffers */
276 shared_ptr<AudioBuffers>
277 AudioBuffers::channel (int channel) const
278 {
279         auto output = make_shared<AudioBuffers>(1, frames());
280         output->copy_channel_from (this, channel, 0);
281         return output;
282 }
283
284
285 /** Copy all the samples from a channel on another AudioBuffers to a channel on this one.
286  *  @param from AudioBuffers to copy from.
287  *  @param from_channel Channel index in `from' to copy from.
288  *  @param to_channel Channel index in this to copy into, overwriting what's already there.
289  */
290 void
291 AudioBuffers::copy_channel_from (AudioBuffers const * from, int from_channel, int to_channel)
292 {
293         DCPOMATIC_ASSERT (from->frames() == frames());
294         memcpy (data(to_channel), from->data(from_channel), frames() * sizeof (float));
295 }
296
297
298 /** Make a copy of these AudioBuffers */
299 shared_ptr<AudioBuffers>
300 AudioBuffers::clone () const
301 {
302         auto b = make_shared<AudioBuffers>(channels(), frames());
303         b->copy_from (this, frames(), 0, 0);
304         return b;
305 }
306
307
308 /** Extend these buffers with the data from another.  The AudioBuffers must have the same number of channels. */
309 void
310 AudioBuffers::append (shared_ptr<const AudioBuffers> other)
311 {
312         DCPOMATIC_ASSERT (channels() == other->channels());
313         auto old_frames = frames();
314         set_frames(old_frames + other->frames());
315         copy_from (other.get(), other->frames(), 0, old_frames);
316 }
317
318
319 /** Remove some frames from the start of these AudioBuffers */
320 void
321 AudioBuffers::trim_start (int frames_to_trim)
322 {
323         DCPOMATIC_ASSERT (frames_to_trim <= frames());
324         move (frames() - frames_to_trim, frames_to_trim, 0);
325         set_frames (frames() - frames_to_trim);
326 }
327
328
329 void
330 AudioBuffers::update_data_pointers ()
331 {
332         _data_pointers.resize (channels());
333         for (int i = 0; i < channels(); ++i) {
334                 _data_pointers[i] = _data[i].data();
335         }
336 }
337