SAF
Loading...
Searching...
No Matches
saf_utility_pitch.c
Go to the documentation of this file.
1/*
2 * Copyright 2019 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
27#include "saf_utilities.h"
28
32#define SMB_ENABLE_SAF_FFT
33
34/* ========================================================================== */
35/* SMB PitchShifter */
36/* ========================================================================== */
37
38#ifndef SMB_ENABLE_SAF_FFT
39static void smbFft(float *fftBuffer, int fftFrameSize, long sign)
40/*
41 FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)
42 Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the
43 time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes
44 and returns the cosine and sine parts in an interleaved manner, ie.
45 fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize
46 must be a power of 2. It expects a complex input signal (see footnote 2),
47 ie. when working with 'common' audio signals our input signal has to be
48 passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform
49 of the frequencies of interest is in fftBuffer[0...fftFrameSize].
50*/
51{
52 float wr, wi, arg, *p1, *p2, temp;
53 float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
54 long i, bitm, j, le, le2, k;
55
56 for (i = 2; i < 2*fftFrameSize-2; i += 2) {
57 for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) {
58 if (i & bitm) j++;
59 j <<= 1;
60 }
61 if (i < j) {
62 p1 = fftBuffer+i; p2 = fftBuffer+j;
63 temp = *p1; *(p1++) = *p2;
64 *(p2++) = temp; temp = *p1;
65 *p1 = *p2; *p2 = temp;
66 }
67 }
68 for (k = 0, le = 2; k < (int)(log(fftFrameSize)/log(2.)+.5); k++) {
69 le <<= 1;
70 le2 = le>>1;
71 ur = 1.0;
72 ui = 0.0;
73 arg = SAF_PI / (le2>>1);
74 wr = cos(arg);
75 wi = sign*sin(arg);
76 for (j = 0; j < le2; j += 2) {
77 p1r = fftBuffer+j; p1i = p1r+1;
78 p2r = p1r+le2; p2i = p2r+1;
79 for (i = j; i < 2*fftFrameSize; i += le) {
80 tr = *p2r * ur - *p2i * ui;
81 ti = *p2r * ui + *p2i * ur;
82 *p2r = *p1r - tr; *p2i = *p1i - ti;
83 *p1r += tr; *p1i += ti;
84 p1r += le; p1i += le;
85 p2r += le; p2i += le;
86 }
87 tr = ur*wr - ui*wi;
88 ui = ur*wi + ui*wr;
89 ur = tr;
90 }
91 }
92}
93#endif
94
98typedef struct _smb_pitchShift_data
99{
100 /* parameters */
101 int fftFrameSize, osamp, nCH;
102 float sampleRate, pitchShiftFactor;
103
104 /* internals */
105 void* hFFT;
106 float* window;
107 float** gInFIFO, **gOutFIFO;
108#ifdef SMB_ENABLE_SAF_FFT
109 float_complex** gFFTworksp_td;
110 float_complex** gFFTworksp_fd;
111#else
112 float** gFFTworksp;
113#endif
114 float** gLastPhase, **gSumPhase;
115 float** gOutputAccum;
116 float** gAnaFreq, **gAnaMagn;
117 float** gSynFreq, **gSynMagn;
118 int* gRover;
119 int stepSize, inFifoLatency;
120
122
124(
125 void** hSmb,
126 int nCH,
127 int fftFrameSize,
128 int osamp,
129 float sampleRate
130)
131{
132 *hSmb = malloc(sizeof(smb_pitchShift_data));
134 int i;
135
136 h->fftFrameSize = fftFrameSize;
137 h->osamp = osamp;
138 h->sampleRate = sampleRate;
139 h->nCH = nCH;
140 h->pitchShiftFactor = 1.0f;
141
142 /* internals */
143 saf_fft_create(&(h->hFFT), fftFrameSize);
144 h->stepSize = fftFrameSize/h->osamp;
145 h->inFifoLatency = fftFrameSize - (h->stepSize);
146 h->gRover = (int*)malloc1d(nCH * sizeof(int));
147 for(i=0; i<nCH; i++)
148 h->gRover[i] = h->inFifoLatency;
149 h->window = (float*)malloc1d(fftFrameSize*sizeof(float));
150 for (i = 0; i < fftFrameSize; i++)
151 h->window[i] = -0.5f*cosf(2.0f*SAF_PI*(float)i/(float)fftFrameSize)+0.5f;
152 h->gInFIFO = (float**)calloc2d(nCH,fftFrameSize,sizeof(float));
153 h->gOutFIFO = (float**)calloc2d(nCH,fftFrameSize,sizeof(float));
154#ifdef SMB_ENABLE_SAF_FFT
155 h->gFFTworksp_td = (float_complex**)calloc2d(nCH,fftFrameSize,sizeof(float_complex));
156 h->gFFTworksp_fd = (float_complex**)calloc2d(nCH,fftFrameSize,sizeof(float_complex));
157#else
158 h->gFFTworksp = (float**)calloc2d(nCH,2*fftFrameSize,sizeof(float));
159#endif
160 h->gLastPhase = (float**)calloc2d(nCH,fftFrameSize/2+1,sizeof(float));
161 h->gSumPhase = (float**)calloc2d(nCH,fftFrameSize/2+1,sizeof(float));
162 h->gOutputAccum = (float**)calloc2d(nCH,2*(h->fftFrameSize),sizeof(float));
163 h->gAnaFreq = (float**)calloc2d(nCH,fftFrameSize,sizeof(float));
164 h->gAnaMagn = (float**)calloc2d(nCH,fftFrameSize,sizeof(float));
165 h->gSynFreq = (float**)malloc2d(nCH,fftFrameSize,sizeof(float));
166 h->gSynMagn = (float**)malloc2d(nCH,fftFrameSize,sizeof(float));
167}
168
170(
171 void ** const hSmb
172)
173{
175 if(h!=NULL){
176 saf_fft_destroy(&(h->hFFT));
177 free(h->window);
178 free(h->gRover);
179 free(h->gInFIFO);
180 free(h->gOutFIFO);
181#ifdef SMB_ENABLE_SAF_FFT
182 free(h->gFFTworksp_td);
183 free(h->gFFTworksp_fd);
184#else
185 free(h->gFFTworksp);
186#endif
187 free(h->gLastPhase);
188 free(h->gSumPhase);
189 free(h->gOutputAccum);
190 free(h->gAnaFreq);
191 free(h->gAnaMagn);
192 free(h->gSynFreq);
193 free(h->gSynMagn);
194 free(h);
195 h = NULL;
196 *hSmb = NULL;
197 }
198}
199
200/* Adapted from: http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
201 * Original Copyright notice:
202 * COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
203 *
204 * The Wide Open License (WOL)
205 *
206 * Permission to use, copy, modify, distribute and sell this software and its
207 * documentation for any purpose is hereby granted without fee, provided that
208 * the above copyright notice and this license appear in all source copies.
209 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
210 * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
211 */
213(
214 void* hSmb,
215 float pitchShift,
216 int frameSize,
217 float *indata,
218 float *outdata
219)
220{
222 float magn, phase, tmp, real, imag;
223 float freqPerBin, expct;
224 int ch, i, k, qpd, index, fftFrameSize2;
225
226 /* set up some handy variables */
227 fftFrameSize2 = h->fftFrameSize/2;
228 freqPerBin = h->sampleRate/(float)h->fftFrameSize;
229 expct = 2.0f*SAF_PI*(float)(h->stepSize)/(float)h->fftFrameSize;
230
231 /* flush buffers */
232 if(h->pitchShiftFactor!=pitchShift){
233 h->pitchShiftFactor = pitchShift;
234 for(ch=0; ch<h->nCH; ch++){
235 memset(h->gOutputAccum[ch], 0, h->stepSize*sizeof(float));
236 memset(h->gLastPhase[ch], 0, (h->fftFrameSize/2+1)*sizeof(float));
237 memset(h->gSumPhase[ch], 0, (h->fftFrameSize/2+1)*sizeof(float));
238 }
239 }
240
241 /* main processing loop */
242 for(ch=0; ch<h->nCH; ch++){
243 for (i = 0; i < frameSize; i++){
244 /* As long as we have not yet collected enough data just read in */
245 h->gInFIFO[ch][h->gRover[ch]] = indata[ch*frameSize+i];
246 outdata[ch*frameSize+i] = h->gOutFIFO[ch][h->gRover[ch]-(h->inFifoLatency)];
247 h->gRover[ch]++;
248
249 /* now we have enough data for processing */
250 if (h->gRover[ch] >= h->fftFrameSize) {
251 h->gRover[ch] = h->inFifoLatency;
252
253#ifdef SMB_ENABLE_SAF_FFT
254 for (k = 0; k < h->fftFrameSize;k++)
255 h->gFFTworksp_td[ch][k] = cmplxf(h->gInFIFO[ch][k] * (float)h->window[k], 0.0f);
256 saf_fft_forward(h->hFFT, h->gFFTworksp_td[ch], h->gFFTworksp_fd[ch]);
257#else
258 /* do windowing and re,im interleave */
259 for (k = 0; k < h->fftFrameSize;k++) {
260 h->gFFTworksp[ch][2*k] = h->gInFIFO[ch][k] * h->window[k];
261 h->gFFTworksp[ch][2*k+1] = 0.;
262 }
263
264 /* do transform */
265 smbFft(h->gFFTworksp[ch], h->fftFrameSize, -1);
266#endif
267
268 /* ***************** ANALYSIS ******************* */
269 for (k = 0; k <= fftFrameSize2; k++) {
270#ifdef SMB_ENABLE_SAF_FFT
271 real = crealf(h->gFFTworksp_fd[ch][k]);
272 imag = cimagf(h->gFFTworksp_fd[ch][k]);
273#else
274 /* de-interlace FFT buffer */
275 real = h->gFFTworksp[ch][2*k];
276 imag = h->gFFTworksp[ch][2*k+1];
277#endif
278 /* compute magnitude and phase */
279 magn = 2.0f*sqrtf(real*real + imag*imag);
280 phase = atan2f(imag,real);
281
282 /* compute phase difference */
283 tmp = phase - h->gLastPhase[ch][k];
284 h->gLastPhase[ch][k] = phase;
285
286 /* subtract expected phase difference */
287 tmp -= (float)k*expct;
288
289 /* map delta phase into +/- Pi interval */
290 qpd = (int)(tmp/SAF_PI);
291 if (qpd >= 0) qpd += qpd&1;
292 else qpd -= qpd&1;
293 tmp -= SAF_PI*(float)qpd;
294
295 /* get deviation from bin frequency from the +/- Pi interval */
296 tmp = (float)h->osamp*tmp/(2.0f*SAF_PI);
297
298 /* compute the k-th partials' true frequency */
299 tmp = (float)k*freqPerBin + tmp*freqPerBin;
300
301 /* store magnitude and true frequency in analysis arrays */
302 h->gAnaMagn[ch][k] = magn;
303 h->gAnaFreq[ch][k] = tmp;
304
305 }
306
307 /* ***************** PROCESSING ******************* */
308 /* this does the actual pitch shifting */
309 memset(h->gSynMagn[ch], 0, h->fftFrameSize*sizeof(float));
310 memset(h->gSynFreq[ch], 0, h->fftFrameSize*sizeof(float));
311 for (k = 0; k <= fftFrameSize2; k++) {
312 index = (int)((float)k*(h->pitchShiftFactor));
313 if (index <= fftFrameSize2) {
314 h->gSynMagn[ch][index] += (h->gAnaMagn[ch][k]);
315 h->gSynFreq[ch][index] = h->gAnaFreq[ch][k] * (h->pitchShiftFactor);
316 }
317 }
318
319 /* ***************** SYNTHESIS ******************* */
320 /* this is the synthesis step */
321 for (k = 0; k <= fftFrameSize2; k++) {
322 /* get magnitude and true frequency from synthesis arrays */
323 magn = h->gSynMagn[ch][k];
324 tmp = h->gSynFreq[ch][k];
325
326 /* subtract bin mid frequency */
327 tmp -= (float)k*freqPerBin;
328
329 /* get bin deviation from freq deviation */
330 tmp /= freqPerBin;
331
332 /* take osamp into account */
333 tmp = 2.0f*SAF_PI*tmp/(h->osamp);
334
335 /* add the overlap phase advance back in */
336 tmp += (float)k*expct;
337
338 /* accumulate delta phase to get bin phase */
339 h->gSumPhase[ch][k] += tmp;
340 phase = h->gSumPhase[ch][k];
341
342#ifdef SMB_ENABLE_SAF_FFT
343 h->gFFTworksp_fd[ch][k] = cmplxf(magn*cosf(phase), magn*sinf(phase));
344#else
345 /* get real and imag part and re-interleave */
346 h->gFFTworksp[ch][2*k] = magn*cos(phase);
347 h->gFFTworksp[ch][2*k+1] = magn*sin(phase);
348#endif
349 }
350
351#ifdef SMB_ENABLE_SAF_FFT
352 for (k = fftFrameSize2+1; k < h->fftFrameSize; k++)
353 h->gFFTworksp_fd[ch][k] = cmplxf(0.0f, 0.0f);
354
355 saf_fft_backward(h->hFFT, h->gFFTworksp_fd[ch], h->gFFTworksp_td[ch]);
356
357 for(k=0; k < h->fftFrameSize; k++)
358 h->gOutputAccum[ch][k] += 2.0f*(h->window[k])*crealf(h->gFFTworksp_td[ch][k])/((h->osamp));
359#else
360 /* zero negative frequencies */
361 for (k = h->fftFrameSize+2; k < 2*(h->fftFrameSize); k++)
362 h->gFFTworksp[ch][k] = 0.;
363
364 /* do inverse transform */
365 smbFft(h->gFFTworksp[ch], h->fftFrameSize, 1);
366
367 /* do windowing and add to output accumulator */
368 for(k=0; k < h->fftFrameSize; k++)
369 h->gOutputAccum[ch][k] += 2.*(h->window[k])*(h->gFFTworksp[ch][2*k])/(fftFrameSize2*(h->osamp));
370#endif
371 for (k = 0; k < h->stepSize; k++)
372 h->gOutFIFO[ch][k] = h->gOutputAccum[ch][k];
373
374 /* shift accumulator */
375 memmove(h->gOutputAccum[ch], h->gOutputAccum[ch] + (h->stepSize), h->fftFrameSize*sizeof(float));
376
377 /* move input FIFO */
378 for (k = 0; k < h->inFifoLatency; k++)
379 h->gInFIFO[ch][k] = h->gInFIFO[ch][k+h->stepSize];
380 }
381 }
382 }
383}
void smb_pitchShift_create(void **hSmb, int nCH, int fftFrameSize, int osamp, float sampleRate)
Creates an instance of SMB PitchShifter.
#define SAF_PI
pi constant (single precision)
void saf_fft_backward(void *const hFFT, float_complex *inputFD, float_complex *outputTD)
Performs the backward-FFT operation; use for complex to complex transformations.
void saf_fft_create(void **const phFFT, int N)
Creates an instance of saf_fft; complex<->complex FFT.
void smb_pitchShift_apply(void *hSmb, float pitchShift, int frameSize, float *indata, float *outdata)
Performs pitch shifting of the input signals, while retaining the same time duration as the original ...
void smb_pitchShift_destroy(void **const hSmb)
Destroys an instance of SMB PitchShifter.
void saf_fft_forward(void *const hFFT, float_complex *inputTD, float_complex *outputFD)
Performs the forward-FFT operation; use for complex to complex transformations.
void saf_fft_destroy(void **const phFFT)
Destroys an instance of saf_fft.
void ** malloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D malloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:89
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
Main header for the utilities module (SAF_UTILITIES_MODULE)
Main structure for the SMB pitch shifter.