Guest User

Untitled

a guest
Aug 20th, 2018
217
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /****************************************************************************
  2. *
  3. * NAME: PitchShift.cs
  4. * VERSION: 1.2
  5. * HOME URL: http://www.dspdimension.com
  6. * KNOWN BUGS: none
  7. *
  8. * SYNOPSIS: Routine for doing pitch shifting while maintaining
  9. * duration using the Short Time Fourier Transform.
  10. *
  11. * DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5
  12. * (one octave down) and 2. (one octave up). A value of exactly 1 does not change
  13. * the pitch. numSampsToProcess tells the routine how many samples in indata[0...
  14. * numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...
  15. * numSampsToProcess-1]. The two buffers can be identical (ie. it can process the
  16. * data in-place). fftFrameSize defines the FFT frame size used for the
  17. * processing. Typical values are 1024, 2048 and 4096. It may be any value <=
  18. * MAX_FRAME_LENGTH but it MUST be a power of 2. osamp is the STFT
  19. * oversampling factor which also determines the overlap between adjacent STFT
  20. * frames. It should at least be 4 for moderate scaling ratios. A value of 32 is
  21. * recommended for best quality. sampleRate takes the sample rate for the signal
  22. * in unit Hz, ie. 44100 for 44.1 kHz audio. The data passed to the routine in
  23. * indata[] should be in the range [-1.0, 1.0), which is also the output range
  24. * for the data, make sure you scale the data accordingly (for 16bit signed integers
  25. * you would have to divide (and multiply) by 32768).
  26. *
  27. * COPYRIGHT 1999-2006 Stephan M. Bernsee <smb [AT] dspdimension [DOT] com>
  28. *
  29. *                       The Wide Open License (WOL)
  30. *
  31. * Permission to use, copy, modify, distribute and sell this software and its
  32. * documentation for any purpose is hereby granted without fee, provided that
  33. * the above copyright notice and this license appear in all source copies.
  34. * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
  35. * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
  36. *
  37. *****************************************************************************/
  38.  
  39. /****************************************************************************
  40. *
  41. * This code was converted to C# by Michael Knight
  42. * madmik3 at gmail dot com.
  43. * http://sites.google.com/site/mikescoderama/
  44. *
  45. *****************************************************************************/
  46.  
  47.  
  48. using System.Collections;
  49. using System.Collections.Generic;
  50. using UnityEngine;
  51.  
  52. public static class PitchShifter
  53. {
  54.  
  55.     #region Private Static Memebers
  56.     private static int MAX_FRAME_LENGTH = 16000;
  57.     private static float[] gInFIFO = new float[MAX_FRAME_LENGTH];
  58.     private static float[] gOutFIFO = new float[MAX_FRAME_LENGTH];
  59.     private static float[] gFFTworksp = new float[2 * MAX_FRAME_LENGTH];
  60.     private static float[] gLastPhase = new float[MAX_FRAME_LENGTH / 2 + 1];
  61.     private static float[] gSumPhase = new float[MAX_FRAME_LENGTH / 2 + 1];
  62.     private static float[] gOutputAccum = new float[2 * MAX_FRAME_LENGTH];
  63.     private static float[] gAnaFreq = new float[MAX_FRAME_LENGTH];
  64.     private static float[] gAnaMagn = new float[MAX_FRAME_LENGTH];
  65.     private static float[] gSynFreq = new float[MAX_FRAME_LENGTH];
  66.     private static float[] gSynMagn = new float[MAX_FRAME_LENGTH];
  67.     private static long gRover, gInit;
  68.  
  69.     public static int Progress = 0;
  70.     #endregion
  71.  
  72.     #region Public Static  Methods
  73.     public static float[] PitchShift(float pitchShift, long numSampsToProcess,
  74.        float sampleRate, float[] indata)
  75.     {
  76.         return PitchShift(pitchShift, numSampsToProcess, (long)2048, (long)10, sampleRate, indata);
  77.     }
  78.     public static float[] PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize,
  79.         long osamp, float sampleRate, float[] indata)
  80.     {
  81.         int MAX_FRAME_LENGTH = 16000;
  82.         gInFIFO = new float[MAX_FRAME_LENGTH];
  83.         gOutFIFO = new float[MAX_FRAME_LENGTH];
  84.         gFFTworksp = new float[2 * MAX_FRAME_LENGTH];
  85.         gLastPhase = new float[MAX_FRAME_LENGTH / 2 + 1];
  86.         gSumPhase = new float[MAX_FRAME_LENGTH / 2 + 1];
  87.         gOutputAccum = new float[2 * MAX_FRAME_LENGTH];
  88.         gAnaFreq = new float[MAX_FRAME_LENGTH];
  89.         gAnaMagn = new float[MAX_FRAME_LENGTH];
  90.         gSynFreq = new float[MAX_FRAME_LENGTH];
  91.         gSynMagn = new float[MAX_FRAME_LENGTH];
  92.         gRover = 0; gInit=0;
  93.         float magn, phase, tmp, window, real, imag;
  94.         float freqPerBin, expct;
  95.         long i, k, qpd, index, inFifoLatency, stepSize, fftFrameSize2;
  96.  
  97.  
  98.         float[] outdata = indata;
  99.         /* set up some handy variables */
  100.         fftFrameSize2 = fftFrameSize / 2;
  101.         stepSize = fftFrameSize / osamp;
  102.         freqPerBin = sampleRate / (float)fftFrameSize;
  103.         expct = 2.0f * Mathf.PI * (float)stepSize / (float)fftFrameSize;
  104.         inFifoLatency = fftFrameSize - stepSize;
  105.         if (gRover == 0) gRover = inFifoLatency;
  106.  
  107.  
  108.         /* main processing loop */
  109.         Debug.Log(numSampsToProcess);
  110.         for (i = 0; i < numSampsToProcess; i++)
  111.         {
  112.             Progress = (int)(((i + 1) * 100) / (1.0f * numSampsToProcess));
  113.             /* As long as we have not yet collected enough data just read in */
  114.             gInFIFO[gRover] = indata[i];
  115.             outdata[i] = gOutFIFO[gRover - inFifoLatency];
  116.             gRover++;
  117.  
  118.             /* now we have enough data for processing */
  119.             if (gRover >= fftFrameSize)
  120.             {
  121.                 gRover = inFifoLatency;
  122.                
  123.                 /* do windowing and re,im interleave */
  124.                 for (k = 0; k < fftFrameSize; k++)
  125.                 {
  126.                     window = -.5f * Mathf.Cos(2.0f * Mathf.PI * (float)k / (float)fftFrameSize) + .5f;
  127.                     gFFTworksp[2 * k] = (float)(gInFIFO[k] * window);
  128.                     gFFTworksp[2 * k + 1] = 0.0F;
  129.                 }
  130.                
  131.                 /* ***************** ANALYSIS ******************* */
  132.                 /* do transform */
  133.                 ShortTimeFourierTransform(gFFTworksp, fftFrameSize, -1);
  134.                
  135.                 /* this is the analysis step */
  136.                 for (k = 0; k <= fftFrameSize2; k++)
  137.                 {
  138.  
  139.                     /* de-interlace FFT buffer */
  140.                     real = gFFTworksp[2 * k];
  141.                     imag = gFFTworksp[2 * k + 1];
  142.  
  143.                     /* compute magnitude and phase */
  144.                     magn = 2.0f * Mathf.Sqrt(real * real + imag * imag);
  145.                     phase = Mathf.Atan2(imag, real);
  146.  
  147.                     /* compute phase difference */
  148.                     tmp = phase - gLastPhase[k];
  149.                     gLastPhase[k] = (float)phase;
  150.  
  151.                     /* subtract expected phase difference */
  152.                     tmp -= (float)k * expct;
  153.  
  154.                     /* map delta phase into +/- Pi interval */
  155.                     qpd = (long)(tmp / Mathf.PI);
  156.                     if (qpd >= 0) qpd += qpd & 1;
  157.                     else qpd -= qpd & 1;
  158.                     tmp -= Mathf.PI * (float)qpd;
  159.  
  160.                     /* get deviation from bin frequency from the +/- Pi interval */
  161.                     tmp = osamp * tmp / (2.0f * Mathf.PI);
  162.  
  163.                     /* compute the k-th partials' true frequency */
  164.                     tmp = (float)k * freqPerBin + tmp * freqPerBin;
  165.  
  166.                     /* store magnitude and true frequency in analysis arrays */
  167.                     gAnaMagn[k] = (float)magn;
  168.                     gAnaFreq[k] = (float)tmp;
  169.  
  170.                 }
  171.  
  172.                 /* ***************** PROCESSING ******************* */
  173.                 /* this does the actual pitch shifting */
  174.                 for (int zero = 0; zero < fftFrameSize; zero++)
  175.                 {
  176.                     gSynMagn[zero] = 0;
  177.                     gSynFreq[zero] = 0;
  178.                 }
  179.  
  180.                 for (k = 0; k <= fftFrameSize2; k++)
  181.                 {
  182.                     index = (long)(k * pitchShift);
  183.                     if (index <= fftFrameSize2)
  184.                     {
  185.                         gSynMagn[index] += gAnaMagn[k];
  186.                         gSynFreq[index] = gAnaFreq[k] * pitchShift;
  187.                     }
  188.                     else break;
  189.                 }
  190.  
  191.  
  192.                 /* ***************** SYNTHESIS ******************* */
  193.                 /* this is the synthesis step */
  194.                 for (k = 0; k <= fftFrameSize2; k++)
  195.                 {
  196.  
  197.                     /* get magnitude and true frequency from synthesis arrays */
  198.                     magn = gSynMagn[k];
  199.                     tmp = gSynFreq[k];
  200.  
  201.                     /* subtract bin mid frequency */
  202.                     tmp -= (float)k * freqPerBin;
  203.  
  204.                     /* get bin deviation from freq deviation */
  205.                     tmp /= freqPerBin;
  206.  
  207.                     /* take osamp into account */
  208.                     tmp = 2.0f * Mathf.PI * tmp / osamp;
  209.  
  210.                     /* add the overlap phase advance back in */
  211.                     tmp += (float)k * expct;
  212.  
  213.                     /* accumulate delta phase to get bin phase */
  214.                     gSumPhase[k] += (float)tmp;
  215.                     phase = gSumPhase[k];
  216.  
  217.                     /* get real and imag part and re-interleave */
  218.                     gFFTworksp[2 * k] = (float)(magn * Mathf.Cos(phase));
  219.                     gFFTworksp[2 * k + 1] = (float)(magn * Mathf.Sin(phase));
  220.                 }
  221.  
  222.                 /* zero negative frequencies */
  223.                 for (k = fftFrameSize + 2; k < 2 * fftFrameSize; k++) gFFTworksp[k] = 0.0F;
  224.  
  225.                 /* do inverse transform */
  226.                 ShortTimeFourierTransform(gFFTworksp, fftFrameSize, 1);
  227.  
  228.                 /* do windowing and add to output accumulator */
  229.                 for (k = 0; k < fftFrameSize; k++)
  230.                 {
  231.                     window = -.5f * Mathf.Cos(2.0f * Mathf.PI * (float)k / (float)fftFrameSize) + .5f;
  232.                     gOutputAccum[k] += (float)(2.0 * window * gFFTworksp[2 * k] / (fftFrameSize2 * osamp));
  233.                 }
  234.                 for (k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];
  235.  
  236.                 /* shift accumulator */
  237.                 //memmove(gOutputAccum, gOutputAccum + stepSize, fftFrameSize * sizeof(float));
  238.                 for (k = 0; k < fftFrameSize; k++)
  239.                 {
  240.                     gOutputAccum[k] = gOutputAccum[k + stepSize];
  241.                 }
  242.  
  243.                 /* move input FIFO */
  244.                 for (k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k + stepSize];
  245.             }
  246.         }
  247.  
  248.         return outdata;
  249.     }
  250.     #endregion
  251.  
  252.     #region Private Static Methods
  253.     public static void ShortTimeFourierTransform(float[] fftBuffer, long fftFrameSize, long sign)
  254.     {
  255.  
  256.         float wr, wi, arg, temp;
  257.         float tr, ti, ur, ui;
  258.         long i, bitm, j, le, le2, k;
  259.  
  260.         for (i = 2; i < 2 * fftFrameSize - 2; i += 2)
  261.         {
  262.             for (bitm = 2, j = 0; bitm < 2 * fftFrameSize; bitm <<= 1)
  263.             {
  264.                 if ((i & bitm) != 0) j++;
  265.                 j <<= 1;
  266.             }
  267.             if (i < j)
  268.             {
  269.                 temp = fftBuffer[i];
  270.                 fftBuffer[i] = fftBuffer[j];
  271.                 fftBuffer[j] = temp;
  272.                 temp = fftBuffer[i + 1];
  273.                 fftBuffer[i + 1] = fftBuffer[j + 1];
  274.                 fftBuffer[j + 1] = temp;
  275.             }
  276.         }
  277.         long max = (long)(Mathf.Log(fftFrameSize) / Mathf.Log(2.0f) + .5);
  278.         for (k = 0, le = 2; k < max; k++)
  279.         {
  280.             le <<= 1;
  281.             le2 = le >> 1;
  282.             ur = 1.0F;
  283.             ui = 0.0F;
  284.             arg = (float)Mathf.PI / (le2 >> 1);
  285.             wr = (float)Mathf.Cos(arg);
  286.             wi = (float)(sign * Mathf.Sin(arg));
  287.             for (j = 0; j < le2; j += 2)
  288.             {
  289.  
  290.                 for (i = j; i < 2 * fftFrameSize; i += le)
  291.                 {
  292.                     tr = fftBuffer[i + le2] * ur - fftBuffer[i + le2 + 1] * ui;
  293.                     ti = fftBuffer[i + le2] * ui + fftBuffer[i + le2 + 1] * ur;
  294.                     fftBuffer[i + le2] = fftBuffer[i] - tr;
  295.                     fftBuffer[i + le2 + 1] = fftBuffer[i + 1] - ti;
  296.                     fftBuffer[i] += tr;
  297.                     fftBuffer[i + 1] += ti;
  298.  
  299.                 }
  300.                 tr = ur * wr - ui * wi;
  301.                 ui = ur * wi + ui * wr;
  302.                 ur = tr;
  303.             }
  304.         }
  305.     }
  306.     #endregion
  307. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×