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