Guitarix
gx_resampler.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * --------------------------------------------------------------------------
19  *
20  *
21  * This is the Guitarix resampler
22  * to use zita-resampler
23  *
24  * --------------------------------------------------------------------------
25  */
26 
27 #include "engine.h"
28 
29 namespace gx_resample {
30 
31 // copyed gcd from (zita) resampler.cc to get ratio_a and ratio_b for
32 // calculate the correct buffer size resulting from resample
33 static unsigned int gcd (unsigned int a, unsigned int b)
34 {
35  if (a == 0) return b;
36  if (b == 0) return a;
37  while (1)
38  {
39  if (a > b)
40  {
41  a = a % b;
42  if (a == 0) return b;
43  if (a == 1) return 1;
44  }
45  else
46  {
47  b = b % a;
48  if (b == 0) return a;
49  if (b == 1) return 1;
50  }
51  }
52  return 1;
53 }
54 
55 void SimpleResampler::setup(int sampleRate, unsigned int fact)
56 {
57  assert(fact <= MAX_UPSAMPLE);
58  m_fact = fact;
59  const int qual = 16; // resulting in a total delay of 2*qual (0.7ms @44100)
60  // upsampler
61  r_up.setup(sampleRate, sampleRate*fact, 1, qual);
62  // k == inpsize() == 2 * qual
63  // pre-fill with k-1 zeros
64  r_up.inp_count = r_up.inpsize() - 1;
65  r_up.out_count = 1;
66  r_up.inp_data = r_up.out_data = 0;
67  r_up.process();
68  // downsampler
69  r_down.setup(sampleRate*fact, sampleRate, 1, qual);
70  // k == inpsize() == 2 * qual * fact
71  // pre-fill with k-1 zeros
72  r_down.inp_count = r_down.inpsize() - 1;
73  r_down.out_count = 1;
74  r_down.inp_data = r_down.out_data = 0;
75  r_down.process();
76 }
77 
78 void SimpleResampler::up(int count, float *input, float *output)
79 {
80  r_up.inp_count = count;
81  r_up.inp_data = input;
82  r_up.out_count = count * m_fact;
83  r_up.out_data = output;
84  r_up.process();
85  assert(r_up.inp_count == 0);
86  assert(r_up.out_count == 0);
87 }
88 
89 void SimpleResampler::down(int count, float *input, float *output)
90 {
91  r_down.inp_count = count * m_fact;
92  r_down.inp_data = input;
93  r_down.out_count = count+1; // +1 == trick to drain input
94  r_down.out_data = output;
95  r_down.process();
96  assert(r_down.inp_count == 0);
97  assert(r_down.out_count == 1);
98 }
99 
100 float *BufferResampler::process(int fs_inp, int ilen, float *input, int fs_outp, int *olen)
101 {
102  int d = gcd(fs_inp, fs_outp);
103  int ratio_a = fs_inp / d;
104  int ratio_b = fs_outp / d;
105 
106  const int qual = 32;
107  if (setup(fs_inp, fs_outp, 1, qual) != 0) {
108  return 0;
109  }
110  // pre-fill with k/2-1 zeros
111  int k = inpsize();
112  inp_count = k/2-1;
113  inp_data = 0;
114  out_count = 1; // must be at least 1 to get going
115  out_data = 0;
116  if (Resampler::process() != 0) {
117  return 0;
118  }
119  inp_count = ilen;
120  int nout = out_count = (ilen * ratio_b + ratio_a - 1) / ratio_a;
121  inp_data = input;
122  float *p = out_data = new float[out_count];
123  if (Resampler::process() != 0) {
124  delete p;
125  return 0;
126  }
127  inp_data = 0;
128  inp_count = k/2;
129  if (Resampler::process() != 0) {
130  delete p;
131  return 0;
132  }
133  assert(inp_count == 0);
134  assert(out_count <= 1);
135  *olen = nout - out_count;
136  return p;
137 }
138 
139 bool StreamingResampler::setup(int srcRate, int dstRate, int nchan)
140 {
141  int d = gcd(srcRate, dstRate);
142  ratio_a = srcRate / d;
143  ratio_b = dstRate / d;
144 
145  const int qual = 32;
146  if (Resampler::setup(srcRate, dstRate, nchan, qual) != 0) {
147  return false;
148  }
149  inp_count = inpsize()/2-1;
150  inp_data = 0;
151  out_count = 1; // must be at least 1 to get going
152  out_data = 0;
153  if (Resampler::process() != 0) {
154  return false;
155  }
156  assert(inp_count == 0);
157  assert(out_count == 1);
158  return true;
159 }
160 
161 int StreamingResampler::process(int count, float *input, float *output)
162 {
163  inp_count = count;
164  int olen = out_count = get_max_out_size(count);
165  inp_data = input;
166  out_data = output;
167  if (Resampler::process() != 0) {
168  return 0;
169  }
170  assert(inp_count == 0);
171  return olen - out_count;
172 }
173 
174 int StreamingResampler::flush(float *output)
175 {
176  // maximum data written to output:
177  // srcRate > dstRate: ~ 2 * qual
178  // srcRate < dstRate: ~ 2 * qual * dstRate/srcRate
179  inp_data = 0;
180  inp_count = inpsize()/2;
181  out_data = output;
182  int olen = out_count = get_max_out_size(inp_count);
183  if (Resampler::process() != 0) {
184  return 0;
185  }
186  assert(inp_count == 0);
187  return olen - out_count;
188 }
189 
190 int FixedRateResampler::setup(int _inputRate, int _outputRate)
191 {
192  const int qual = 16; // resulting in a total delay of 2*qual (0.7ms @44100)
193  inputRate = _inputRate;
194  outputRate = _outputRate;
195  if (inputRate >= outputRate) {
196  return 0;
197  }
198  // upsampler
199  int ret = r_up.setup(inputRate, outputRate, 1, qual);
200  if (ret) {
201  return ret;
202  }
203  // k == filtlen() == 2 * qual
204  // pre-fill with k-1 zeros
205  r_up.inp_count = r_up.filtlen() - 1;
206  r_up.out_count = 1;
207  r_up.inp_data = r_up.out_data = 0;
208  r_up.process();
209  // downsampler
210  ret = r_down.setup(outputRate, inputRate, 1, qual);
211  if (ret) {
212  return ret;
213  }
214  // k == filtlen() == 2 * qual * fact
215  // pre-fill with k-2 zeros
216  r_down.inp_count = r_down.filtlen() - 2;
217  r_down.out_count = 1;
218  r_down.inp_data = r_down.out_data = 0;
219  r_down.process();
220  return 0;
221 }
222 
223 int FixedRateResampler::up(int count, float *input, float *output)
224 {
225  if (inputRate >= outputRate) {
226  memcpy(output, input, count*sizeof(float));
227  r_down.out_count = count;
228  return count;
229  }
230  r_up.inp_count = count;
231  r_down.out_count = count+1; // +1 == trick to drain input
232  r_up.inp_data = input;
233  int m = max_out_count(count);
234  r_up.out_count = m;
235  r_up.out_data = output;
236  r_up.process();
237  assert(r_up.inp_count == 0);
238  assert(r_up.out_count <= 1);
239  r_down.inp_count = m - r_up.out_count;
240  return r_down.inp_count;
241 }
242 
243 void FixedRateResampler::down(float *input, float *output)
244 {
245  if (inputRate >= outputRate) {
246  memcpy(output, input, r_down.out_count*sizeof(float));
247  return;
248  }
249  r_down.inp_data = input;
250  r_down.out_data = output;
251  r_down.process();
252  assert(r_down.inp_count == 0);
253  assert(r_down.out_count == 1);
254 }
255 
256 } // namespace gx_resample
void up(int count, float *input, float *output)
void down(float *input, float *output)
float * process(int fs_inp, int ilen, float *input, int fs_outp, int *olen)
int setup(int _inputRate, int _outputRate)
void down(int count, float *input, float *output)
#define MAX_UPSAMPLE
Definition: gx_resampler.h:32
int up(int count, float *input, float *output)
void setup(int sampleRate, unsigned int fact)
bool setup(int srcRate, int dstRate, int nchan)
int process(int count, float *input, float *output)