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