Advertisement
Guest User

Untitled

a guest
Aug 20th, 2018
567
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.33 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement