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=" _LD " input_size=%d\n",
134 intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < .0001);
135 fcn = .90 / resample_ratio;
136 if(fcn > .90) fcn = .90;
137 filter_l = BLACKSIZE - 6;
139 if(0 == filter_l % 2 ) --filter_l;
141 /* if resample_ratio = int, filter_l should be even */
142 filter_l += (int)intratio;
144 // Blackman filter initialization must be called whenever there is a
145 // sampling ratio change
146 if(!resample_init || last_ratio != resample_ratio)
150 bzero(old, sizeof(double) * BLACKSIZE);
152 // precompute blackman filter coefficients
153 for (j = 0; j <= 2 * BPC; ++j)
155 for(j = 0; j <= 2 * BPC; j++)
157 offset = (double)(j - BPC) / (2 * BPC);
158 for(i = 0; i <= filter_l; i++)
160 blackfilt[j][i] = blackman(i, offset, fcn, filter_l);
167 double *inbuf_old = old;
173 time0 = k * resample_ratio;
174 j = (int)floor(time0 - itime);
176 // if(j + filter_l / 2 >= input_size) break;
177 if(j + filter_l / 2 >= in_len) break;
179 /* blackman filter. by default, window centered at j+.5(filter_l%2) */
180 /* but we want a window centered at time0. */
181 offset = (time0 - itime - (j + .5 * (filter_l % 2)));
182 joff = (int)floor((offset * 2 * BPC) + BPC + .5);
186 for(i = 0; i <= filter_l; i++)
188 int j2 = i + j - filter_l / 2;
189 //printf("j2=%d\n", j2);
190 double y = ((j2 < 0) ? inbuf_old[BLACKSIZE + j2] : input[j2]);
192 xvalue += y * blackfilt[joff][i];
196 if(output_allocation <= output_size)
198 double *new_output = 0;
199 int64_t new_allocation = output_allocation ? (output_allocation * 2) : 16384;
200 new_output = new double[new_allocation];
203 bcopy(output_temp, new_output, output_allocation * sizeof(double));
204 delete [] output_temp;
207 output_temp = new_output;
208 output_allocation = new_allocation;
211 output_temp[output_size++] = xvalue;
214 num_used = MIN(in_len, j + filter_l / 2);
215 itime += num_used - k * resample_ratio;
216 for(i = 0; i < BLACKSIZE; i++)
217 inbuf_old[i] = input[num_used + i - BLACKSIZE];
219 last_ratio = resample_ratio;
223 int Resample::read_chunk(Samples *input,
227 if(direction == PLAY_REVERSE &&
228 input_position - len < 0)
230 fragment = input_position;
233 int result = read_samples(input, input_position, fragment);
235 if(direction == PLAY_FORWARD)
237 input_position += fragment;
241 input_position -= fragment;
242 // Mute unused part of buffer
245 bzero(input->get_data() + fragment,
246 (len - fragment) * sizeof(double));
254 void Resample::reverse_buffer(double *buffer, int64_t len)
257 double *bp = ap + len;
266 int Resample::resample(Samples *output,
270 int64_t out_position,
276 // printf("Resample::resample 1 output_position=" _LD " out_position=" _LD " out_len=" _LD "\n",
281 if(labs(this->output_position - out_position) > 0 ||
282 direction != this->direction)
286 // Compute starting point in input rate.
287 this->input_position = out_position * in_rate / out_rate;
288 this->direction = direction;
292 int remaining_len = out_len;
293 double *output_ptr = output->get_data();
294 while(remaining_len > 0 && !result)
296 // Drain output buffer
299 int fragment_len = output_size;
300 if(fragment_len > remaining_len) fragment_len = remaining_len;
302 //printf("Resample::resample 1 %d %d\n", remaining_len, output_size);
303 bcopy(output_temp, output_ptr, fragment_len * sizeof(double));
305 // Shift leftover forward
306 for(int i = fragment_len; i < output_size; i++)
307 output_temp[i - fragment_len] = output_temp[i];
309 output_size -= fragment_len;
310 remaining_len -= fragment_len;
311 output_ptr += fragment_len;
314 // Import new samples
315 //printf("Resample::resample 2 %d\n", remaining_len);
316 if(remaining_len > 0)
318 //printf("Resample::resample 3 input_size=%d out_position=%d\n", input_size, out_position);
319 result = read_chunk(input, input_size);
320 resample_chunk(input,
328 if(direction == PLAY_FORWARD)
329 this->output_position = out_position + out_len;
331 this->output_position = out_position - out_len;
333 //printf("Resample::resample 2 %d %d\n", this->output_position, out_position);
334 //printf("Resample::resample 2 %d %d\n", out_len, output_size);
336 //printf("Resample::resample 2 %d\n", output_size);