smbPitchShift.m 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. // original source from http://www.dspdimension.com Stephan M. Bernsee
  2. //
  3. // has been modified to use FFT functions from accelerate framework (vdsp)
  4. // tz 11/2011
  5. /****************************************************************************
  6. *
  7. * NAME: smbPitchShift.cpp
  8. * VERSION: 1.2
  9. * HOME URL: http://www.dspdimension.com
  10. * KNOWN BUGS: none
  11. *
  12. * SYNOPSIS: Routine for doing pitch shifting while maintaining
  13. * duration using the Short Time Fourier Transform.
  14. *
  15. * DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
  16. * (one octave down) and 2. (one octave up). A value of exactly 1 does not change
  17. * the pitch. numSampsToProcess tells the routine how many samples in indata[0...
  18. * numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
  19. * numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
  20. * data in-place). fftFrameSize defines the FFT frame size used for the
  21. * processing. Typical values are 1024, 2048 and 4096. It may be any value <=
  22. * MAX_FRAME_LENGTH but it MUST be a power of 2. osamp is the STFT
  23. * oversampling factor which also determines the overlap between adjacent STFT
  24. * frames. It should at least be 4 for moderate scaling ratios. A value of 32 is
  25. * recommended for best quality. sampleRate takes the sample rate for the signal
  26. * in unit Hz, ie. 44100 for 44.1 kHz audio. The data passed to the routine in
  27. * indata[] should be in the range [-1.0, 1.0), which is also the output range
  28. * for the data, make sure you scale the data accordingly (for 16bit signed integers
  29. * you would have to divide (and multiply) by 32768).
  30. *
  31. * COPYRIGHT 1999-2009 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
  32. *
  33. * The Wide Open License (WOL)
  34. *
  35. * Permission to use, copy, modify, distribute and sell this software and its
  36. * documentation for any purpose is hereby granted without fee, provided that
  37. * the above copyright notice and this license appear in all source copies.
  38. * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
  39. * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
  40. *
  41. *****************************************************************************/
  42. #include <string.h>
  43. #include <math.h>
  44. #include <stdio.h>
  45. #import <Accelerate/Accelerate.h>
  46. // #define M_PI 3.14159265358979323846
  47. // #define MAX_FRAME_LENGTH 8192
  48. #define MAX_FRAME_LENGTH 4096 // tz
  49. void smbFft(float *fftBuffer, long fftFrameSize, long sign);
  50. double smbAtan2(double x, double y);
  51. void printFFTInitSnapshot(long fftFrameSize2,long stepSize,double freqPerBin,double expct,
  52. long inFifoLatency, long gRover);
  53. void printFFTSnapshot(long i, long k, long qpd, long index,
  54. double magn, double phase, double tmp,
  55. double window, double real, double imag,
  56. long gRover);
  57. // -----------------------------------------------------------------------------------------------------------------
  58. void smbPitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata)
  59. /*
  60. Routine smbPitchShift(). See top of file for explanation
  61. Purpose: doing pitch shifting while maintaining duration using the Short
  62. Time Fourier Transform.
  63. Author: (c)1999-2009 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
  64. */
  65. {
  66. static float gInFIFO[MAX_FRAME_LENGTH];
  67. static float gOutFIFO[MAX_FRAME_LENGTH];
  68. static float gFFTworksp[2*MAX_FRAME_LENGTH];
  69. static float gLastPhase[MAX_FRAME_LENGTH/2+1];
  70. static float gSumPhase[MAX_FRAME_LENGTH/2+1];
  71. static float gOutputAccum[2*MAX_FRAME_LENGTH];
  72. static float gAnaFreq[MAX_FRAME_LENGTH];
  73. static float gAnaMagn[MAX_FRAME_LENGTH];
  74. static float gSynFreq[MAX_FRAME_LENGTH];
  75. static float gSynMagn[MAX_FRAME_LENGTH];
  76. static long gRover = FALSE, gInit = FALSE;
  77. double magn, phase, tmp, window, real, imag;
  78. double freqPerBin;
  79. double expct; // expected phase difference tz
  80. long i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2;
  81. // float maxMag; // tz maximum magnitude for pitch detection display
  82. // float displayFreq; // true pitch from last window analysis
  83. /* set up some handy variables */
  84. fftFrameSize2 = fftFrameSize/2;
  85. stepSize = fftFrameSize/osamp;
  86. freqPerBin = sampleRate/(double)fftFrameSize;
  87. expct = 2.*M_PI*(double)stepSize/(double)fftFrameSize;
  88. inFifoLatency = fftFrameSize-stepSize;
  89. if (gRover == FALSE) gRover = inFifoLatency;
  90. /* initialize our static arrays */
  91. if (gInit == FALSE) {
  92. // NSLog(@"init static arrays");
  93. printFFTInitSnapshot(fftFrameSize2,stepSize, freqPerBin, expct, inFifoLatency, gRover);
  94. memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
  95. memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
  96. memset(gFFTworksp, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
  97. memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
  98. memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
  99. memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
  100. memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));
  101. memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));
  102. gInit = true;
  103. }
  104. /* main processing loop */
  105. for (i = 0; i < numSampsToProcess; i++){
  106. // loading
  107. // load the next section of data, one stepsize chunk at a time, starting at beginning of indata. the chunk gets loaded
  108. // to a slot at the end of the gInFIFO, while at the same time, the chunk at the beginning of gOutFIFO gets loaded to into
  109. // the outdata buffer one chunk at a time starting at the beginning.
  110. //
  111. // the very first time this pitchshifter is called, the gOutFIFO will be initialized with zero's so it looks like
  112. // there will be some latency before the actual 'processed' samples begin to fill outdata.
  113. //
  114. /* As long as we have not yet collected enough data, just read in */
  115. gInFIFO[gRover] = indata[i];
  116. outdata[i] = gOutFIFO[gRover-inFifoLatency];
  117. gRover++;
  118. /* now we have enough data for processing */
  119. if (gRover >= fftFrameSize) {
  120. gRover = inFifoLatency; // gRover cycles up between (fftFrameSize - stepsize) and fftFrameSize
  121. // eg., 896 - 1024 for an osamp of 8 and framesize of 1024
  122. /* do windowing and re,im interleave */
  123. // note that the first time this runs, the inFIFO will be mostly zeroes, but essentially, the fft runs on
  124. // data that keeps getting slid to the left?
  125. // the window is like a triangular hat that gets imposed over the sample buffer before its input to the fft
  126. // the size of the hat is the fftsize and it scales off the data at beginning and end of the buffer
  127. // i think that the vDSP_ctoz function will accomplish the interleaving and complex formatting stuff below
  128. // we would still need to do the windowing, but maybe there's an apple function for that too
  129. for (k = 0; k < fftFrameSize;k++) {
  130. window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  131. gFFTworksp[2*k] = gInFIFO[k] * window; // real part is winowed amplitude of samples
  132. gFFTworksp[2*k+1] = 0.; // imag part is set to 0
  133. // NSLog(@"i: %d, k: %d, window: %f", i, k, window );
  134. }
  135. /* ***************** ANALYSIS ******************* */
  136. /* do transform */
  137. // lets try replacing this with accelerate functions
  138. smbFft(gFFTworksp, fftFrameSize, -1);
  139. /* this is the analysis step */
  140. // this is looping through the fft output bins in the frequency domain
  141. for (k = 0; k <= fftFrameSize2; k++) {
  142. /* de-interlace FFT buffer */
  143. real = gFFTworksp[2*k];
  144. imag = gFFTworksp[2*k+1];
  145. /* compute magnitude and phase */
  146. magn = 2.*sqrt(real*real + imag*imag);
  147. phase = atan2(imag,real);
  148. /* compute phase difference */
  149. // the gLastPhase[k] would be the phase from the kth frequency bin from the previous transform over this endlessly
  150. // shifting data
  151. tmp = phase - gLastPhase[k];
  152. gLastPhase[k] = phase;
  153. /* subtract expected phase difference */
  154. tmp -= (double)k*expct;
  155. /* map delta phase into +/- Pi interval */
  156. qpd = tmp/M_PI;
  157. if (qpd >= 0) qpd += qpd&1;
  158. else qpd -= qpd&1;
  159. tmp -= M_PI*(double)qpd;
  160. /* get deviation from bin frequency from the +/- Pi interval */
  161. tmp = osamp*tmp/(2.*M_PI);
  162. /* compute the k-th partials' true frequency */
  163. tmp = (double)k*freqPerBin + tmp*freqPerBin;
  164. /* store magnitude and true frequency in analysis arrays */
  165. gAnaMagn[k] = magn;
  166. gAnaFreq[k] = tmp;
  167. }
  168. /*
  169. // pitch detection ------------------
  170. // find max magnitude for this pass
  171. maxMag = 0.0;
  172. displayFreq = 0.0;
  173. for (k = 0; k <= fftFrameSize2; k++) {
  174. if (gAnaMagn[k] > maxMag) {
  175. maxMag = gAnaMagn[k];
  176. displayFreq = gAnaFreq[k];
  177. }
  178. }
  179. NSLog(@"pitch is: %f", displayFreq);
  180. */
  181. /* ***************** PROCESSING ******************* */
  182. /* this does the actual pitch shifting */
  183. memset(gSynMagn, 0, fftFrameSize*sizeof(float)); // why do we zero out the buffer to frame size but
  184. memset(gSynFreq, 0, fftFrameSize*sizeof(float)); // only actually seem to use half of frame size?
  185. // so this code assigns the results of the analysis.
  186. // it sets up pitch shifted bins using analyzed magnitude and analyzed freq * pitchShift
  187. for (k = 0; k <= fftFrameSize2; k++) {
  188. index = (long) (k * pitchShift);
  189. // NSLog(@"i: %d, index: %d, k: %d, pitchShift: %f", i, index, k, pitchShift );
  190. if (index <= fftFrameSize2) {
  191. gSynMagn[index] += gAnaMagn[k];
  192. gSynFreq[index] = gAnaFreq[k] * pitchShift;
  193. }
  194. }
  195. /* ***************** SYNTHESIS ******************* */
  196. /* this is the synthesis step */
  197. for (k = 0; k <= fftFrameSize2; k++) {
  198. /* get magnitude and true frequency from synthesis arrays */
  199. magn = gSynMagn[k];
  200. tmp = gSynFreq[k];
  201. /* subtract bin mid frequency */
  202. tmp -= (double)k*freqPerBin;
  203. /* get bin deviation from freq deviation */
  204. tmp /= freqPerBin;
  205. /* take osamp into account */
  206. tmp = 2.*M_PI*tmp/osamp;
  207. /* add the overlap phase advance back in */
  208. tmp += (double)k*expct;
  209. /* accumulate delta phase to get bin phase */
  210. gSumPhase[k] += tmp;
  211. phase = gSumPhase[k];
  212. /* get real and imag part and re-interleave */
  213. gFFTworksp[2*k] = magn*cos(phase);
  214. gFFTworksp[2*k+1] = magn*sin(phase);
  215. }
  216. /* zero negative frequencies */
  217. for (k = fftFrameSize+2; k < 2*fftFrameSize; k++) gFFTworksp[k] = 0.;
  218. /* do inverse transform */
  219. smbFft(gFFTworksp, fftFrameSize, 1);
  220. /* do windowing and add to output accumulator */
  221. for(k=0; k < fftFrameSize; k++) {
  222. window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  223. gOutputAccum[k] += 2.*window*gFFTworksp[2*k]/(fftFrameSize2*osamp);
  224. }
  225. for (k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];
  226. // why use two different methods to copy memory?
  227. /* shift accumulator */
  228. // this shifts in zeroes from beyond the bounds of framesize to fill the upper step size chunk
  229. memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float));
  230. /* move input FIFO */
  231. for (k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k+stepSize];
  232. }
  233. }
  234. }
  235. // -----------------------------------------------------------------------------------------------------------------
  236. // -----------------------------------------------------------------------------------------------------------------
  237. void smb2PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp,
  238. float sampleRate, float *indata, float *outdata,
  239. FFTSetup fftSetup, float *frequency)
  240. /*
  241. Routine smbPitchShift(). See top of file for explanation
  242. Purpose: doing pitch shifting while maintaining duration using the Short
  243. Time Fourier Transform.
  244. Author: (c)1999-2009 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
  245. */
  246. {
  247. static float gInFIFO[MAX_FRAME_LENGTH];
  248. static float gOutFIFO[MAX_FRAME_LENGTH];
  249. static float gFFTworksp[2*MAX_FRAME_LENGTH];
  250. static float gLastPhase[MAX_FRAME_LENGTH/2+1];
  251. static float gSumPhase[MAX_FRAME_LENGTH/2+1];
  252. static float gOutputAccum[2*MAX_FRAME_LENGTH];
  253. static float gAnaFreq[MAX_FRAME_LENGTH];
  254. static float gAnaMagn[MAX_FRAME_LENGTH];
  255. static float gSynFreq[MAX_FRAME_LENGTH];
  256. static float gSynMagn[MAX_FRAME_LENGTH];
  257. static COMPLEX_SPLIT A;
  258. static long gRover = FALSE, gInit = FALSE;
  259. double magn, phase, tmp, window, real, imag;
  260. double freqPerBin;
  261. double expct; // expected phase difference tz
  262. long i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2;
  263. int stride;
  264. size_t bufferCapacity; // In samples
  265. int log2n, n, nOver2; // params for fft setup
  266. float maxMag; // tz maximum magnitude for pitch detection display
  267. float displayFreq; // true pitch from last window analysis
  268. int pitchCount = 0; // number of times pitch gets measured
  269. float freqTotal = 0; // sum of all pitch measurements
  270. /* set up some handy variables */
  271. fftFrameSize2 = fftFrameSize/2;
  272. stepSize = fftFrameSize/osamp;
  273. freqPerBin = sampleRate/(double)fftFrameSize;
  274. expct = 2.*M_PI*(double)stepSize/(double)fftFrameSize;
  275. inFifoLatency = fftFrameSize-stepSize;
  276. if (gRover == FALSE) gRover = inFifoLatency;
  277. stride = 1;
  278. log2n = log2f(fftFrameSize); // log base2 of max number of frames, eg., 10 for 1024
  279. n = 1 << log2n; // actual max number of frames, eg., 1024 - what a silly way to compute it
  280. nOver2 = fftFrameSize/2;
  281. bufferCapacity = fftFrameSize;
  282. // index = 0;
  283. /* initialize our static arrays */
  284. if (gInit == FALSE) {
  285. // NSLog(@"init static arrays");
  286. printFFTInitSnapshot(fftFrameSize2,stepSize, freqPerBin, expct, inFifoLatency, gRover);
  287. memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
  288. memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));
  289. memset(gFFTworksp, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
  290. memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
  291. memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));
  292. memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));
  293. memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));
  294. memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));
  295. // split complex number buffer
  296. A.realp = (float *)malloc(nOver2 * sizeof(float)); //
  297. A.imagp = (float *)malloc(nOver2 * sizeof(float)); // why is it set to half the frame size
  298. gInit = true;
  299. }
  300. // NSLog(@"before load");
  301. /* main processing loop */
  302. for (i = 0; i < numSampsToProcess; i++){
  303. // loading
  304. // load the next section of data, one stepsize chunk at a time, starting at beginning of indata. the chunk gets loaded
  305. // to a slot at the end of the gInFIFO, while at the same time, the chunk at the beginning of gOutFIFO gets loaded to into
  306. // the outdata buffer one chunk at a time starting at the beginning.
  307. //
  308. // the very first time this pitchshifter is called, the gOutFIFO will be initialized with zero's so it looks like
  309. // there will be some latency before the actual 'processed' samples begin to fill outdata.
  310. //
  311. /* As long as we have not yet collected enough data, just read in */
  312. gInFIFO[gRover] = indata[i];
  313. outdata[i] = gOutFIFO[gRover-inFifoLatency];
  314. gRover++;
  315. /* now we have enough data for processing */
  316. if (gRover >= fftFrameSize) {
  317. gRover = inFifoLatency; // gRover cycles up between (fftFrameSize - stepsize) and fftFrameSize
  318. // eg., 896 - 1024 for an osamp of 8 and framesize of 1024
  319. /* do windowing and re,im interleave */
  320. // note that the first time this runs, the inFIFO will be mostly zeroes, but essentially, the fft runs on
  321. // data that keeps getting slid to the left?
  322. // the window is like a triangular hat that gets imposed over the sample buffer before its input to the fft
  323. // the size of the hat is the fftsize and it scales off the data at beginning and end of the buffer
  324. // i think that the vDSP_ctoz function will accomplish the interleaving and complex formatting stuff below
  325. // we would still need to do the windowing, but maybe there's an apple function for that too
  326. // for (k = 0; k < fftFrameSize;k++) {
  327. // window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  328. // gFFTworksp[2*k] = gInFIFO[k] * window; // real part is winowed amplitude of samples
  329. // gFFTworksp[2*k+1] = 0.; // imag part is set to 0
  330. // // NSLog(@"i: %d, k: %d, window: %f", i, k, window );
  331. // }
  332. for (k = 0; k < fftFrameSize;k++) {
  333. window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  334. gFFTworksp[k] = gInFIFO[k] * window; // real part is winowed amplitude of samples
  335. // gFFTworksp[2*k+1] = 0.; // imag part is set to 0
  336. // NSLog(@"i: %d, k: %d, window: %f", i, k, window );
  337. }
  338. // cast to complex interleaved then convert to split complex vector
  339. vDSP_ctoz((COMPLEX*)gFFTworksp, 2, &A, 1, nOver2);
  340. // Carry out a Forward FFT transform.
  341. // NSLog(@"before transform");
  342. vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_FORWARD);
  343. // NSLog(@"after transform");
  344. // convert from split complex to complex interleaved for analysis
  345. vDSP_ztoc(&A, 1, (COMPLEX *)gFFTworksp, 2, nOver2);
  346. /* ***************** ANALYSIS ******************* */
  347. /* do transform */
  348. // lets try replacing this with accelerate functions
  349. // smbFft(gFFTworksp, fftFrameSize, -1);
  350. /* this is the analysis step */
  351. // this is looping through the fft output bins in the frequency domain
  352. for (k = 0; k <= fftFrameSize2; k++) {
  353. /* de-interlace FFT buffer */
  354. real = gFFTworksp[2*k];
  355. imag = gFFTworksp[2*k+1];
  356. /* compute magnitude and phase */
  357. magn = 2.*sqrt(real*real + imag*imag);
  358. phase = atan2(imag,real);
  359. /* compute phase difference */
  360. // the gLastPhase[k] would be the phase from the kth frequency bin from the previous transform over this endlessly
  361. // shifting data
  362. tmp = phase - gLastPhase[k];
  363. gLastPhase[k] = phase;
  364. /* subtract expected phase difference */
  365. tmp -= (double)k*expct;
  366. /* map delta phase into +/- Pi interval */
  367. qpd = tmp/M_PI;
  368. if (qpd >= 0) qpd += qpd&1;
  369. else qpd -= qpd&1;
  370. tmp -= M_PI*(double)qpd;
  371. /* get deviation from bin frequency from the +/- Pi interval */
  372. tmp = osamp*tmp/(2.*M_PI);
  373. /* compute the k-th partials' true frequency */
  374. tmp = (double)k*freqPerBin + tmp*freqPerBin;
  375. /* store magnitude and true frequency in analysis arrays */
  376. gAnaMagn[k] = magn;
  377. gAnaFreq[k] = tmp;
  378. }
  379. // pitch detection ------------------
  380. // find max magnitude for this pass
  381. maxMag = 0.0;
  382. displayFreq = 0.0;
  383. for (k = 0; k <= fftFrameSize2; k++) {
  384. if (gAnaMagn[k] > maxMag) {
  385. maxMag = gAnaMagn[k];
  386. displayFreq = gAnaFreq[k];
  387. }
  388. }
  389. freqTotal += displayFreq;
  390. pitchCount++;
  391. /* ***************** PROCESSING ******************* */
  392. /* this does the actual pitch shifting */
  393. memset(gSynMagn, 0, fftFrameSize*sizeof(float)); // why do we zero out the buffer to frame size but
  394. memset(gSynFreq, 0, fftFrameSize*sizeof(float)); // only actually seem to use half of frame size?
  395. // so this code assigns the results of the analysis.
  396. // it sets up pitch shifted bins using analyzed magnitude and analyzed freq * pitchShift
  397. for (k = 0; k <= fftFrameSize2; k++) {
  398. index = (long) (k * pitchShift);
  399. // NSLog(@"i: %d, index: %d, k: %d, pitchShift: %f", i, index, k, pitchShift );
  400. if (index <= fftFrameSize2) {
  401. gSynMagn[index] += gAnaMagn[k];
  402. gSynFreq[index] = gAnaFreq[k] * pitchShift;
  403. }
  404. }
  405. /* ***************** SYNTHESIS ******************* */
  406. /* this is the synthesis step */
  407. for (k = 0; k <= fftFrameSize2; k++) {
  408. /* get magnitude and true frequency from synthesis arrays */
  409. magn = gSynMagn[k];
  410. tmp = gSynFreq[k];
  411. /* subtract bin mid frequency */
  412. tmp -= (double)k*freqPerBin;
  413. /* get bin deviation from freq deviation */
  414. tmp /= freqPerBin;
  415. /* take osamp into account */
  416. tmp = 2.*M_PI*tmp/osamp;
  417. /* add the overlap phase advance back in */
  418. tmp += (double)k*expct;
  419. /* accumulate delta phase to get bin phase */
  420. gSumPhase[k] += tmp;
  421. phase = gSumPhase[k];
  422. /* get real and imag part and re-interleave */
  423. gFFTworksp[2*k] = magn*cos(phase);
  424. gFFTworksp[2*k+1] = magn*sin(phase);
  425. }
  426. /* zero negative frequencies */
  427. for (k = fftFrameSize+2; k < 2*fftFrameSize; k++) gFFTworksp[k] = 0.;
  428. // convert from complex interleaved to split complex vector
  429. vDSP_ctoz((COMPLEX*)gFFTworksp, 2, &A, 1, nOver2);
  430. // Carry out an inverse FFT transform.
  431. vDSP_fft_zrip(fftSetup, &A, stride, log2n, FFT_INVERSE );
  432. // scale it
  433. // the suggested scale factor makes the sound barely audible
  434. // so we should probably experiment with various things
  435. // I have a hunch that the stfft needs a different kind of scaling
  436. // float scale = (float) 1.0 / (2 * n);
  437. // float scale = (float) 1.0 / (osamp);
  438. float scale = .25;
  439. vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, nOver2 );
  440. vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, nOver2 );
  441. // covert from split complex to complex interleaved
  442. vDSP_ztoc(&A, 1, (COMPLEX *) gFFTworksp, 2, nOver2);
  443. /* do inverse transform */
  444. // smbFft(gFFTworksp, fftFrameSize, 1);
  445. /* do windowing and add to output accumulator */
  446. /*
  447. for(k=0; k < fftFrameSize; k++) {
  448. window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  449. gOutputAccum[k] += 2.*window*gFFTworksp[2*k]/(fftFrameSize2*osamp);
  450. }
  451. */
  452. /* do windowing and add to output accumulator */
  453. for(k=0; k < fftFrameSize; k++) {
  454. window = -.5*cos(2.*M_PI*(double)k/(double)fftFrameSize)+.5;
  455. gOutputAccum[k] += 2.*window*gFFTworksp[k]/(fftFrameSize2*osamp);
  456. }
  457. for (k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];
  458. // why use two different methods to copy memory?
  459. /* shift accumulator */
  460. // this shifts in zeroes from beyond the bounds of framesize to fill the upper step size chunk
  461. memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float));
  462. /* move input FIFO */
  463. for (k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k+stepSize];
  464. }
  465. }
  466. // NSLog(@"pitchCount: %d", pitchCount);
  467. *frequency = (float) (freqTotal / pitchCount);
  468. // NSLog(@"pitch is: %f", *frequency );
  469. }
  470. // -----------------------------------------------------------------------------------------------------------------
  471. void smbFft(float *fftBuffer, long fftFrameSize, long sign)
  472. /*
  473. FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)
  474. Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the
  475. time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes
  476. and returns the cosine and sine parts in an interleaved manner, ie.
  477. fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize
  478. must be a power of 2. It expects a complex input signal (see footnote 2),
  479. ie. when working with 'common' audio signals our input signal has to be
  480. passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform
  481. of the frequencies of interest is in fftBuffer[0...fftFrameSize].
  482. */
  483. {
  484. float wr, wi, arg, *p1, *p2, temp;
  485. float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
  486. long i, bitm, j, le, le2, k;
  487. for (i = 2; i < 2*fftFrameSize-2; i += 2) {
  488. for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) {
  489. if (i & bitm) j++;
  490. j <<= 1;
  491. }
  492. if (i < j) {
  493. p1 = fftBuffer+i; p2 = fftBuffer+j;
  494. temp = *p1; *(p1++) = *p2;
  495. *(p2++) = temp; temp = *p1;
  496. *p1 = *p2; *p2 = temp;
  497. }
  498. }
  499. for (k = 0, le = 2; k < (long)(log(fftFrameSize)/log(2.)+.5); k++) {
  500. le <<= 1;
  501. le2 = le>>1;
  502. ur = 1.0;
  503. ui = 0.0;
  504. arg = M_PI / (le2>>1);
  505. wr = cos(arg);
  506. wi = sign*sin(arg);
  507. for (j = 0; j < le2; j += 2) {
  508. p1r = fftBuffer+j; p1i = p1r+1;
  509. p2r = p1r+le2; p2i = p2r+1;
  510. for (i = j; i < 2*fftFrameSize; i += le) {
  511. tr = *p2r * ur - *p2i * ui;
  512. ti = *p2r * ui + *p2i * ur;
  513. *p2r = *p1r - tr; *p2i = *p1i - ti;
  514. *p1r += tr; *p1i += ti;
  515. p1r += le; p1i += le;
  516. p2r += le; p2i += le;
  517. }
  518. tr = ur*wr - ui*wi;
  519. ui = ur*wi + ui*wr;
  520. ur = tr;
  521. }
  522. }
  523. }
  524. // -----------------------------------------------------------------------------------------------------------------
  525. /*
  526. 12/12/02, smb
  527. PLEASE NOTE:
  528. There have been some reports on domain errors when the atan2() function was used
  529. as in the above code. Usually, a domain error should not interrupt the program flow
  530. (maybe except in Debug mode) but rather be handled "silently" and a global variable
  531. should be set according to this error. However, on some occasions people ran into
  532. this kind of scenario, so a replacement atan2() function is provided here.
  533. If you are experiencing domain errors and your program stops, simply replace all
  534. instances of atan2() with calls to the smbAtan2() function below.
  535. */
  536. double smbAtan2(double x, double y)
  537. {
  538. double signx;
  539. if (x > 0.) signx = 1.;
  540. else signx = -1.;
  541. if (x == 0.) return 0.;
  542. if (y == 0.) return signx * M_PI / 2.;
  543. return atan2(x, y);
  544. }
  545. // tz utility functions
  546. void printFFTInitSnapshot(long fftFrameSize2,long stepSize,double freqPerBin,double expct,
  547. long inFifoLatency, long gRover) {
  548. // NSLog(@"fft init snapshot");
  549. //
  550. // NSLog(@"fftFrameSize2: %ld", fftFrameSize2);
  551. // NSLog(@"stepSize: %ld", stepSize);
  552. // NSLog(@"freqPerBin: %f", freqPerBin);
  553. // NSLog(@"expct: %f", expct);
  554. // NSLog(@"inFifoLatency: %ld", inFifoLatency);
  555. // NSLog(@"gRover: %ld", gRover);
  556. }
  557. void printFFTSnapshot(long i, long k, long qpd, long index,
  558. double magn, double phase, double tmp,
  559. double window, double real, double imag,
  560. long gRover){
  561. // NSLog(@"fft snapshot");
  562. // NSLog(@"i: %ld, k: %ld, qpd: %ld, index: %ld", i,k,qpd,index);
  563. // NSLog(@"magn: %f, phase: %f, tmp: %f", magn, phase, tmp );
  564. // NSLog(@"window: %f, real: %f, imag: %f ", window, real, imag);
  565. // NSLog(@"gRover %ld", gRover);
  566. //
  567. }
  568. // -----------------------------------------------------------------------------------------------------------------
  569. // -----------------------------------------------------------------------------------------------------------------
  570. // -----------------------------------------------------------------------------------------------------------------