Apply panners/automation patch from torbenh (Panner is-a Processor).
[ardour.git] / libs / ardour / export_utilities.cc
1 /*
2     Copyright (C) 1999-2008 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 /* see gdither.cc for why we have to do this */
21
22 #define _ISOC9X_SOURCE  1
23 #define _ISOC99_SOURCE  1
24 #include <cmath>
25 #undef  _ISOC99_SOURCE
26 #undef  _ISOC9X_SOURCE
27 #undef  __USE_SVID 
28 #define __USE_SVID 1
29 #include <cstdlib>
30 #undef  __USE_SVID
31
32 #include <unistd.h>
33 #include <inttypes.h>
34 #include <float.h>
35
36 /* ...*/
37
38 #include <ardour/export_utilities.h>
39
40 #include <string.h>
41
42 #include <ardour/export_failed.h>
43 #include <ardour/gdither.h>
44 #include <ardour/dB.h>
45 #include <pbd/failed_constructor.h>
46
47 #include "i18n.h"
48
49 using namespace PBD;
50
51 namespace ARDOUR
52 {
53 /* SampleRateConverter */
54
55 SampleRateConverter::SampleRateConverter (uint32_t channels, nframes_t in_rate, nframes_t out_rate, int quality) :
56   channels (channels),
57   leftover_frames (0),
58   data_in (0),
59   leftover_data (0),
60   data_out (0),
61   data_out_size (0),
62   src_state (0)
63 {
64         if (in_rate == out_rate) {
65                 active = false;
66                 return;
67         }
68         
69         active = true;
70         int err;
71
72         if ((src_state = src_new (quality, channels, &err)) == 0) {
73                 throw ExportFailed (string_compose (X_("Cannot initialize sample rate conversion: %1"), src_strerror (err)));
74         }
75         
76         src_data.src_ratio = out_rate / (double) in_rate;
77 }
78
79 SampleRateConverter::~SampleRateConverter ()
80 {
81         if (src_state) {
82                 src_delete (src_state);
83         }
84         if (data_out) {
85                 delete [] data_out;
86         }
87         if (leftover_data) {
88                 free (leftover_data);
89         }
90 }
91
92 nframes_t
93 SampleRateConverter::process (float * data, nframes_t frames)
94 {
95         if (!active) {
96                 // Just pass it on...
97                 return piped_to->write (data, frames);
98         }
99
100         /* Manage memory */
101         
102         nframes_t out_samples_max = (nframes_t) ceil (frames * src_data.src_ratio * channels);
103         if (data_out_size < out_samples_max) {
104
105                 free (data_out);
106                 data_out = new float[out_samples_max];
107                 src_data.data_out = data_out;
108                 
109                 max_leftover_frames = 4 * frames;
110                 leftover_data = (float *) realloc (leftover_data, max_leftover_frames * channels * sizeof (float));
111                 if (!leftover_data) {
112                         throw ExportFailed (X_("A memory allocation error occured during sample rate conversion"));
113                 }
114                 
115                 data_out_size = out_samples_max;
116         }
117
118         /* Do SRC */
119
120         data_in = data;
121         frames_in = frames;
122
123         int err;
124         int cnt = 0;
125         nframes_t frames_out_total = 0;
126         
127         do {
128                 src_data.output_frames = out_samples_max / channels;
129                 src_data.end_of_input = end_of_input;
130                 src_data.data_out = data_out;
131
132                 if (leftover_frames > 0) {
133
134                         /* input data will be in leftover_data rather than data_in */
135
136                         src_data.data_in = leftover_data;
137
138                         if (cnt == 0) {
139                                 
140                                 /* first time, append new data from data_in into the leftover_data buffer */
141
142                                 memcpy (leftover_data + (leftover_frames * channels), data_in, frames_in * channels * sizeof(float));
143                                 src_data.input_frames = frames_in + leftover_frames;
144                         } else {
145                                 
146                                 /* otherwise, just use whatever is still left in leftover_data; the contents
147                                         were adjusted using memmove() right after the last SRC call (see
148                                         below)
149                                 */
150
151                                 src_data.input_frames = leftover_frames;
152                         }
153                                 
154                 } else {
155
156                         src_data.data_in = data_in;
157                         src_data.input_frames = frames_in;
158
159                 }
160
161                 ++cnt;
162
163                 if ((err = src_process (src_state, &src_data)) != 0) {
164                         throw ExportFailed (string_compose ("An error occured during sample rate conversion: %1", src_strerror (err)));
165                 }
166         
167                 frames_out = src_data.output_frames_gen;
168                 leftover_frames = src_data.input_frames - src_data.input_frames_used;
169
170                 if (leftover_frames > 0) {
171                         if (leftover_frames > max_leftover_frames) {
172                                 error << _("warning, leftover frames overflowed, glitches might occur in output") << endmsg;
173                                 leftover_frames = max_leftover_frames;
174                         }
175                         memmove (leftover_data, (char *) (src_data.data_in + (src_data.input_frames_used * channels)),
176                                         leftover_frames * channels * sizeof(float));
177                 }
178                 
179                 
180                 nframes_t frames_written = piped_to->write (data_out, frames_out);
181                 if (frames_written < 0) {
182                         return frames_written;
183                 } else {
184                         frames_out_total += frames_written;
185                 }
186
187         } while (leftover_frames > frames_in);
188
189         
190         return frames_out_total;
191 }
192
193 /* SampleFormatConverter */
194
195 template <typename TOut>
196 SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels, ExportFormatBase::DitherType type, int data_width_) :
197   channels (channels),
198   data_width (data_width_),
199   dither (0),
200   data_out_size (0),
201   data_out (0),
202   clip_floats (false)
203 {
204         if (data_width != 24) {
205                 data_width = sizeof (TOut) * 8;
206         }
207         
208         GDitherSize dither_size = GDitherFloat;
209
210         switch (data_width) {
211         case 8:
212                 dither_size = GDither8bit;
213                 break;
214
215         case 16:
216                 dither_size = GDither16bit;
217                 break;
218         case 24:
219                 dither_size = GDither32bit;
220         }
221         
222         dither = gdither_new ((GDitherType) type, channels, dither_size, data_width);
223 }
224
225 template <typename TOut>
226 SampleFormatConverter<TOut>::~SampleFormatConverter ()
227 {
228         if (dither) {
229                 gdither_free (dither);
230         }
231         if (data_out) {
232                 delete data_out;
233         }
234 }
235
236 template <typename TOut>
237 nframes_t
238 SampleFormatConverter<TOut>::process (float * data, nframes_t frames)
239 {
240         /* Make sure we have enough memory allocated */
241         
242         size_t data_size = channels * frames * sizeof (TOut);
243         if (data_size  > data_out_size) {
244                 free (data_out);
245                 data_out = new TOut[data_size];
246                 data_out_size = data_size;
247         }
248         
249         /* Do conversion */
250         
251         if (data_width < 32) {
252                 for (uint32_t chn = 0; chn < channels; ++chn) {
253                         gdither_runf (dither, chn, frames, data, data_out);
254                 }
255         } else {
256                 for (uint32_t chn = 0; chn < channels; ++chn) {
257                         
258                         TOut * ob = data_out;
259                         const double int_max = (float) INT_MAX;
260                         const double int_min = (float) INT_MIN;
261                 
262                         nframes_t i;
263                         for (nframes_t x = 0; x < frames; ++x) {
264                                 i = chn + (x * channels);
265                         
266                                 if (data[i] > 1.0f) {
267                                         ob[i] = static_cast<TOut> (INT_MAX);
268                                 } else if (data[i] < -1.0f) {
269                                         ob[i] = static_cast<TOut> (INT_MIN);
270                                 } else {
271                                         if (data[i] >= 0.0f) {
272                                                 ob[i] = lrintf (int_max * data[i]);
273                                         } else {
274                                                 ob[i] = - lrintf (int_min * data[i]);
275                                         }
276                                 }
277                         }
278                 }
279         }
280         
281         /* Write forward */
282         
283         return GraphSinkVertex<float, TOut>::piped_to->write (data_out, frames);
284 }
285
286 template<>
287 nframes_t
288 SampleFormatConverter<float>::process (float * data, nframes_t frames)
289 {
290         if (clip_floats) {
291                 for (nframes_t x = 0; x < frames * channels; ++x) {
292                         if (data[x] > 1.0f) {
293                                 data[x] = 1.0f;
294                         } else if (data[x] < -1.0f) {
295                                 data[x] = -1.0f;
296                         } 
297                 }
298         }
299         
300         return piped_to->write (data, frames);
301 }
302
303 template class SampleFormatConverter<short>;
304 template class SampleFormatConverter<int>;
305 template class SampleFormatConverter<float>;
306
307 /* Normalizer */
308
309 Normalizer::Normalizer (uint32_t channels, float target_dB) :
310   channels (channels),
311   enabled (false)
312 {
313         target = dB_to_coefficient (target_dB); 
314         
315         if (target == 1.0f) {
316                 /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
317                    that we may have clipped.
318                 */
319                 target -= FLT_EPSILON;
320         }
321 }
322
323 Normalizer::~Normalizer ()
324 {
325
326 }
327
328 void
329 Normalizer::set_peak (float peak)
330 {       
331         if (peak == 0.0f || peak == target) {
332                 /* don't even try */
333                 enabled = false;
334         } else {
335                 enabled = true;
336                 gain = target / peak;
337         }
338 }
339
340 nframes_t
341 Normalizer::process (float * data, nframes_t frames)
342 {
343         if (enabled) {
344                 for (nframes_t i = 0; i < (channels * frames); ++i) {
345                         data[i] *= gain;
346                 }
347         }
348         return piped_to->write (data, frames);
349 }
350
351 };