1 #include "audiographer/sample_format_converter.h"
3 #include "gdither/gdither.h"
4 #include "audiographer/exception.h"
6 #include <boost/format.hpp>
10 namespace AudioGrapher
13 template <typename TOut>
14 SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels) :
25 SampleFormatConverter<float>::init (nframes_t max_frames, int type, int data_width)
27 if (data_width != 32) { throw Exception (*this, "Unsupported data width"); }
28 init_common (max_frames);
29 dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
34 SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_width)
36 if(data_width < 24) { throw Exception (*this, "Use SampleFormatConverter<int16_t> for data widths < 24"); }
38 init_common (max_frames);
40 if (data_width == 24) {
41 dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
42 } else if (data_width == 32) {
43 dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
45 throw Exception (*this, "Unsupported data width");
51 SampleFormatConverter<int16_t>::init (nframes_t max_frames, int type, int data_width)
53 if (data_width != 16) { throw Exception (*this, "Unsupported data width"); }
54 init_common (max_frames);
55 dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
60 SampleFormatConverter<uint8_t>::init (nframes_t max_frames, int type, int data_width)
62 if (data_width != 8) { throw Exception (*this, "Unsupported data width"); }
63 init_common (max_frames);
64 dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
67 template <typename TOut>
69 SampleFormatConverter<TOut>::init_common (nframes_t max_frames )
72 if (max_frames > data_out_size) {
76 data_out = new TOut[max_frames];
77 data_out_size = max_frames;
81 template <typename TOut>
82 SampleFormatConverter<TOut>::~SampleFormatConverter ()
87 template <typename TOut>
89 SampleFormatConverter<TOut>::reset()
92 gdither_free (dither);
103 /* Basic const version of process() */
104 template <typename TOut>
106 SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
108 float const * const data = c_in.data();
109 nframes_t const frames = c_in.frames();
111 check_frame_count (frames);
115 for (uint32_t chn = 0; chn < channels; ++chn) {
116 gdither_runf (dither, chn, frames / channels, data, data_out);
121 ProcessContext<TOut> c_out(c_in, data_out);
125 /* Basic non-const version of process(), calls the const one */
126 template<typename TOut>
128 SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
130 process (static_cast<ProcessContext<float> const &> (c_in));
133 /* template specialization for float, in-place processing (non-const) */
136 SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
138 nframes_t frames = c_in.frames();
139 float * data = c_in.data();
142 for (nframes_t x = 0; x < frames; ++x) {
143 if (data[x] > 1.0f) {
145 } else if (data[x] < -1.0f) {
154 /* template specialized const version, copies the data, and calls the non-const version */
157 SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
159 // Make copy of data and pass it to non-const version
160 nframes_t frames = c_in.frames();
161 check_frame_count (frames);
162 memcpy (data_out, c_in.data(), frames * sizeof(float));
164 ProcessContext<float> c (c_in, data_out);
168 template<typename TOut>
170 SampleFormatConverter<TOut>::check_frame_count(nframes_t frames)
172 if (frames % channels != 0) {
173 throw Exception (*this, boost::str (boost::format (
174 "Number of frames given to process() was not a multiple of channels: %1% frames with %2% channels")
175 % frames % channels));
178 if (frames > data_out_size) {
179 throw Exception (*this, boost::str (boost::format (
180 "Too many frames given to process(), %1% instad of %2%")
181 % frames % data_out_size));
185 template class SampleFormatConverter<uint8_t>;
186 template class SampleFormatConverter<int16_t>;
187 template class SampleFormatConverter<int32_t>;
188 template class SampleFormatConverter<float>;