Zero 'lost' frames when audio buffer frame counts are dropped.
[dcpomatic.git] / src / lib / audio_buffers.cc
1 /*
2     Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
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 <cassert>
21 #include <cstring>
22 #include <stdexcept>
23 #include "audio_buffers.h"
24
25 using std::bad_alloc;
26 using boost::shared_ptr;
27
28 /** Construct an AudioBuffers.  Audio data is undefined after this constructor.
29  *  @param channels Number of channels.
30  *  @param frames Number of frames to reserve space for.
31  */
32 AudioBuffers::AudioBuffers (int channels, int frames)
33 {
34         allocate (channels, frames);
35 }
36
37 /** Copy constructor.
38  *  @param other Other AudioBuffers; data is copied.
39  */
40 AudioBuffers::AudioBuffers (AudioBuffers const & other)
41 {
42         allocate (other._channels, other._frames);
43         copy_from (&other, other._frames, 0, 0);
44 }
45
46 AudioBuffers::AudioBuffers (boost::shared_ptr<const AudioBuffers> other)
47 {
48         allocate (other->_channels, other->_frames);
49         copy_from (other.get(), other->_frames, 0, 0);
50 }
51
52 AudioBuffers &
53 AudioBuffers::operator= (AudioBuffers const & other)
54 {
55         if (this == &other) {
56                 return *this;
57         }
58                 
59         deallocate ();
60         allocate (other._channels, other._frames);
61         copy_from (&other, other._frames, 0, 0);
62
63         return *this;
64 }
65
66 /** AudioBuffers destructor */
67 AudioBuffers::~AudioBuffers ()
68 {
69         deallocate ();
70 }
71
72 void
73 AudioBuffers::allocate (int channels, int frames)
74 {
75         _channels = channels;
76         _frames = frames;
77         _allocated_frames = frames;
78         
79         _data = static_cast<float**> (malloc (_channels * sizeof (float *)));
80         if (!_data) {
81                 throw bad_alloc ();
82         }
83         
84         for (int i = 0; i < _channels; ++i) {
85                 _data[i] = static_cast<float*> (malloc (frames * sizeof (float)));
86                 if (!_data[i]) {
87                         throw bad_alloc ();
88                 }
89         }
90 }
91
92 void
93 AudioBuffers::deallocate ()
94 {
95         for (int i = 0; i < _channels; ++i) {
96                 free (_data[i]);
97         }
98
99         free (_data);
100 }
101
102 /** @param c Channel index.
103  *  @return Buffer for this channel.
104  */
105 float*
106 AudioBuffers::data (int c) const
107 {
108         assert (c >= 0 && c < _channels);
109         return _data[c];
110 }
111
112 /** Set the number of frames that these AudioBuffers will report themselves
113  *  as having.  If we reduce the number of frames, the `lost' frames will
114  *  be silenced.
115  *  @param f Frames; must be less than or equal to the number of allocated frames.
116  */
117 void
118 AudioBuffers::set_frames (int f)
119 {
120         assert (f <= _allocated_frames);
121
122         for (int c = 0; c < _channels; ++c) {
123                 for (int i = f; i < _frames; ++i) {
124                         _data[c][i] = 0;
125                 }
126         }
127         
128         _frames = f;
129 }
130
131 /** Make all samples on all channels silent */
132 void
133 AudioBuffers::make_silent ()
134 {
135         for (int i = 0; i < _channels; ++i) {
136                 make_silent (i);
137         }
138 }
139
140 /** Make all samples on a given channel silent.
141  *  @param c Channel.
142  */
143 void
144 AudioBuffers::make_silent (int c)
145 {
146         assert (c >= 0 && c < _channels);
147         
148         for (int i = 0; i < _frames; ++i) {
149                 _data[c][i] = 0;
150         }
151 }
152
153 void
154 AudioBuffers::make_silent (int from, int frames)
155 {
156         assert ((from + frames) <= _allocated_frames);
157
158         for (int c = 0; c < _channels; ++c) {
159                 for (int i = from; i < (from + frames); ++i) {
160                         _data[c][i] = 0;
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         assert (from->channels() == channels());
175
176         assert (from);
177         assert (read_offset >= 0 && (read_offset + frames_to_copy) <= from->_allocated_frames);
178         assert (write_offset >= 0 && (write_offset + frames_to_copy) <= _allocated_frames);
179
180         for (int i = 0; i < _channels; ++i) {
181                 memcpy (_data[i] + write_offset, from->_data[i] + read_offset, frames_to_copy * sizeof(float));
182         }
183 }
184
185 /** Move audio data around.
186  *  @param from Offset to move from.
187  *  @param to Offset to move to.
188  *  @param frames Number of frames to move.
189  */
190     
191 void
192 AudioBuffers::move (int from, int to, int frames)
193 {
194         if (frames == 0) {
195                 return;
196         }
197         
198         assert (from >= 0);
199         assert (from < _frames);
200         assert (to >= 0);
201         assert (to < _frames);
202         assert (frames > 0);
203         assert (frames <= _frames);
204         assert ((from + frames) <= _frames);
205         assert ((to + frames) <= _allocated_frames);
206         
207         for (int i = 0; i < _channels; ++i) {
208                 memmove (_data[i] + to, _data[i] + from, frames * sizeof(float));
209         }
210 }
211
212 /** Add data from from `from', `from_channel' to our channel `to_channel' */
213 void
214 AudioBuffers::accumulate_channel (AudioBuffers const * from, int from_channel, int to_channel)
215 {
216         int const N = frames ();
217         assert (from->frames() == N);
218         assert (to_channel <= _channels);
219
220         float* s = from->data (from_channel);
221         float* d = _data[to_channel];
222
223         for (int i = 0; i < N; ++i) {
224                 *d++ += *s++;
225         }
226 }
227
228 /** Ensure we have space for at least a certain number of frames.  If we extend
229  *  the buffers, fill the new space with silence.
230  */
231 void
232 AudioBuffers::ensure_size (int frames)
233 {
234         if (_allocated_frames >= frames) {
235                 return;
236         }
237
238         for (int i = 0; i < _channels; ++i) {
239                 _data[i] = static_cast<float*> (realloc (_data[i], frames * sizeof (float)));
240                 if (!_data[i]) {
241                         throw bad_alloc ();
242                 }
243                 for (int j = _allocated_frames; j < frames; ++j) {
244                         _data[i][j] = 0;
245                 }
246         }
247
248         _allocated_frames = frames;
249 }
250
251 void
252 AudioBuffers::accumulate_frames (AudioBuffers const * from, int read_offset, int write_offset, int frames)
253 {
254         assert (_channels == from->channels ());
255
256         for (int i = 0; i < _channels; ++i) {
257                 for (int j = 0; j < frames; ++j) {
258                         _data[i][j + write_offset] += from->data()[i][j + read_offset];
259                 }
260         }
261 }
262