Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

hello all this is my Java Code for Boll's 1979 Spectral Subtraction Algorithm in Java . this is based on Esfandiar Zavarehei Matlab code.

i have added some samples. the code works very good and i'm using Jtransforms lib for the FFT and IFFT

i need my code for a university project in Android. so i need to optimize it for real-time Android.

if anyone can please help. or give me a direction

thanks a lot

this is my full code http://www.4shared.com/zip/fOAyocmk/testing.html

public class GGSpecSub {

//Constructor
public GGSpecSub()
{

}

//repmat(1:W,N,1) - do this alreay transpose
public double[][] reprowtrans(int end, int replications)
{
    double[][] result = new double[end +1][replications+1];

    for (int x = 1; x <= end; x++) {
        for (int y = 1; y <= replications; y++) {
            result[x][y] = x ;
        }
    }

    return result;
}

//repmat((0:(N-1))'*SP,1,W) this is already transposed
public double[][] repcoltrans(int end, double multiplier, int replications)
{
    double[][] result = new double[replications+1][end+1];

    for (int x = 1; x <= replications; x++) {
        for (int y = 1; y <= end ; y++) {
            result[x][y] = (y-1)*multiplier;
        }
    }

    return result;
}
//repmat(Window,1,N)
public double[][] repvector(double[] vec, int replications)
{
    double[][] result = new double[vec.length][replications];

    for (int x = 0; x < vec.length; x++) {
        for (int y = 0; y < replications; y++) {
            result[x][y] = vec[x];
        }
    }

    return result;
}

public double[] HammingWindow(int size)
{
    double[] window = new double[size];
    for (int i = 0; i < size; i++)
    {

        window[i] =  0.54-0.46 * (Math.cos(2.0 * Math.PI * i / (size-1)));
    }
    return window;
}

public double[] HanningWindow(int size)
{
    double[] window = new double[size];
    for (int i = 0; i < size; i++)
    {

        window[i] =  0.5 * (1.0 - Math.cos(2.0 * Math.PI * i / size));
    }
    return window;
}

public MatrixAndSegments segment (double[] signal_in,int samplesPerWindow, double shiftPercentage, double[] window)
{
    //default shiftPercentage = 0.4
    //default samplesPerWindow = 256  //W
    //default window = hanning 


    int L = signal_in.length;
    shiftPercentage = fix(samplesPerWindow * shiftPercentage); //SP
    int numberOfSegments = fix ( (L - samplesPerWindow)/ shiftPercentage + 1); //N

    double[][] reprowMatrix =  reprowtrans(samplesPerWindow,numberOfSegments);
    double[][] repcolMatrix = repcoltrans(numberOfSegments, shiftPercentage,samplesPerWindow );

    //Index=(repmat(1:W,N,1)+repmat((0:(N-1))'*SP,1,W))';
    double[][] index = new double[samplesPerWindow+1][numberOfSegments+1];

    for (int x = 1;  x < samplesPerWindow+1; x++ )
    {
        for (int y = 1 ; y < numberOfSegments + 1; y++) //numberOfSegments was 3
        {
             index[x][y] = reprowMatrix[x][y] + repcolMatrix[x][y];
        }
    }

    //hamming window
    double[] hammingWindow = this.HammingWindow(samplesPerWindow);
    double[][] HW = repvector(hammingWindow, numberOfSegments);

    double[][] seg = new double[samplesPerWindow][numberOfSegments];
    for (int y = 1 ; y < numberOfSegments + 1; y++)
    {
        for (int x = 1; x < samplesPerWindow+1; x++)
        {
            seg[x-1][y-1] = signal_in[ (int)index[x][y]-1 ] * HW[x-1][y-1]; 
        }
    }
    MatrixAndSegments Matrixseg = new MatrixAndSegments(numberOfSegments,seg);
    return Matrixseg;

}

//not sure about casting to INT
public int fix(double val) {
    if (val < 0) {
        return (int) Math.ceil(val);
    }
    return (int) Math.floor(val);
}

public double[][] angle(double[][] array,int samplesPerWindow,int numberOfSegments)
{ 
  //array[2*k] = Re[k], 
  //array[2*k+1] = Im[k]
    double[][] phase = new double[fix(samplesPerWindow/2) +1][numberOfSegments];


    if (fix(samplesPerWindow*2/2) + 2 % 2 != 0)
    {
        for (int y = 0; y < numberOfSegments; y++ )
        {   
            for (int x = 0, k = 0; x <= fix(samplesPerWindow*2/2); x = x + 2, k++)
            {
              phase[k][y] = Math.atan2(array[x+1][y],array[x][y]);
            }
        }
    }
    else
    {
        for (int y = 0; y < numberOfSegments; y++ )
        {   
            for (int x = 0, k = 0; x < fix(samplesPerWindow*2/2) + 2; x = x + 2, k++)
            {
              phase[k][y] = Math.atan2(array[x+1][y],array[x][y]);
            }
        }
    }
    return phase;
}

public double[][] complexAbs(double[][] array,int samplesPerWindow,int numberOfSegments)
{ 
  //array[2*k] = Re[k], 
  //array[2*k+1] = Im[k]
    double[][] abs = new double[fix(samplesPerWindow/2) +1][numberOfSegments];


if (fix(samplesPerWindow*2/2) + 2 % 2 != 0)
{

    for (int y = 0; y < numberOfSegments; y++ )
    {   
        for (int x = 0, k = 0; x <= fix(samplesPerWindow*2/2); x = x + 2, k++)
        {
          abs[k][y] = Math.sqrt(  ((array[x+1][y])*(array[x+1][y])) + ((array[x][y])*(array[x][y])) );
        }
    }
}   
else
{
    for (int y = 0; y < numberOfSegments; y++ )
    {   
        for (int x = 0, k = 0; x < fix(samplesPerWindow*2/2); x = x + 2, k++)
        {
          abs[k][y] = Math.sqrt(  ((array[x+1][y])*(array[x+1][y])) + ((array[x][y])*(array[x][y])) );
        }
    }
}
return abs;
}

//does mean of each row and divide by the number of cols
public double[] mean(double[][] array,int samplesPerWindow,int numberOfSegments,int nis )
{
    double[] meanArray = new double[samplesPerWindow];

    for (int x = 0 ; x < samplesPerWindow ; x++)
    {
        for (int y = 0; y < nis ; y++)
        {
            meanArray[x] += array[x][y];
        }
        meanArray[x] = meanArray[x] / nis;
    }
    return meanArray;
}

public vadResult vad(double[] signal,double[] noise,int noiseCounter)
{
    vadResult vadRes = new vadResult();
    int noiseMargin = 3;
    int hangover = 8;
    double sumSpectralDist = 0.0;
    int FreqResol = signal.length;              //FreqResol=length(signal);
    double[] spectralDist = new double[FreqResol];
    //SpectralDist= 20*(log10(signal)-log10(noise));
    for(int i = 0; i < signal.length ; i++){
         double temp = 20 * (Math.log10(signal[i]) - Math.log10(noise[i]));
         spectralDist[i] = (temp < 0) ? 0 : temp;
         sumSpectralDist += spectralDist[i];  
    }

    double dist = sumSpectralDist/(double)signal.length;
    if (dist < noiseMargin){
        vadRes.noiseFlag = true;
        noiseCounter = noiseCounter + 1;
    }
    else{
        vadRes.noiseFlag = false;
        noiseCounter = 0;
    }
    if (noiseCounter > hangover){
        vadRes.speechFlag = false;
    }
    else{
        vadRes.speechFlag = true;
    }
    vadRes.noiseCounter = noiseCounter;
    return vadRes;
}

public double[] getColumn(double[][] signal,int i)
 {
  double[] column = new double[signal.length];
  for (int j = 0 ; j < signal.length ; j++)
  {
   column[j] = signal[j][i];
  }
  return column;
 }

public double[] OverLapAdd2(double[][] XNEW,int XNEWcolNum, double[][]yphase,int windowLen, int shiftLen)
{
    //double[] res= new double[XNEWcolNum];//check me
    double[][] Spec = new double[2*XNEW.length][XNEWcolNum];// x2 fro complex numbers
    if (fix(shiftLen) != shiftLen)
        shiftLen = fix(shiftLen);
    int FreqRes = XNEW.length;//number of Rows in Xnew
    int FrameNum = XNEWcolNum; // number of cols in XNEW
    //array[2*k] = Re[k], 
    //array[2*k+1] = Im[k]



    for (int y = 0;  y < XNEWcolNum; y++ )
    {
        for (int x = 0,k = 0 ; x < 2*XNEW.length; x=x+2, k++)
        {
            double length = Math.exp(0);
            Spec[x][y] =XNEW[k][y]*length*Math.cos(yphase[k][y]); //real
            Spec[x + 1][y] =XNEW[k][y]*length*Math.sin(yphase[k][y]); //im
            //Spec=XNEW.*exp(j*yphase);
        }
    }


    double[][] flipudMatrix= this.flipud(Spec,XNEWcolNum,windowLen);//if mod(windowLen,2) %if FreqResol is odd
                                                                    //    Spec=[Spec;flipud(conj(Spec(2:end,:)))];
                                                                    //else
                                                                    //    Spec=[Spec;flipud(conj(Spec(2:end-1,:)))];
                                                                    //end
    //we do NOT join the Spec and FlipUdmatrix it's a waste of time 
    double[] signal_out = new double[ (((FrameNum -1) * (shiftLen)) + windowLen)];
    DoubleFFT_1D fft = new DoubleFFT_1D((flipudMatrix.length + Spec.length )/2);
    for (int i = 0 ; i < FrameNum; i++)
    {
        int start = ((i /*- 1*/) * shiftLen) + 1;              //start=(i-1)*ShiftLen+1;


        double[] specAndFlipudcol = new double[flipudMatrix.length + Spec.length];  
        for (int j = 0 ; j < (Spec.length) ; j++)
        {
            specAndFlipudcol[j] = Spec[j][i];
        }
        for (int j = 0; j < flipudMatrix.length ;j++)
        {
            specAndFlipudcol[j + Spec.length] = flipudMatrix[j][i];                 //  spec=Spec(:,i);
        }

        fft.realInverse(specAndFlipudcol,true);
        for (int j = start,k = 0 ; j < start + windowLen - 1 ;k++, j++)
            signal_out[j] = signal_out[j] + specAndFlipudcol[k];
        int gili = 0;
    }

    return signal_out;
    //return res;

}

public double[] SSBoll79(double[] signal_in,int fs)
{
    int length = signal_in.length;
    int numberOfSegments;
    int samplesPerWindow = fix(0.025*fs);                                                               //W
    double shiftPercentage = 0.4;
    double IS=0.25;

    int nis = (int)this.fix((IS*fs-samplesPerWindow)/(shiftPercentage * samplesPerWindow)+1); //%number of initial silence segments

    double[] window = new double[samplesPerWindow];                                         //wnd = hamming(W)

    //need to return both the Matrix and number of segments
    MatrixAndSegments Matrixres = this.segment(signal_in, samplesPerWindow, shiftPercentage, window); //y=segment(signal,W,SP,wnd);
    double [][] newRes = new double[samplesPerWindow*2][Matrixres.numberOfSegments];
    double [] colForFFT = new double [samplesPerWindow*2];
    DoubleFFT_1D fft = new DoubleFFT_1D(samplesPerWindow);

    for(int y = 0; y < Matrixres.numberOfSegments; y++)
    {
        //copy the original col into a col and and a col of zeros before FFT
        for(int x = 0; x < samplesPerWindow; x++)
        {
            colForFFT[x] = Matrixres.res[x][y];        
        }

        //fft on each col of the matrix
        fft.realForwardFull(colForFFT);                                                     //Y=fft(y,nfft);

        //copy the output of col*2 size into a new matrix 
        for(int x = 0; x < samplesPerWindow*2; x++)
        {
            newRes[x][y] = colForFFT[x];    
        }

    }
    double[][] yphase =  this.angle(newRes,samplesPerWindow,Matrixres.numberOfSegments); //YPhase=angle(Y(1:fix(end/2)+1,:)); %Noisy Speech Phase

    newRes = this.complexAbs(newRes, samplesPerWindow, Matrixres.numberOfSegments);      //Y=abs(Y(1:fix(end/2)+1,:)).^Gamma;%Specrogram
    int numberOfFrames = Matrixres.numberOfSegments;                                    //numberOfFrames=size(Y,2); //number of cols in newRes matrix
    int FreqResol = (this.fix(samplesPerWindow) + 2) / 2;                               //FreqResol=size(Y,1); //number of rows in newRes matrix
    double[] N  = this.mean(newRes, FreqResol, Matrixres.numberOfSegments,nis);             //N=mean(Y(:,1:NIS)')'; %initial Noise Power Spectrum mean
    double[] NRM = new double[N.length];                                                // NRM=zeros(size(N));% Noise Residual Maximum (Initialization)
    int noiseCounter = 0 ;
    int noiseLength = 9;
    double beta = 0.03;

    double[][] YS = new double[newRes.length][];
    for(int i = 0; i < newRes.length; i++)
          YS[i] = newRes[i].clone();                                                    //YS=Y; %Y Magnitude Averaged
    /*MATLAB CODE
     *  for i=2:(numberOfFrames-1)
            YS(:,i)=(Y(:,i-1)+Y(:,i)+Y(:,i+1))/3;
        end
    */

    for (int y = 1; y < numberOfFrames-1; y++)
    {

        for (int x = 0; x < YS.length; x++ )
        {
            if (y==0){}
            else {
                YS[x][y] = (newRes[x][y-1] + newRes[x][y] + newRes[x][y+1]) / 3.0;      //can be optimized Gilad
            }
        }

    }           

    double[][] X = new double[NRM.length][numberOfFrames];
    for (int i = 0; i < numberOfFrames; i++)
    {
        double[] YScolumn = this.getColumn(YS, i);  
        double[] column = this.getColumn(newRes, i);
        vadResult tempVadResult = this.vad(column, N, noiseCounter);            //[NoiseFlag, SpeechFlag, NoiseCounter, Dist]=vad(Y(:,i).^(1/Gamma),N.^(1/Gamma),NoiseCounter); %Magnitude Spectrum Distance VAD
        noiseCounter = tempVadResult.noiseCounter; // keep the result of the noise counter from last loop
        if (tempVadResult.speechFlag == false)
        {                                                                       //if SpeechFlag==0
                                                                        //N=(NoiseLength*N+Y(:,i))/(NoiseLength+1); %Update and smooth noise
            for (int j = 0; j < N.length ; j++)
            {
                N[j] = (noiseLength * N[j] + column[j])/ (noiseLength + 1);
            YScolumn[j] = YScolumn[j]- N[j];
                NRM[j] = Math.max(NRM[j], YScolumn[j]);                         //NRM=max(NRM,YS(:,i)-N);%Update Maximum Noise Residue
                X[j][i] = beta * column[j];                                     // X(:,i)=Beta*Y(:,i);
            }


        }
        //speechFlag == 1
        else
        {
            double[] D = new double[YScolumn.length];
            for (int j = 0 ;j < YScolumn.length ; j++)
            {
                    D[j] = YScolumn[j]- N[j];
            }
            if ((i > 0) && (i < numberOfFrames-1))
            {   /*  for j=1:length(D)
                        if D(j)<NRM(j)
                            D(j)=min([D(j) YS(j,i-1)-N(j) YS(j,i+1)-N(j)]);
                        end
                    end
                */

                for (int j = 0 ; j < D.length ; j++)
                {
                    if (D[j] < NRM[j])
                    {
                        D[j] = Math.min( Math.min(D[j], YS[j][i-1] - N[j]), (YS[j][i+1]-N[j]) );

                    }
                }
            }
            for (int j = 0; j <D.length;j++)
            {
                X[j][i] = (D[j] < 0.0) ? 0: D[j];                                                        //X(:,i)=max(D,0);
            }

        }
    }
    double[] output= this.OverLapAdd2(X, /*XNEWcolNum*/ numberOfFrames, yphase, /*windowLen*/samplesPerWindow, (int)(shiftPercentage*samplesPerWindow));
    return output;
}


public double[][] flipud(double[][] matrix,int columns,int windowLen)
{
    double[][] conjMatrix = new double[matrix.length][columns]; // does conj to all the complex numbers
    int end;
    conjMatrix = conj(matrix,columns);
    double[][] flipudMatrix;
    if ((windowLen) % 2 == 0){
        end = matrix.length - 4;
        flipudMatrix = new double[end][columns];
    }
    else{
        end = matrix.length - 2;
        flipudMatrix = new double[end][columns];
    }
    for (int i = end,k = 0 ; i >= 2 ;i = i-2, k= k + 2)
    {
        for(int j = 0 ; j < columns ; j++)
        {
            flipudMatrix[k][j] = conjMatrix[i][j];//real part
            flipudMatrix[k+1][j] = conjMatrix[i+1][j];//imaginary part
        }

    }
    return flipudMatrix;
}

public double[][] conj(double[][] originalMatrix,int columns)
{
    double [][] matrix = new double[originalMatrix.length][];
    for(int i = 0; i < originalMatrix.length; i++)
      matrix[i] = originalMatrix[i].clone();

    int end = ((matrix.length/2) % 2 == 0)? matrix.length-2 :matrix.length ;
    for (int i = 3; i < end  ; i=i+2)//we need just the row that are odd and we don't change the first 2 lines // so no 0+1 lines , line 2 is real . line 3 is the first img we need
    {
        for (int j = 0 ; j < columns ; j++)
        {
            matrix[i][j] = -1*matrix[i][j];
        }
    }
    return matrix;
}   
}
share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.