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