繁体   English   中英

在Java中应用Hamming,然后对wav文件进行FFT

[英]Apply Hamming followed by FFT of wav file in Java

我正在尝试执行海明运算,然后执行wav文件的FFT。 我已经在python中实现了相同的功能。 如何在Java中执行此操作。 我在给定的wave文件上应用了汉明,该文件返回一个bytearrayOutputStream。 现在如何在此byteArrayOutputStream上执行FFT? 我是音频处理的新手。 我当前的代码是:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;


import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

public class AudioFFT {

    public static void main(String[] args) throws UnsupportedAudioFileException, IOException {


        String wavFilePath="C:\\abc.wav";
        ByteArrayOutputStream byteArrayOutputStream=applyHamming(wavFilePath);
        byte[] bytesOut=byteArrayOutputStream.toByteArray();   
        System.out.println(Arrays.toString(bytesOut));
    }

    public static ByteArrayOutputStream applyHamming(String filePath)

    {
        // TODO Auto-generated method stub

        ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
        File fileIn = new File(filePath);
        AudioInputStream audioInputStream;
        try {
            audioInputStream = AudioSystem.getAudioInputStream(fileIn);
            int bytesPerFrame = audioInputStream.getFormat().getFrameSize();
            if (bytesPerFrame == AudioSystem.NOT_SPECIFIED) {
                bytesPerFrame = 1;
            }
            int numBytes = 1024 * bytesPerFrame;
            byte[] audioBytes = new byte[numBytes];
            int numBytesRead = 0;

            while ((numBytesRead = audioInputStream.read(audioBytes, 0, audioBytes.length)) != -1) {

                outputStream.write(audioBytes, 0, numBytesRead);
            }

        } catch (UnsupportedAudioFileException | IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        return outputStream;
    }


    private static int BITS_IN_BYTE = 8;

    private static AudioInputStream audioInputStream;
    private static AudioFormat format;
    final static int W = 1024;

    public static void getFFT() {
        String wavFilePath="C:\\abc.wav";;
        File AudioFile = new File(wavFilePath);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedInputStream in;

        try {
            audioInputStream = AudioSystem.getAudioInputStream(AudioFile);
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        format = audioInputStream.getFormat();
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);

        if (!AudioSystem.isLineSupported(info)) {
            System.out.println("Error");
        }

        TargetDataLine line = null;
        try {

            line = (TargetDataLine) AudioSystem.getLine(info);
            line.open(format);

        } catch (LineUnavailableException ex) {
            System.out.println("Error");
        }

        line.start();
        byte[] data = new byte[W * format.getSampleSizeInBits() / BITS_IN_BYTE];
        double[] inbuf = new double[W];
        double[] fftbuf = new double[W];

        try {
            in = new BufferedInputStream(new FileInputStream(AudioFile));
            int read;
            while ((read = in.read(data)) > 0) {
                out.write(data, 0, read);
            }
            out.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        data = out.toByteArray();

        decode(data, inbuf);

        fft(inbuf, fftbuf);

    }

    public static void decode(byte[] input, double[] output) {
        assert input.length == 2 * output.length;
        for (int i = 0; i < output.length; i++) {
            output[i] = (short) (((0xFF & input[2 * i + 1]) << 8) | (0xFF & input[2 * i]));
            output[i] /= Short.MAX_VALUE;
        }
    }

    public static void fft(final double[] inputReal, double[] inputImag) {
        assert inputReal.length == 2 * inputImag.length;
        int n = inputReal.length;
        double ld = Math.log(n) / Math.log(2.0);

        if (((int) ld) - ld != 0) {
            System.out.println("The number of elements is not a power of 2.");
        }
        int nu = (int) ld;
        int n2 = n / 2;
        int nu1 = nu - 1;
        double[] xReal = new double[n];
        double[] xImag = new double[n];
        double tReal, tImag, p, arg, c, s;

        double constant;
        if (true){
            constant = -2 * Math.PI;
        }

        for (int i = 0; i < n; i++) {
            xReal[i] = inputReal[i];
            xImag[i] = inputImag[i];
        }

        int k = 0;
        for (int l = 1; l <= nu; l++) {
            while (k < n) {
                for (int i = 1; i <= n2; i++) {
                    p = bitreverseReference(k >> nu1, nu);
                    arg = constant * p / n;
                    c = Math.cos(arg);
                    s = Math.sin(arg);
                    tReal = xReal[k + n2] * c + xImag[k + n2] * s;
                    tImag = xImag[k + n2] * c - xReal[k + n2] * s;
                    xReal[k + n2] = xReal[k] - tReal;
                    xImag[k + n2] = xImag[k] - tImag;
                    xReal[k] += tReal;
                    xImag[k] += tImag;
                    k++;
                }
                k += n2;
            }
            k = 0;
            nu1--;
            n2 /= 2;
        }

        k = 0;
        int r;
        while (k < n) {
            r = bitreverseReference(k, nu);
            if (r > k) {
                tReal = xReal[k];
                tImag = xImag[k];
                xReal[k] = xReal[r];
                xImag[k] = xImag[r];
                xReal[r] = tReal;
                xImag[r] = tImag;
            }
            k++;
        }

        double[] newArray = new double[xReal.length * 2];
        double radice = 1 / Math.sqrt(n);
        for (int i = 0; i < newArray.length; i += 2) {
            int i2 = i / 2;
            newArray[i] = xReal[i2] * radice;
            newArray[i + 1] = xImag[i2] * radice;
        }

        for (int i = 0; i < newArray.length; i++) {
            System.out.println("Array: " + newArray[i]);
        }

    }

    private static int bitreverseReference(int j, int nu) {
        int j2;
        int j1 = j;
        int k = 0;
        for (int i = 1; i <= nu; i++) {
            j2 = j1 / 2;
            k = 2 * k + j1 - 2 * j2;
            j1 = j2;
        }
        return k;
    }
}

bytesOut包含您的wav文件数据(在经过Hamming window函数修改后)。 这些数据代表您应该发送给fft方法( inputReal )的real part 对于虚部,创建一个与inputReal大小相同的数组,并用零填充

//为虚部创建一个数组(假设长度为1024)

double[] imgBytesOut = new double[1024]; //imgBytesOut is not a good name for this
for(int i=0; i<1024;i++)
    imgBytesOut[i] = 0;

现在您拥有了调用fft所需的一切

fft(bytesOut, imgBytesOut);

您的fft方法会填充xRealxImg数组,但是由于您是在本地声明它们的,因此在fft完成后(将它们声明为静态全局变量),您将无法使用它们。

另外,如果您的文件包含10000个样本,而fft size为1024个样本( outBytesimgBytesOut为1024个样本),则您将不得不反复调用fft来处理整个文件。 为了获得最佳结果,您仍然需要应用overlapping (例如,对于50%的重叠和fft大小为1024的情况,您将先处理示例1-1024 ,然后处理512-1536 ,然后处理1024-2048 ,依此类推)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM