Chris@10
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@10
|
2
|
Chris@10
|
3 /*
|
Chris@10
|
4 Rubber Band Library
|
Chris@10
|
5 An audio time-stretching and pitch-shifting library.
|
Chris@10
|
6 Copyright 2007-2012 Particular Programs Ltd.
|
Chris@10
|
7
|
Chris@10
|
8 This program is free software; you can redistribute it and/or
|
Chris@10
|
9 modify it under the terms of the GNU General Public License as
|
Chris@10
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@10
|
11 License, or (at your option) any later version. See the file
|
Chris@10
|
12 COPYING included with this distribution for more information.
|
Chris@10
|
13
|
Chris@10
|
14 Alternatively, if you have a valid commercial licence for the
|
Chris@10
|
15 Rubber Band Library obtained by agreement with the copyright
|
Chris@10
|
16 holders, you may redistribute and/or modify it under the terms
|
Chris@10
|
17 described in that licence.
|
Chris@10
|
18
|
Chris@10
|
19 If you wish to distribute code using the Rubber Band Library
|
Chris@10
|
20 under terms other than those of the GNU General Public License,
|
Chris@10
|
21 you must obtain a valid commercial licence before doing so.
|
Chris@10
|
22 */
|
Chris@10
|
23
|
Chris@10
|
24 #include "RubberBandPitchShifter.h"
|
Chris@10
|
25
|
Chris@10
|
26 #include "RubberBandStretcher.h"
|
Chris@10
|
27
|
Chris@10
|
28 #include <iostream>
|
Chris@10
|
29 #include <cmath>
|
Chris@10
|
30
|
Chris@10
|
31 using namespace RubberBand;
|
Chris@10
|
32
|
Chris@10
|
33 using std::cout;
|
Chris@10
|
34 using std::cerr;
|
Chris@10
|
35 using std::endl;
|
Chris@10
|
36 using std::min;
|
Chris@10
|
37
|
Chris@10
|
38 const char *const
|
Chris@10
|
39 RubberBandPitchShifter::portNamesMono[PortCountMono] =
|
Chris@10
|
40 {
|
Chris@10
|
41 "latency",
|
Chris@10
|
42 "Cents",
|
Chris@10
|
43 "Semitones",
|
Chris@10
|
44 "Octaves",
|
Chris@10
|
45 "Crispness",
|
Chris@10
|
46 "Formant Preserving",
|
Chris@10
|
47 "Faster",
|
Chris@10
|
48 "Input",
|
Chris@10
|
49 "Output"
|
Chris@10
|
50 };
|
Chris@10
|
51
|
Chris@10
|
52 const char *const
|
Chris@10
|
53 RubberBandPitchShifter::portNamesStereo[PortCountStereo] =
|
Chris@10
|
54 {
|
Chris@10
|
55 "latency",
|
Chris@10
|
56 "Cents",
|
Chris@10
|
57 "Semitones",
|
Chris@10
|
58 "Octaves",
|
Chris@10
|
59 "Crispness",
|
Chris@10
|
60 "Formant Preserving",
|
Chris@10
|
61 "Faster",
|
Chris@10
|
62 "Input L",
|
Chris@10
|
63 "Output L",
|
Chris@10
|
64 "Input R",
|
Chris@10
|
65 "Output R"
|
Chris@10
|
66 };
|
Chris@10
|
67
|
Chris@10
|
68 const LADSPA_PortDescriptor
|
Chris@10
|
69 RubberBandPitchShifter::portsMono[PortCountMono] =
|
Chris@10
|
70 {
|
Chris@10
|
71 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
72 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
73 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
74 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
75 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
76 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
77 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
78 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
Chris@10
|
79 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
|
Chris@10
|
80 };
|
Chris@10
|
81
|
Chris@10
|
82 const LADSPA_PortDescriptor
|
Chris@10
|
83 RubberBandPitchShifter::portsStereo[PortCountStereo] =
|
Chris@10
|
84 {
|
Chris@10
|
85 LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
86 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
87 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
88 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
89 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
90 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
91 LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
|
Chris@10
|
92 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
Chris@10
|
93 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
|
Chris@10
|
94 LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
|
Chris@10
|
95 LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
|
Chris@10
|
96 };
|
Chris@10
|
97
|
Chris@10
|
98 const LADSPA_PortRangeHint
|
Chris@10
|
99 RubberBandPitchShifter::hintsMono[PortCountMono] =
|
Chris@10
|
100 {
|
Chris@10
|
101 { 0, 0, 0 }, // latency
|
Chris@10
|
102 { LADSPA_HINT_DEFAULT_0 | // cents
|
Chris@10
|
103 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
104 LADSPA_HINT_BOUNDED_ABOVE,
|
Chris@10
|
105 -100.0, 100.0 },
|
Chris@10
|
106 { LADSPA_HINT_DEFAULT_0 | // semitones
|
Chris@10
|
107 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
108 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
109 LADSPA_HINT_INTEGER,
|
Chris@10
|
110 -12.0, 12.0 },
|
Chris@10
|
111 { LADSPA_HINT_DEFAULT_0 | // octaves
|
Chris@10
|
112 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
113 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
114 LADSPA_HINT_INTEGER,
|
Chris@10
|
115 -3.0, 3.0 },
|
Chris@10
|
116 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
|
Chris@10
|
117 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
118 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
119 LADSPA_HINT_INTEGER,
|
Chris@10
|
120 0.0, 3.0 },
|
Chris@10
|
121 { LADSPA_HINT_DEFAULT_0 | // formant preserving
|
Chris@10
|
122 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
123 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
124 LADSPA_HINT_TOGGLED,
|
Chris@10
|
125 0.0, 1.0 },
|
Chris@10
|
126 { LADSPA_HINT_DEFAULT_0 | // fast
|
Chris@10
|
127 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
128 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
129 LADSPA_HINT_TOGGLED,
|
Chris@10
|
130 0.0, 1.0 },
|
Chris@10
|
131 { 0, 0, 0 },
|
Chris@10
|
132 { 0, 0, 0 }
|
Chris@10
|
133 };
|
Chris@10
|
134
|
Chris@10
|
135 const LADSPA_PortRangeHint
|
Chris@10
|
136 RubberBandPitchShifter::hintsStereo[PortCountStereo] =
|
Chris@10
|
137 {
|
Chris@10
|
138 { 0, 0, 0 }, // latency
|
Chris@10
|
139 { LADSPA_HINT_DEFAULT_0 | // cents
|
Chris@10
|
140 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
141 LADSPA_HINT_BOUNDED_ABOVE,
|
Chris@10
|
142 -100.0, 100.0 },
|
Chris@10
|
143 { LADSPA_HINT_DEFAULT_0 | // semitones
|
Chris@10
|
144 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
145 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
146 LADSPA_HINT_INTEGER,
|
Chris@10
|
147 -12.0, 12.0 },
|
Chris@10
|
148 { LADSPA_HINT_DEFAULT_0 | // octaves
|
Chris@10
|
149 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
150 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
151 LADSPA_HINT_INTEGER,
|
Chris@10
|
152 -3.0, 3.0 },
|
Chris@10
|
153 { LADSPA_HINT_DEFAULT_MAXIMUM | // crispness
|
Chris@10
|
154 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
155 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
156 LADSPA_HINT_INTEGER,
|
Chris@10
|
157 0.0, 3.0 },
|
Chris@10
|
158 { LADSPA_HINT_DEFAULT_0 | // formant preserving
|
Chris@10
|
159 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
160 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
161 LADSPA_HINT_TOGGLED,
|
Chris@10
|
162 0.0, 1.0 },
|
Chris@10
|
163 { LADSPA_HINT_DEFAULT_0 | // fast
|
Chris@10
|
164 LADSPA_HINT_BOUNDED_BELOW |
|
Chris@10
|
165 LADSPA_HINT_BOUNDED_ABOVE |
|
Chris@10
|
166 LADSPA_HINT_TOGGLED,
|
Chris@10
|
167 0.0, 1.0 },
|
Chris@10
|
168 { 0, 0, 0 },
|
Chris@10
|
169 { 0, 0, 0 },
|
Chris@10
|
170 { 0, 0, 0 },
|
Chris@10
|
171 { 0, 0, 0 }
|
Chris@10
|
172 };
|
Chris@10
|
173
|
Chris@10
|
174 const LADSPA_Properties
|
Chris@10
|
175 RubberBandPitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
|
Chris@10
|
176
|
Chris@10
|
177 const LADSPA_Descriptor
|
Chris@10
|
178 RubberBandPitchShifter::ladspaDescriptorMono =
|
Chris@10
|
179 {
|
Chris@10
|
180 2979, // "Unique" ID
|
Chris@10
|
181 "rubberband-pitchshifter-mono", // Label
|
Chris@10
|
182 properties,
|
Chris@10
|
183 "Rubber Band Mono Pitch Shifter", // Name
|
Chris@10
|
184 "Breakfast Quay",
|
Chris@10
|
185 "GPL",
|
Chris@10
|
186 PortCountMono,
|
Chris@10
|
187 portsMono,
|
Chris@10
|
188 portNamesMono,
|
Chris@10
|
189 hintsMono,
|
Chris@10
|
190 0, // Implementation data
|
Chris@10
|
191 instantiate,
|
Chris@10
|
192 connectPort,
|
Chris@10
|
193 activate,
|
Chris@10
|
194 run,
|
Chris@10
|
195 0, // Run adding
|
Chris@10
|
196 0, // Set run adding gain
|
Chris@10
|
197 deactivate,
|
Chris@10
|
198 cleanup
|
Chris@10
|
199 };
|
Chris@10
|
200
|
Chris@10
|
201 const LADSPA_Descriptor
|
Chris@10
|
202 RubberBandPitchShifter::ladspaDescriptorStereo =
|
Chris@10
|
203 {
|
Chris@10
|
204 9792, // "Unique" ID
|
Chris@10
|
205 "rubberband-pitchshifter-stereo", // Label
|
Chris@10
|
206 properties,
|
Chris@10
|
207 "Rubber Band Stereo Pitch Shifter", // Name
|
Chris@10
|
208 "Breakfast Quay",
|
Chris@10
|
209 "GPL",
|
Chris@10
|
210 PortCountStereo,
|
Chris@10
|
211 portsStereo,
|
Chris@10
|
212 portNamesStereo,
|
Chris@10
|
213 hintsStereo,
|
Chris@10
|
214 0, // Implementation data
|
Chris@10
|
215 instantiate,
|
Chris@10
|
216 connectPort,
|
Chris@10
|
217 activate,
|
Chris@10
|
218 run,
|
Chris@10
|
219 0, // Run adding
|
Chris@10
|
220 0, // Set run adding gain
|
Chris@10
|
221 deactivate,
|
Chris@10
|
222 cleanup
|
Chris@10
|
223 };
|
Chris@10
|
224
|
Chris@10
|
225 const LADSPA_Descriptor *
|
Chris@10
|
226 RubberBandPitchShifter::getDescriptor(unsigned long index)
|
Chris@10
|
227 {
|
Chris@10
|
228 if (index == 0) return &ladspaDescriptorMono;
|
Chris@10
|
229 if (index == 1) return &ladspaDescriptorStereo;
|
Chris@10
|
230 else return 0;
|
Chris@10
|
231 }
|
Chris@10
|
232
|
Chris@10
|
233 RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) :
|
Chris@10
|
234 m_latency(0),
|
Chris@10
|
235 m_cents(0),
|
Chris@10
|
236 m_semitones(0),
|
Chris@10
|
237 m_octaves(0),
|
Chris@10
|
238 m_crispness(0),
|
Chris@10
|
239 m_formant(0),
|
Chris@10
|
240 m_fast(0),
|
Chris@10
|
241 m_ratio(1.0),
|
Chris@10
|
242 m_prevRatio(1.0),
|
Chris@10
|
243 m_currentCrispness(-1),
|
Chris@10
|
244 m_currentFormant(false),
|
Chris@10
|
245 m_currentFast(false),
|
Chris@10
|
246 m_blockSize(1024),
|
Chris@10
|
247 m_reserve(1024),
|
Chris@10
|
248 m_minfill(0),
|
Chris@10
|
249 m_stretcher(new RubberBandStretcher
|
Chris@10
|
250 (sampleRate, channels,
|
Chris@10
|
251 RubberBandStretcher::OptionProcessRealTime |
|
Chris@10
|
252 RubberBandStretcher::OptionPitchHighConsistency)),
|
Chris@10
|
253 m_sampleRate(sampleRate),
|
Chris@10
|
254 m_channels(channels)
|
Chris@10
|
255 {
|
Chris@10
|
256 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
257
|
Chris@10
|
258 m_input[c] = 0;
|
Chris@10
|
259 m_output[c] = 0;
|
Chris@10
|
260
|
Chris@10
|
261 int bufsize = m_blockSize + m_reserve + 8192;
|
Chris@10
|
262
|
Chris@10
|
263 m_outputBuffer[c] = new RingBuffer<float>(bufsize);
|
Chris@10
|
264
|
Chris@10
|
265 m_scratch[c] = new float[bufsize];
|
Chris@10
|
266 for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f;
|
Chris@10
|
267 }
|
Chris@10
|
268
|
Chris@10
|
269 activateImpl();
|
Chris@10
|
270 }
|
Chris@10
|
271
|
Chris@10
|
272 RubberBandPitchShifter::~RubberBandPitchShifter()
|
Chris@10
|
273 {
|
Chris@10
|
274 delete m_stretcher;
|
Chris@10
|
275 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
276 delete m_outputBuffer[c];
|
Chris@10
|
277 delete[] m_scratch[c];
|
Chris@10
|
278 }
|
Chris@10
|
279 }
|
Chris@10
|
280
|
Chris@10
|
281 LADSPA_Handle
|
Chris@10
|
282 RubberBandPitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate)
|
Chris@10
|
283 {
|
Chris@10
|
284 if (desc->PortCount == ladspaDescriptorMono.PortCount) {
|
Chris@10
|
285 return new RubberBandPitchShifter(rate, 1);
|
Chris@10
|
286 } else if (desc->PortCount == ladspaDescriptorStereo.PortCount) {
|
Chris@10
|
287 return new RubberBandPitchShifter(rate, 2);
|
Chris@10
|
288 }
|
Chris@10
|
289 return 0;
|
Chris@10
|
290 }
|
Chris@10
|
291
|
Chris@10
|
292 void
|
Chris@10
|
293 RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
|
Chris@10
|
294 unsigned long port, LADSPA_Data *location)
|
Chris@10
|
295 {
|
Chris@10
|
296 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
|
Chris@10
|
297
|
Chris@10
|
298 float **ports[PortCountStereo] = {
|
Chris@10
|
299 &shifter->m_latency,
|
Chris@10
|
300 &shifter->m_cents,
|
Chris@10
|
301 &shifter->m_semitones,
|
Chris@10
|
302 &shifter->m_octaves,
|
Chris@10
|
303 &shifter->m_crispness,
|
Chris@10
|
304 &shifter->m_formant,
|
Chris@10
|
305 &shifter->m_fast,
|
Chris@10
|
306 &shifter->m_input[0],
|
Chris@10
|
307 &shifter->m_output[0],
|
Chris@10
|
308 &shifter->m_input[1],
|
Chris@10
|
309 &shifter->m_output[1]
|
Chris@10
|
310 };
|
Chris@10
|
311
|
Chris@10
|
312 if (shifter->m_channels == 1) {
|
Chris@10
|
313 if (port >= PortCountMono) return;
|
Chris@10
|
314 } else {
|
Chris@10
|
315 if (port >= PortCountStereo) return;
|
Chris@10
|
316 }
|
Chris@10
|
317
|
Chris@10
|
318 *ports[port] = (float *)location;
|
Chris@10
|
319
|
Chris@10
|
320 if (shifter->m_latency) {
|
Chris@10
|
321 *(shifter->m_latency) =
|
Chris@10
|
322 float(shifter->m_stretcher->getLatency() + shifter->m_reserve);
|
Chris@10
|
323 }
|
Chris@10
|
324 }
|
Chris@10
|
325
|
Chris@10
|
326 void
|
Chris@10
|
327 RubberBandPitchShifter::activate(LADSPA_Handle handle)
|
Chris@10
|
328 {
|
Chris@10
|
329 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
|
Chris@10
|
330 shifter->activateImpl();
|
Chris@10
|
331 }
|
Chris@10
|
332
|
Chris@10
|
333 void
|
Chris@10
|
334 RubberBandPitchShifter::activateImpl()
|
Chris@10
|
335 {
|
Chris@10
|
336 updateRatio();
|
Chris@10
|
337 m_prevRatio = m_ratio;
|
Chris@10
|
338 m_stretcher->reset();
|
Chris@10
|
339 m_stretcher->setPitchScale(m_ratio);
|
Chris@10
|
340
|
Chris@10
|
341 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
342 m_outputBuffer[c]->reset();
|
Chris@10
|
343 m_outputBuffer[c]->zero(m_reserve);
|
Chris@10
|
344 }
|
Chris@10
|
345
|
Chris@10
|
346 m_minfill = 0;
|
Chris@10
|
347
|
Chris@10
|
348 // prime stretcher
|
Chris@10
|
349 // for (int i = 0; i < 8; ++i) {
|
Chris@10
|
350 // int reqd = m_stretcher->getSamplesRequired();
|
Chris@10
|
351 // m_stretcher->process(m_scratch, reqd, false);
|
Chris@10
|
352 // int avail = m_stretcher->available();
|
Chris@10
|
353 // if (avail > 0) {
|
Chris@10
|
354 // m_stretcher->retrieve(m_scratch, avail);
|
Chris@10
|
355 // }
|
Chris@10
|
356 // }
|
Chris@10
|
357 }
|
Chris@10
|
358
|
Chris@10
|
359 void
|
Chris@10
|
360 RubberBandPitchShifter::run(LADSPA_Handle handle, unsigned long samples)
|
Chris@10
|
361 {
|
Chris@10
|
362 RubberBandPitchShifter *shifter = (RubberBandPitchShifter *)handle;
|
Chris@10
|
363 shifter->runImpl(samples);
|
Chris@10
|
364 }
|
Chris@10
|
365
|
Chris@10
|
366 void
|
Chris@10
|
367 RubberBandPitchShifter::updateRatio()
|
Chris@10
|
368 {
|
Chris@10
|
369 double oct = (m_octaves ? *m_octaves : 0.0);
|
Chris@10
|
370 oct += (m_semitones ? *m_semitones : 0.0) / 12;
|
Chris@10
|
371 oct += (m_cents ? *m_cents : 0.0) / 1200;
|
Chris@10
|
372 m_ratio = pow(2.0, oct);
|
Chris@10
|
373 }
|
Chris@10
|
374
|
Chris@10
|
375 void
|
Chris@10
|
376 RubberBandPitchShifter::updateCrispness()
|
Chris@10
|
377 {
|
Chris@10
|
378 if (!m_crispness) return;
|
Chris@10
|
379
|
Chris@10
|
380 int c = lrintf(*m_crispness);
|
Chris@10
|
381 if (c == m_currentCrispness) return;
|
Chris@10
|
382 if (c < 0 || c > 3) return;
|
Chris@10
|
383 RubberBandStretcher *s = m_stretcher;
|
Chris@10
|
384
|
Chris@10
|
385 switch (c) {
|
Chris@10
|
386 case 0:
|
Chris@10
|
387 s->setPhaseOption(RubberBandStretcher::OptionPhaseIndependent);
|
Chris@10
|
388 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
|
Chris@10
|
389 break;
|
Chris@10
|
390 case 1:
|
Chris@10
|
391 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
|
Chris@10
|
392 s->setTransientsOption(RubberBandStretcher::OptionTransientsSmooth);
|
Chris@10
|
393 break;
|
Chris@10
|
394 case 2:
|
Chris@10
|
395 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
|
Chris@10
|
396 s->setTransientsOption(RubberBandStretcher::OptionTransientsMixed);
|
Chris@10
|
397 break;
|
Chris@10
|
398 case 3:
|
Chris@10
|
399 s->setPhaseOption(RubberBandStretcher::OptionPhaseLaminar);
|
Chris@10
|
400 s->setTransientsOption(RubberBandStretcher::OptionTransientsCrisp);
|
Chris@10
|
401 break;
|
Chris@10
|
402 }
|
Chris@10
|
403
|
Chris@10
|
404 m_currentCrispness = c;
|
Chris@10
|
405 }
|
Chris@10
|
406
|
Chris@10
|
407 void
|
Chris@10
|
408 RubberBandPitchShifter::updateFormant()
|
Chris@10
|
409 {
|
Chris@10
|
410 if (!m_formant) return;
|
Chris@10
|
411
|
Chris@10
|
412 bool f = (*m_formant > 0.5f);
|
Chris@10
|
413 if (f == m_currentFormant) return;
|
Chris@10
|
414
|
Chris@10
|
415 RubberBandStretcher *s = m_stretcher;
|
Chris@10
|
416
|
Chris@10
|
417 s->setFormantOption(f ?
|
Chris@10
|
418 RubberBandStretcher::OptionFormantPreserved :
|
Chris@10
|
419 RubberBandStretcher::OptionFormantShifted);
|
Chris@10
|
420
|
Chris@10
|
421 m_currentFormant = f;
|
Chris@10
|
422 }
|
Chris@10
|
423
|
Chris@10
|
424 void
|
Chris@10
|
425 RubberBandPitchShifter::updateFast()
|
Chris@10
|
426 {
|
Chris@10
|
427 if (!m_fast) return;
|
Chris@10
|
428
|
Chris@10
|
429 bool f = (*m_fast > 0.5f);
|
Chris@10
|
430 if (f == m_currentFast) return;
|
Chris@10
|
431
|
Chris@10
|
432 RubberBandStretcher *s = m_stretcher;
|
Chris@10
|
433
|
Chris@10
|
434 s->setPitchOption(f ?
|
Chris@10
|
435 RubberBandStretcher::OptionPitchHighSpeed :
|
Chris@10
|
436 RubberBandStretcher::OptionPitchHighConsistency);
|
Chris@10
|
437
|
Chris@10
|
438 m_currentFast = f;
|
Chris@10
|
439 }
|
Chris@10
|
440
|
Chris@10
|
441 void
|
Chris@10
|
442 RubberBandPitchShifter::runImpl(unsigned long insamples)
|
Chris@10
|
443 {
|
Chris@10
|
444 unsigned long offset = 0;
|
Chris@10
|
445
|
Chris@10
|
446 // We have to break up the input into chunks like this because
|
Chris@10
|
447 // insamples could be arbitrarily large and our output buffer is
|
Chris@10
|
448 // of limited size
|
Chris@10
|
449
|
Chris@10
|
450 while (offset < insamples) {
|
Chris@10
|
451
|
Chris@10
|
452 unsigned long block = (unsigned long)m_blockSize;
|
Chris@10
|
453 if (block + offset > insamples) block = insamples - offset;
|
Chris@10
|
454
|
Chris@10
|
455 runImpl(block, offset);
|
Chris@10
|
456
|
Chris@10
|
457 offset += block;
|
Chris@10
|
458 }
|
Chris@10
|
459 }
|
Chris@10
|
460
|
Chris@10
|
461 void
|
Chris@10
|
462 RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset)
|
Chris@10
|
463 {
|
Chris@10
|
464 // cerr << "RubberBandPitchShifter::runImpl(" << insamples << ")" << endl;
|
Chris@10
|
465
|
Chris@10
|
466 // static int incount = 0, outcount = 0;
|
Chris@10
|
467
|
Chris@10
|
468 updateRatio();
|
Chris@10
|
469 if (m_ratio != m_prevRatio) {
|
Chris@10
|
470 m_stretcher->setPitchScale(m_ratio);
|
Chris@10
|
471 m_prevRatio = m_ratio;
|
Chris@10
|
472 }
|
Chris@10
|
473
|
Chris@10
|
474 if (m_latency) {
|
Chris@10
|
475 *m_latency = float(m_stretcher->getLatency() + m_reserve);
|
Chris@10
|
476 // cerr << "latency = " << *m_latency << endl;
|
Chris@10
|
477 }
|
Chris@10
|
478
|
Chris@10
|
479 updateCrispness();
|
Chris@10
|
480 updateFormant();
|
Chris@10
|
481 updateFast();
|
Chris@10
|
482
|
Chris@10
|
483 const int samples = insamples;
|
Chris@10
|
484 int processed = 0;
|
Chris@10
|
485 size_t outTotal = 0;
|
Chris@10
|
486
|
Chris@10
|
487 float *ptrs[2];
|
Chris@10
|
488
|
Chris@10
|
489 int rs = m_outputBuffer[0]->getReadSpace();
|
Chris@10
|
490 if (rs < int(m_minfill)) {
|
Chris@10
|
491 // cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl;
|
Chris@10
|
492 m_stretcher->setTimeRatio(1.1); // fill up temporarily
|
Chris@10
|
493 } else if (rs > 8192) {
|
Chris@10
|
494 // cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl;
|
Chris@10
|
495 m_stretcher->setTimeRatio(0.9); // reduce temporarily
|
Chris@10
|
496 } else {
|
Chris@10
|
497 m_stretcher->setTimeRatio(1.0);
|
Chris@10
|
498 }
|
Chris@10
|
499
|
Chris@10
|
500 while (processed < samples) {
|
Chris@10
|
501
|
Chris@10
|
502 // never feed more than the minimum necessary number of
|
Chris@10
|
503 // samples at a time; ensures nothing will overflow internally
|
Chris@10
|
504 // and we don't need to call setMaxProcessSize
|
Chris@10
|
505
|
Chris@10
|
506 int toCauseProcessing = m_stretcher->getSamplesRequired();
|
Chris@10
|
507 int inchunk = min(samples - processed, toCauseProcessing);
|
Chris@10
|
508 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
509 ptrs[c] = &(m_input[c][offset + processed]);
|
Chris@10
|
510 }
|
Chris@10
|
511 m_stretcher->process(ptrs, inchunk, false);
|
Chris@10
|
512 processed += inchunk;
|
Chris@10
|
513
|
Chris@10
|
514 int avail = m_stretcher->available();
|
Chris@10
|
515 int writable = m_outputBuffer[0]->getWriteSpace();
|
Chris@10
|
516 int outchunk = min(avail, writable);
|
Chris@10
|
517 size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
|
Chris@10
|
518 outTotal += actual;
|
Chris@10
|
519
|
Chris@10
|
520 // incount += inchunk;
|
Chris@10
|
521 // outcount += actual;
|
Chris@10
|
522
|
Chris@10
|
523 // cout << "avail: " << avail << ", outchunk = " << outchunk;
|
Chris@10
|
524 // if (actual != outchunk) cout << " (" << actual << ")";
|
Chris@10
|
525 // cout << endl;
|
Chris@10
|
526
|
Chris@10
|
527 outchunk = actual;
|
Chris@10
|
528
|
Chris@10
|
529 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
530 if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) {
|
Chris@10
|
531 cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl;
|
Chris@10
|
532 }
|
Chris@10
|
533 m_outputBuffer[c]->write(m_scratch[c], outchunk);
|
Chris@10
|
534 }
|
Chris@10
|
535 }
|
Chris@10
|
536
|
Chris@10
|
537 for (size_t c = 0; c < m_channels; ++c) {
|
Chris@10
|
538 int toRead = m_outputBuffer[c]->getReadSpace();
|
Chris@10
|
539 if (toRead < samples && c == 0) {
|
Chris@10
|
540 cerr << "RubberBandPitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
|
Chris@10
|
541 }
|
Chris@10
|
542 int chunk = min(toRead, samples);
|
Chris@10
|
543 m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
|
Chris@10
|
544 }
|
Chris@10
|
545
|
Chris@10
|
546 if (m_minfill == 0) {
|
Chris@10
|
547 m_minfill = m_outputBuffer[0]->getReadSpace();
|
Chris@10
|
548 // cerr << "minfill = " << m_minfill << endl;
|
Chris@10
|
549 }
|
Chris@10
|
550 }
|
Chris@10
|
551
|
Chris@10
|
552 void
|
Chris@10
|
553 RubberBandPitchShifter::deactivate(LADSPA_Handle handle)
|
Chris@10
|
554 {
|
Chris@10
|
555 activate(handle); // both functions just reset the plugin
|
Chris@10
|
556 }
|
Chris@10
|
557
|
Chris@10
|
558 void
|
Chris@10
|
559 RubberBandPitchShifter::cleanup(LADSPA_Handle handle)
|
Chris@10
|
560 {
|
Chris@10
|
561 delete (RubberBandPitchShifter *)handle;
|
Chris@10
|
562 }
|
Chris@10
|
563
|