1 #include "audiographer/general/sr_converter.h"
3 #include "audiographer/exception.h"
4 #include "audiographer/type_utils.h"
7 #include <boost/format.hpp>
14 SampleRateConverter::SampleRateConverter (uint32_t channels)
20 , max_leftover_frames (0)
25 add_supported_flag (ProcessContext<>::EndOfInput);
29 SampleRateConverter::init (framecnt_t in_rate, framecnt_t out_rate, int quality)
33 if (in_rate == out_rate) {
34 src_data.src_ratio = 1;
40 src_state = src_new (quality, channels, &err);
41 if (throw_level (ThrowObject) && !src_state) {
42 throw Exception (*this, str (format
43 ("Cannot initialize sample rate converter: %1%")
44 % src_strerror (err)));
47 src_data.src_ratio = (double) out_rate / (double) in_rate;
50 SampleRateConverter::~SampleRateConverter ()
56 SampleRateConverter::allocate_buffers (framecnt_t max_frames)
58 if (!active) { return max_frames; }
60 framecnt_t max_frames_out = (framecnt_t) ceil (max_frames * src_data.src_ratio);
61 if (data_out_size < max_frames_out) {
64 data_out = new float[max_frames_out];
65 src_data.data_out = data_out;
67 max_leftover_frames = 4 * max_frames;
68 leftover_data = (float *) realloc (leftover_data, max_leftover_frames * sizeof (float));
69 if (throw_level (ThrowObject) && !leftover_data) {
70 throw Exception (*this, "A memory allocation error occured");
73 max_frames_in = max_frames;
74 data_out_size = max_frames_out;
77 return max_frames_out;
81 SampleRateConverter::process (ProcessContext<float> const & c)
83 check_flags (*this, c);
90 framecnt_t frames = c.frames();
91 float * in = const_cast<float *> (c.data()); // TODO check if this is safe!
93 if (throw_level (ThrowProcess) && frames > max_frames_in) {
94 throw Exception (*this, str (format (
95 "process() called with too many frames, %1% instead of %2%")
96 % frames % max_frames_in));
100 bool first_time = true;
103 src_data.output_frames = data_out_size / channels;
104 src_data.data_out = data_out;
106 if (leftover_frames > 0) {
108 /* input data will be in leftover_data rather than data_in */
110 src_data.data_in = leftover_data;
114 /* first time, append new data from data_in into the leftover_data buffer */
116 TypeUtils<float>::copy (in, &leftover_data [leftover_frames * channels], frames);
117 src_data.input_frames = frames / channels + leftover_frames;
120 /* otherwise, just use whatever is still left in leftover_data; the contents
121 were adjusted using memmove() right after the last SRC call (see
125 src_data.input_frames = leftover_frames;
129 src_data.data_in = in;
130 src_data.input_frames = frames / channels;
135 if (debug_level (DebugVerbose)) {
136 debug_stream() << "data_in: " << src_data.data_in <<
137 ", input_frames: " << src_data.input_frames <<
138 ", data_out: " << src_data.data_out <<
139 ", output_frames: " << src_data.output_frames << std::endl;
142 err = src_process (src_state, &src_data);
143 if (throw_level (ThrowProcess) && err) {
144 throw Exception (*this, str (format
145 ("An error occured during sample rate conversion: %1%")
146 % src_strerror (err)));
149 leftover_frames = src_data.input_frames - src_data.input_frames_used;
151 if (leftover_frames > 0) {
152 if (throw_level (ThrowProcess) && leftover_frames > max_leftover_frames) {
153 throw Exception(*this, "leftover frames overflowed");
155 TypeUtils<float>::move (&src_data.data_in[src_data.input_frames_used * channels],
156 leftover_data, leftover_frames * channels);
159 ProcessContext<float> c_out (c, data_out, src_data.output_frames_gen * channels);
160 if (!src_data.end_of_input || leftover_frames) {
161 c_out.remove_flag (ProcessContext<float>::EndOfInput);
165 if (debug_level (DebugProcess)) {
167 "src_data.output_frames_gen: " << src_data.output_frames_gen <<
168 ", leftover_frames: " << leftover_frames << std::endl;
171 if (throw_level (ThrowProcess) && src_data.output_frames_gen == 0 && leftover_frames) {
172 throw Exception (*this, boost::str (boost::format
173 ("No output frames genereated with %1% leftover frames")
177 } while (leftover_frames > frames);
179 // src_data.end_of_input has to be checked to prevent infinite recursion
180 if (!src_data.end_of_input && c.has_flag(ProcessContext<float>::EndOfInput)) {
181 set_end_of_input (c);
185 void SampleRateConverter::set_end_of_input (ProcessContext<float> const & c)
187 src_data.end_of_input = true;
190 ProcessContext<float> const dummy (c, &f, 0, channels);
192 /* No idea why this has to be done twice for all data to be written,
193 * but that just seems to be the way it is...
195 dummy.remove_flag (ProcessContext<float>::EndOfInput);
197 dummy.set_flag (ProcessContext<float>::EndOfInput);
202 void SampleRateConverter::reset ()
206 src_data.end_of_input = false;
209 src_delete (src_state);
213 max_leftover_frames = 0;
215 free (leftover_data);