Remove all use of nframes_t.
[ardour.git] / libs / audiographer / src / general / sample_format_converter.cc
1 #include "audiographer/general/sample_format_converter.h"
2
3 #include "audiographer/exception.h"
4 #include "audiographer/type_utils.h"
5 #include "private/gdither/gdither.h"
6
7 #include <boost/format.hpp>
8
9 namespace AudioGrapher
10 {
11
12 template <typename TOut>
13 SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
14   channels (channels),
15   dither (0),
16   data_out_size (0),
17   data_out (0),
18   clip_floats (false)
19 {
20 }
21
22 template <>
23 void
24 SampleFormatConverter<float>::init (framecnt_t max_frames, int /* type */, int data_width)
25 {
26         if (throw_level (ThrowObject) && data_width != 32) {
27                 throw Exception (*this, "Unsupported data width");
28         }
29         init_common (max_frames);
30         dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
31 }
32
33 template <>
34 void
35 SampleFormatConverter<int32_t>::init (framecnt_t max_frames, int type, int data_width)
36 {
37         if(throw_level (ThrowObject) && data_width < 24) {
38                 throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> for data widths < 24");
39         }
40         
41         init_common (max_frames);
42         
43         if (data_width == 24) {
44                 dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
45         } else if (data_width == 32) {
46                 dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
47         } else if (throw_level (ThrowObject)) {
48                 throw Exception (*this, "Unsupported data width");
49         }
50 }
51
52 template <>
53 void
54 SampleFormatConverter<int16_t>::init (framecnt_t max_frames, int type, int data_width)
55 {
56         if (throw_level (ThrowObject) && data_width != 16) {
57                 throw Exception (*this, "Unsupported data width");
58         }
59         init_common (max_frames);
60         dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
61 }
62
63 template <>
64 void
65 SampleFormatConverter<uint8_t>::init (framecnt_t max_frames, int type, int data_width)
66 {
67         if (throw_level (ThrowObject) && data_width != 8) {
68                 throw Exception (*this, "Unsupported data width");
69         }
70         init_common (max_frames);
71         dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
72 }
73
74 template <typename TOut>
75 void
76 SampleFormatConverter<TOut>::init_common (framecnt_t max_frames)
77 {
78         reset();
79         if (max_frames  > data_out_size) {
80
81                 delete[] data_out;
82
83                 data_out = new TOut[max_frames];
84                 data_out_size = max_frames;
85         }
86 }
87
88 template <typename TOut>
89 SampleFormatConverter<TOut>::~SampleFormatConverter ()
90 {
91         reset();
92 }
93
94 template <typename TOut>
95 void
96 SampleFormatConverter<TOut>::reset()
97 {
98         if (dither) {
99                 gdither_free (dither);
100                 dither = 0;
101         }
102         
103         delete[] data_out;
104         data_out_size = 0;
105         data_out = 0;
106         
107         clip_floats = false;
108 }
109
110 /* Basic const version of process() */
111 template <typename TOut>
112 void
113 SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
114 {
115         float const * const data = c_in.data();
116         
117         check_frame_and_channel_count (c_in.frames (), c_in.channels ());
118
119         /* Do conversion */
120
121         for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
122                 gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
123         }
124
125         /* Write forward */
126
127         ProcessContext<TOut> c_out(c_in, data_out);
128         output (c_out);
129 }
130
131 /* Basic non-const version of process(), calls the const one */
132 template<typename TOut>
133 void
134 SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
135 {
136         process (static_cast<ProcessContext<float> const &> (c_in));
137 }
138
139 /* template specialization for float, in-place processing (non-const) */
140 template<>
141 void
142 SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
143 {
144         framecnt_t frames = c_in.frames();
145         float * data = c_in.data();
146         
147         if (clip_floats) {
148                 for (framecnt_t x = 0; x < frames; ++x) {
149                         if (data[x] > 1.0f) {
150                                 data[x] = 1.0f;
151                         } else if (data[x] < -1.0f) {
152                                 data[x] = -1.0f;
153                         }
154                 }
155         }
156
157         output (c_in);
158 }
159
160 /* template specialized const version, copies the data, and calls the non-const version */
161 template<>
162 void
163 SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
164 {
165         // Make copy of data and pass it to non-const version
166         check_frame_and_channel_count (c_in.frames(), c_in.channels());
167         TypeUtils<float>::copy (c_in.data(), data_out, c_in.frames());
168         
169         ProcessContext<float> c (c_in, data_out);
170         process (c);
171 }
172
173 template<typename TOut>
174 void
175 SampleFormatConverter<TOut>::check_frame_and_channel_count (framecnt_t frames, ChannelCount channels_)
176 {
177         if (throw_level (ThrowStrict) && channels_ != channels) {
178                 throw Exception (*this, boost::str (boost::format
179                         ("Wrong channel count given to process(), %1% instead of %2%")
180                         % channels_ % channels));
181         }
182         
183         if (throw_level (ThrowProcess) && frames  > data_out_size) {
184                 throw Exception (*this, boost::str (boost::format
185                         ("Too many frames given to process(), %1% instad of %2%")
186                         % frames % data_out_size));
187         }
188 }
189
190 template class SampleFormatConverter<uint8_t>;
191 template class SampleFormatConverter<int16_t>;
192 template class SampleFormatConverter<int32_t>;
193 template class SampleFormatConverter<float>;
194
195 } // namespace