4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcsignals.h"
26 #include "transportque.inc"
33 // Resampling from Lame
37 old = new double[BLACKSIZE];
42 output_allocation = 0;
43 input_size = RESAMPLE_CHUNKSIZE;
45 input = new Samples(input_size + 1);
48 direction = PLAY_FORWARD;
55 delete [] output_temp;
59 int Resample::read_samples(Samples *buffer, int64_t start, int64_t len)
64 int Resample::get_direction()
70 void Resample::reset()
78 double Resample::blackman(int i, double offset, double fcn, int l)
80 /* This algorithm from:
81 SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C
82 S.D. Stearns and R.A. David, Prentice-Hall, 1992
86 double wcn = (M_PI * fcn);
93 bkwn = 0.42 - 0.5 * cos((x * 2) * M_PI /l) + 0.08 * cos((x * 4) * M_PI /l);
94 if(fabs(x - dly) < 1e-9)
97 return (sin((wcn * (x - dly))) / (M_PI * (x - dly)) * bkwn);
101 int Resample::get_output_size()
106 // void Resample::read_output(double *output, int size)
108 // memcpy(output, output_temp, size * sizeof(double));
109 // // Shift leftover forward
110 // for(int i = size; i < output_size; i++)
111 // output_temp[i - size] = output_temp[i];
112 // output_size -= size;
117 void Resample::resample_chunk(Samples *input_buffer,
122 double resample_ratio = (double)in_rate / out_rate;
124 double fcn, intratio;
125 double offset, xvalue;
128 double *input = input_buffer->get_data();
129 //printf("Resample::resample_chunk %d in_len=%jd input_size=%d\n",
130 // __LINE__, in_len, input_size);
132 intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < .0001);
133 fcn = .90 / resample_ratio;
134 if(fcn > .90) fcn = .90;
135 filter_l = BLACKSIZE - 6;
137 if(0 == filter_l % 2 ) --filter_l;
139 /* if resample_ratio = int, filter_l should be even */
140 filter_l += (int)intratio;
142 // Blackman filter initialization must be called whenever there is a
143 // sampling ratio change
144 if(!resample_init || last_ratio != resample_ratio)
148 bzero(old, sizeof(double) * BLACKSIZE);
150 // precompute blackman filter coefficients
151 for (j = 0; j <= 2 * BPC; ++j)
153 for(j = 0; j <= 2 * BPC; j++)
155 offset = (double)(j - BPC) / (2 * BPC);
156 for(i = 0; i <= filter_l; i++)
158 blackfilt[j][i] = blackman(i, offset, fcn, filter_l);
165 double *inbuf_old = old;
171 time0 = k * resample_ratio;
172 j = (int)floor(time0 - itime);
174 // if(j + filter_l / 2 >= input_size) break;
175 if(j + filter_l / 2 >= in_len) break;
177 /* blackman filter. by default, window centered at j+.5(filter_l%2) */
178 /* but we want a window centered at time0. */
179 offset = (time0 - itime - (j + .5 * (filter_l % 2)));
180 joff = (int)floor((offset * 2 * BPC) + BPC + .5);
184 for(i = 0; i <= filter_l; i++)
186 int j2 = i + j - filter_l / 2;
187 //printf("j2=%d\n", j2);
188 double y = ((j2 < 0) ? inbuf_old[BLACKSIZE + j2] : input[j2]);
190 xvalue += y * blackfilt[joff][i];
194 if(output_allocation <= output_size)
196 double *new_output = 0;
197 int64_t new_allocation = output_allocation ? (output_allocation * 2) : 16384;
198 new_output = new double[new_allocation];
201 bcopy(output_temp, new_output, output_allocation * sizeof(double));
202 delete [] output_temp;
205 output_temp = new_output;
206 output_allocation = new_allocation;
209 output_temp[output_size++] = xvalue;
212 num_used = MIN(in_len, j + filter_l / 2);
213 itime += num_used - k * resample_ratio;
214 for(i = 0; i < BLACKSIZE; i++)
215 inbuf_old[i] = input[num_used + i - BLACKSIZE];
217 last_ratio = resample_ratio;
221 int Resample::read_chunk(Samples *input,
225 if(direction == PLAY_REVERSE &&
226 input_position - len < 0)
228 fragment = input_position;
231 int result = read_samples(input, input_position, fragment);
233 if(direction == PLAY_FORWARD)
235 input_position += fragment;
239 input_position -= fragment;
240 // Mute unused part of buffer
243 bzero(input->get_data() + fragment,
244 (len - fragment) * sizeof(double));
252 void Resample::reverse_buffer(double *buffer, int64_t len)
255 double *bp = ap + len;
264 int Resample::resample(Samples *output,
268 int64_t out_position,
274 //printf("Resample::resample 1 output_position=%jd out_position=%jd out_len=%jd\n",
275 // output_position, out_position, out_len);
277 if(labs(this->output_position - out_position) > 0 ||
278 direction != this->direction)
282 // Compute starting point in input rate.
283 this->input_position = out_position * in_rate / out_rate;
284 this->direction = direction;
288 int remaining_len = out_len;
289 double *output_ptr = output->get_data();
290 while(remaining_len > 0 && !result)
292 // Drain output buffer
295 int fragment_len = output_size;
296 if(fragment_len > remaining_len) fragment_len = remaining_len;
298 //printf("Resample::resample 1 %d %d\n", remaining_len, output_size);
299 bcopy(output_temp, output_ptr, fragment_len * sizeof(double));
301 // Shift leftover forward
302 for(int i = fragment_len; i < output_size; i++)
303 output_temp[i - fragment_len] = output_temp[i];
305 output_size -= fragment_len;
306 remaining_len -= fragment_len;
307 output_ptr += fragment_len;
310 // Import new samples
311 //printf("Resample::resample 2 %d\n", remaining_len);
312 if(remaining_len > 0)
314 //printf("Resample::resample 3 input_size=%d out_position=%d\n", input_size, out_position);
315 result = read_chunk(input, input_size);
316 resample_chunk(input,
324 if(direction == PLAY_FORWARD)
325 this->output_position = out_position + out_len;
327 this->output_position = out_position - out_len;
329 //printf("Resample::resample 2 %d %d\n", this->output_position, out_position);
330 //printf("Resample::resample 2 %d %d\n", out_len, output_size);
332 //printf("Resample::resample 2 %d\n", output_size);