2 Copyright (C) 2012 Paul Davis
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.
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.
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.
21 #include "audiographer/general/sample_format_converter.h"
23 #include "audiographer/exception.h"
24 #include "audiographer/type_utils.h"
25 #include "private/gdither/gdither.h"
27 #include <boost/format.hpp>
29 namespace AudioGrapher
32 template <typename TOut>
33 SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
44 SampleFormatConverter<float>::init (framecnt_t max_frames, int /* type */, int data_width)
46 if (throw_level (ThrowObject) && data_width != 32) {
47 throw Exception (*this, "Unsupported data width");
49 init_common (max_frames);
50 dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
55 SampleFormatConverter<int32_t>::init (framecnt_t max_frames, int type, int data_width)
57 if(throw_level (ThrowObject) && data_width > 32) {
58 throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> with a data width > 32");
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);
65 init_common (max_frames);
66 dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
71 SampleFormatConverter<int16_t>::init (framecnt_t max_frames, int type, int data_width)
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")
78 init_common (max_frames);
79 dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
84 SampleFormatConverter<uint8_t>::init (framecnt_t max_frames, int type, int data_width)
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")
91 init_common (max_frames);
92 dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
95 template <typename TOut>
97 SampleFormatConverter<TOut>::init_common (framecnt_t max_frames)
100 if (max_frames > data_out_size) {
104 data_out = new TOut[max_frames];
105 data_out_size = max_frames;
109 template <typename TOut>
110 SampleFormatConverter<TOut>::~SampleFormatConverter ()
115 template <typename TOut>
117 SampleFormatConverter<TOut>::reset()
120 gdither_free (dither);
131 /* Basic const version of process() */
132 template <typename TOut>
134 SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
136 float const * const data = c_in.data();
138 check_frame_and_channel_count (c_in.frames (), c_in.channels ());
142 for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
143 gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
148 ProcessContext<TOut> c_out(c_in, data_out);
149 this->output (c_out);
152 /* Basic non-const version of process(), calls the const one */
153 template<typename TOut>
155 SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
157 process (static_cast<ProcessContext<float> const &> (c_in));
160 /* template specialization for float, in-place processing (non-const) */
163 SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
165 framecnt_t frames = c_in.frames();
166 float * data = c_in.data();
169 for (framecnt_t x = 0; x < frames; ++x) {
170 if (data[x] > 1.0f) {
172 } else if (data[x] < -1.0f) {
181 /* template specialized const version, copies the data, and calls the non-const version */
184 SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
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());
190 ProcessContext<float> c (c_in, data_out);
194 template<typename TOut>
196 SampleFormatConverter<TOut>::check_frame_and_channel_count (framecnt_t frames, ChannelCount channels_)
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));
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));
211 template class SampleFormatConverter<uint8_t>;
212 template class SampleFormatConverter<int16_t>;
213 template class SampleFormatConverter<int32_t>;
214 template class SampleFormatConverter<float>;