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"
27 #include "transportque.inc"
34 // Resampling from Lame
38 old = new double[BLACKSIZE];
43 output_allocation = 0;
44 input_size = RESAMPLE_CHUNKSIZE;
46 input = new Samples(input_size + 1);
49 direction = PLAY_FORWARD;
56 delete [] output_temp;
60 int Resample::read_samples(Samples *buffer, int64_t start, int64_t len)
65 int Resample::get_direction()
71 void Resample::reset()
79 double Resample::blackman(int i, double offset, double fcn, int l)
81 /* This algorithm from:
82 SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C
83 S.D. Stearns and R.A. David, Prentice-Hall, 1992
87 double wcn = (M_PI * fcn);
94 bkwn = 0.42 - 0.5 * cos((x * 2) * M_PI /l) + 0.08 * cos((x * 4) * M_PI /l);
95 if(fabs(x - dly) < 1e-9)
98 return (sin((wcn * (x - dly))) / (M_PI * (x - dly)) * bkwn);
102 int Resample::get_output_size()
107 // void Resample::read_output(double *output, int size)
109 // memcpy(output, output_temp, size * sizeof(double));
110 // // Shift leftover forward
111 // for(int i = size; i < output_size; i++)
112 // output_temp[i - size] = output_temp[i];
113 // output_size -= size;
118 void Resample::resample_chunk(Samples *input_buffer,
123 double resample_ratio = (double)in_rate / out_rate;
125 double fcn, intratio;
126 double offset, xvalue;
129 double *input = input_buffer->get_data();
130 //printf("Resample::resample_chunk %d in_len=" _LD " input_size=%d\n",
135 intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < .0001);
136 fcn = .90 / resample_ratio;
137 if(fcn > .90) fcn = .90;
138 filter_l = BLACKSIZE - 6;
140 if(0 == filter_l % 2 ) --filter_l;
142 /* if resample_ratio = int, filter_l should be even */
143 filter_l += (int)intratio;
145 // Blackman filter initialization must be called whenever there is a
146 // sampling ratio change
147 if(!resample_init || last_ratio != resample_ratio)
151 bzero(old, sizeof(double) * BLACKSIZE);
153 // precompute blackman filter coefficients
154 for (j = 0; j <= 2 * BPC; ++j)
156 for(j = 0; j <= 2 * BPC; j++)
158 offset = (double)(j - BPC) / (2 * BPC);
159 for(i = 0; i <= filter_l; i++)
161 blackfilt[j][i] = blackman(i, offset, fcn, filter_l);
168 double *inbuf_old = old;
174 time0 = k * resample_ratio;
175 j = (int)floor(time0 - itime);
177 // if(j + filter_l / 2 >= input_size) break;
178 if(j + filter_l / 2 >= in_len) break;
180 /* blackman filter. by default, window centered at j+.5(filter_l%2) */
181 /* but we want a window centered at time0. */
182 offset = (time0 - itime - (j + .5 * (filter_l % 2)));
183 joff = (int)floor((offset * 2 * BPC) + BPC + .5);
187 for(i = 0; i <= filter_l; i++)
189 int j2 = i + j - filter_l / 2;
190 //printf("j2=%d\n", j2);
191 double y = ((j2 < 0) ? inbuf_old[BLACKSIZE + j2] : input[j2]);
193 xvalue += y * blackfilt[joff][i];
197 if(output_allocation <= output_size)
199 double *new_output = 0;
200 int64_t new_allocation = output_allocation ? (output_allocation * 2) : 16384;
201 new_output = new double[new_allocation];
204 bcopy(output_temp, new_output, output_allocation * sizeof(double));
205 delete [] output_temp;
208 output_temp = new_output;
209 output_allocation = new_allocation;
212 output_temp[output_size++] = xvalue;
215 num_used = MIN(in_len, j + filter_l / 2);
216 itime += num_used - k * resample_ratio;
217 for(i = 0; i < BLACKSIZE; i++)
218 inbuf_old[i] = input[num_used + i - BLACKSIZE];
220 last_ratio = resample_ratio;
224 int Resample::read_chunk(Samples *input,
228 if(direction == PLAY_REVERSE &&
229 input_position - len < 0)
231 fragment = input_position;
234 int result = read_samples(input, input_position, fragment);
236 if(direction == PLAY_FORWARD)
238 input_position += fragment;
242 input_position -= fragment;
243 // Mute unused part of buffer
246 bzero(input->get_data() + fragment,
247 (len - fragment) * sizeof(double));
255 void Resample::reverse_buffer(double *buffer, int64_t len)
258 double *bp = ap + len;
267 int Resample::resample(Samples *output,
271 int64_t out_position,
277 // printf("Resample::resample 1 output_position=" _LD " out_position=" _LD " out_len=" _LD "\n",
282 if(labs(this->output_position - out_position) > 0 ||
283 direction != this->direction)
287 // Compute starting point in input rate.
288 this->input_position = out_position * in_rate / out_rate;
289 this->direction = direction;
293 int remaining_len = out_len;
294 double *output_ptr = output->get_data();
295 while(remaining_len > 0 && !result)
297 // Drain output buffer
300 int fragment_len = output_size;
301 if(fragment_len > remaining_len) fragment_len = remaining_len;
303 //printf("Resample::resample 1 %d %d\n", remaining_len, output_size);
304 bcopy(output_temp, output_ptr, fragment_len * sizeof(double));
306 // Shift leftover forward
307 for(int i = fragment_len; i < output_size; i++)
308 output_temp[i - fragment_len] = output_temp[i];
310 output_size -= fragment_len;
311 remaining_len -= fragment_len;
312 output_ptr += fragment_len;
315 // Import new samples
316 //printf("Resample::resample 2 %d\n", remaining_len);
317 if(remaining_len > 0)
319 //printf("Resample::resample 3 input_size=%d out_position=%d\n", input_size, out_position);
320 result = read_chunk(input, input_size);
321 resample_chunk(input,
329 if(direction == PLAY_FORWARD)
330 this->output_position = out_position + out_len;
332 this->output_position = out_position - out_len;
334 //printf("Resample::resample 2 %d %d\n", this->output_position, out_position);
335 //printf("Resample::resample 2 %d %d\n", out_len, output_size);
337 //printf("Resample::resample 2 %d\n", output_size);