NOOP, remove trailing tabs/whitespace.
[ardour.git] / libs / audiographer / src / general / sample_format_converter.cc
1 /*
2     Copyright (C) 2012 Paul Davis
3     Author: Sakari Bergen
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include "audiographer/general/sample_format_converter.h"
22
23 #include "audiographer/exception.h"
24 #include "audiographer/type_utils.h"
25 #include "private/gdither/gdither.h"
26
27 #include <boost/format.hpp>
28
29 namespace AudioGrapher
30 {
31
32 template <typename TOut>
33 SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
34   channels (channels),
35   dither (0),
36   data_out_size (0),
37   data_out (0),
38   clip_floats (false)
39 {
40 }
41
42 template <>
43 void
44 SampleFormatConverter<float>::init (framecnt_t max_frames, int /* type */, int data_width)
45 {
46         if (throw_level (ThrowObject) && data_width != 32) {
47                 throw Exception (*this, "Unsupported data width");
48         }
49         init_common (max_frames);
50         dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
51 }
52
53 template <>
54 void
55 SampleFormatConverter<int32_t>::init (framecnt_t max_frames, int type, int data_width)
56 {
57         if(throw_level (ThrowObject) && data_width > 32) {
58                 throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> with a data width > 32");
59         }
60
61         // GDither is broken with GDither32bit if the dither depth is bigger than 24.
62         // And since floats only have 24 bits of data, we are fine with this.
63         data_width = std::min(data_width, 24);
64
65         init_common (max_frames);
66         dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
67 }
68
69 template <>
70 void
71 SampleFormatConverter<int16_t>::init (framecnt_t max_frames, int type, int data_width)
72 {
73         if (throw_level (ThrowObject) && data_width > 16) {
74                 throw Exception (*this, boost::str(boost::format
75                     ("Data width (%1%) too large for int16_t")
76                     % data_width));
77         }
78         init_common (max_frames);
79         dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
80 }
81
82 template <>
83 void
84 SampleFormatConverter<uint8_t>::init (framecnt_t max_frames, int type, int data_width)
85 {
86         if (throw_level (ThrowObject) && data_width > 8) {
87                 throw Exception (*this, boost::str(boost::format
88                     ("Data width (%1%) too large for uint8_t")
89                     % data_width));
90         }
91         init_common (max_frames);
92         dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
93 }
94
95 template <typename TOut>
96 void
97 SampleFormatConverter<TOut>::init_common (framecnt_t max_frames)
98 {
99         reset();
100         if (max_frames  > data_out_size) {
101
102                 delete[] data_out;
103
104                 data_out = new TOut[max_frames];
105                 data_out_size = max_frames;
106         }
107 }
108
109 template <typename TOut>
110 SampleFormatConverter<TOut>::~SampleFormatConverter ()
111 {
112         reset();
113 }
114
115 template <typename TOut>
116 void
117 SampleFormatConverter<TOut>::reset()
118 {
119         if (dither) {
120                 gdither_free (dither);
121                 dither = 0;
122         }
123
124         delete[] data_out;
125         data_out_size = 0;
126         data_out = 0;
127
128         clip_floats = false;
129 }
130
131 /* Basic const version of process() */
132 template <typename TOut>
133 void
134 SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
135 {
136         float const * const data = c_in.data();
137
138         check_frame_and_channel_count (c_in.frames (), c_in.channels ());
139
140         /* Do conversion */
141
142         for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
143                 gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
144         }
145
146         /* Write forward */
147
148         ProcessContext<TOut> c_out(c_in, data_out);
149         this->output (c_out);
150 }
151
152 /* Basic non-const version of process(), calls the const one */
153 template<typename TOut>
154 void
155 SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
156 {
157         process (static_cast<ProcessContext<float> const &> (c_in));
158 }
159
160 /* template specialization for float, in-place processing (non-const) */
161 template<>
162 void
163 SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
164 {
165         framecnt_t frames = c_in.frames();
166         float * data = c_in.data();
167
168         if (clip_floats) {
169                 for (framecnt_t x = 0; x < frames; ++x) {
170                         if (data[x] > 1.0f) {
171                                 data[x] = 1.0f;
172                         } else if (data[x] < -1.0f) {
173                                 data[x] = -1.0f;
174                         }
175                 }
176         }
177
178         output (c_in);
179 }
180
181 /* template specialized const version, copies the data, and calls the non-const version */
182 template<>
183 void
184 SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
185 {
186         // Make copy of data and pass it to non-const version
187         check_frame_and_channel_count (c_in.frames(), c_in.channels());
188         TypeUtils<float>::copy (c_in.data(), data_out, c_in.frames());
189
190         ProcessContext<float> c (c_in, data_out);
191         process (c);
192 }
193
194 template<typename TOut>
195 void
196 SampleFormatConverter<TOut>::check_frame_and_channel_count (framecnt_t frames, ChannelCount channels_)
197 {
198         if (throw_level (ThrowStrict) && channels_ != channels) {
199                 throw Exception (*this, boost::str (boost::format
200                         ("Wrong channel count given to process(), %1% instead of %2%")
201                         % channels_ % channels));
202         }
203
204         if (throw_level (ThrowProcess) && frames  > data_out_size) {
205                 throw Exception (*this, boost::str (boost::format
206                         ("Too many frames given to process(), %1% instad of %2%")
207                         % frames % data_out_size));
208         }
209 }
210
211 template class SampleFormatConverter<uint8_t>;
212 template class SampleFormatConverter<int16_t>;
213 template class SampleFormatConverter<int32_t>;
214 template class SampleFormatConverter<float>;
215
216 } // namespace