当前位置: 首页 > 知识库问答 >
问题:

将FFT应用于java中的音频录制

余弘毅
2023-03-14

我在这个网站上看到过类似的问题,但我的问题有点不同。我用来捕获音频的代码是这样的。我想简单地获取捕获的音频,并对其应用256点的FFT。

我意识到这个行数= 行读(缓冲区,0,缓冲区长度); 将音频分解为“块”。

我使用的FFT也可以在这里找到。

我的问题是:

  1. 我想知道是否有一种方法可以将FFT应用于整个音频记录,而不仅仅是缓冲量。
  2. 我看到FFT的代码需要实部和虚部,如何从带有音频文件的代码中获取实部和虚部。

共有1个答案

易自珍
2023-03-14

javax.sound.采样包所做的就是从文件中读取原始字节并将其写入输出。因此,您必须执行一个“介于两者之间”的步骤,即自己转换样本。

下面显示了如何为PCM这样做(带有注释),摘自我的代码示例WaveformDemo:

public static float[] unpack(
    byte[] bytes,
    long[] transfer,
    float[] samples,
    int bvalid,
    AudioFormat fmt
) {
    if(fmt.getEncoding() != AudioFormat.Encoding.PCM_SIGNED
            && fmt.getEncoding() != AudioFormat.Encoding.PCM_UNSIGNED) {

        return samples;
    }

    final int bitsPerSample = fmt.getSampleSizeInBits();
    final int bytesPerSample = bitsPerSample / 8;
    final int normalBytes = normalBytesFromBits(bitsPerSample);

    /*
     * not the most DRY way to do this but it's a bit more efficient.
     * otherwise there would either have to be 4 separate methods for
     * each combination of endianness/signedness or do it all in one
     * loop and check the format for each sample.
     * 
     * a helper array (transfer) allows the logic to be split up
     * but without being too repetetive.
     * 
     * here there are two loops converting bytes to raw long samples.
     * integral primitives in Java get sign extended when they are
     * promoted to a larger type so the & 0xffL mask keeps them intact.
     * 
     */

    if(fmt.isBigEndian()) {
        for(int i = 0, k = 0, b; i < bvalid; i += normalBytes, k++) {
            transfer[k] = 0L;

            int least = i + normalBytes - 1;
            for(b = 0; b < normalBytes; b++) {
                transfer[k] |= (bytes[least - b] & 0xffL) << (8 * b);
            }
        }
    } else {
        for(int i = 0, k = 0, b; i < bvalid; i += normalBytes, k++) {
            transfer[k] = 0L;

            for(b = 0; b < normalBytes; b++) {
                transfer[k] |= (bytes[i + b] & 0xffL) << (8 * b);
            }
        }
    }

    final long fullScale = (long)Math.pow(2.0, bitsPerSample - 1);

    /*
     * the OR is not quite enough to convert,
     * the signage needs to be corrected.
     * 
     */

    if(fmt.getEncoding() == AudioFormat.Encoding.PCM_SIGNED) {

        /*
         * if the samples were signed, they must be
         * extended to the 64-bit long.
         * 
         * so first check if the sign bit was set
         * and if so, extend it.
         * 
         * as an example, imagining these were 4-bit samples originally
         * and the destination is 8-bit, a mask can be constructed
         * with -1 (all bits 1) and a left shift:
         * 
         *     11111111
         *  <<  (4 - 1)
         *  ===========
         *     11111000
         * 
         * (except the destination is 64-bit and the original
         * bit depth from the file could be anything.)
         * 
         * then supposing we have a hypothetical sample -5
         * that ought to be negative, an AND can be used to check it:
         * 
         *    00001011
         *  & 11111000
         *  ==========
         *    00001000
         * 
         * and an OR can be used to extend it:
         * 
         *    00001011
         *  | 11111000
         *  ==========
         *    11111011
         * 
         */

        final long signMask = -1L << bitsPerSample - 1L;

        for(int i = 0; i < transfer.length; i++) {
            if((transfer[i] & signMask) != 0L) {
                transfer[i] |= signMask;
            }
        }
    } else {

        /*
         * unsigned samples are easier since they
         * will be read correctly in to the long.
         * 
         * so just sign them:
         * subtract 2^(bits - 1) so the center is 0.
         * 
         */

        for(int i = 0; i < transfer.length; i++) {
            transfer[i] -= fullScale;
        }
    }

    /* finally normalize to range of -1.0f to 1.0f */

    for(int i = 0; i < transfer.length; i++) {
        samples[i] = (float)transfer[i] / (float)fullScale;
    }

    return samples;
}

public static int normalBytesFromBits(int bitsPerSample) {

    /*
     * some formats allow for bit depths in non-multiples of 8.
     * they will, however, typically pad so the samples are stored
     * that way. AIFF is one of these formats.
     * 
     * so the expression:
     * 
     *  bitsPerSample + 7 >> 3
     * 
     * computes a division of 8 rounding up (for positive numbers).
     * 
     * this is basically equivalent to:
     * 
     *  (int)Math.ceil(bitsPerSample / 8.0)
     * 
     */

    return bitsPerSample + 7 >> 3;
}

这段代码假定< code>float[],而您的FFT需要< code>double[],但这是一个相当简单的更改。< code>transfer和< code>samples是长度等于< code > bytes . length * normal bytes 的数组,而< code>bvalid是< code>read的返回值。我的代码示例假设AudioInputStream,但是相同的转换应该适用于TargetDataLine。我不确定你能复制粘贴它,但这是一个例子。

关于你的两个问题:

  1. 您可以对整个记录进行很长的FFT,也可以对每个缓冲区的FFT求平均值。
  2. 您链接到的 FFT 计算已就地。因此,真实部分是音频样本,虚部是长度等于真实部分的空数组(填充零)。

但是当FFT完成时,仍然有一些事情需要做,我看不到链接类在做:

    < li >转换为极坐标。 < li >通常丢弃负频率(频谱的整个上半部分,它是下半部分的镜像)。 < li >通过将结果幅度(实数部分)除以变换的长度,可以对其进行缩放。

编辑,相关:

  • 如何使用Java声音的音频采样数据
 类似资料:
  • 问题内容: 我目前正在尝试使用Android实现一些代码,以检测何时通过手机的麦克风播放了多个特定音频频率范围。我已经使用AudioRecord该类设置了该类: 然后读取音频: 执行FFT是我遇到的困难,因为我在这方面的经验很少。我一直在尝试使用此类: Java和Complex类中的FFT一起使用 然后,我发送以下值: 这很容易让我误解了此类的工作原理,但是返回的值到处都是跳跃的,即使在沉默中也不

  • 问题内容: 我正在尝试建立一个程序来录制一部分互联网音频流,并将其保存到文件(最好是mp3或wav)。我到处都看过,找不到任何合适的方法来做到这一点。我找到了两个似乎可以工作的不同库(NativeBass和Xuggle),但我都不支持64位Windows。 有谁知道使用Java保存一部分互联网音频流的任何简单方法?(如果重要,则为“音频/ mpeg”流)。 编辑:好的,我发现了一种可行的方法。但是

  • 问题内容: 之前,我问过有关使用FFT和Complex class获取频率wav音频的 问题, 在那里,我需要从AudioRecord输入->从麦克风计算FFT值,以某种方式设法获得FFT值… 现在,我需要从之前保存的* .wav音频文件中计算FFT值,然后将音频保存到项目中“ res”文件夹中的“ raw”文件夹中 我仍然使用相同的FFT类:http : //www.cs.princeton.e

  • 问题内容: 我将如何使用Python从WAV PCM文件中读取频率峰值,然后能够生成图像以进行频谱分析? 我正在尝试制作一个程序,使您可以读取任何音频文件,将其转换为WAV PCM,然后查找峰值和频率截止值。 问题答案: Python的wave库将允许您导入音频。之后,您可以使用numpy对音频进行FFT。 然后,matplotlib可以制作出非常漂亮的图表和图形- 绝对可与MATLAB相媲美。

  • 我试图为管道开发一个应用程序: gst-launch-1.0 rtspsrc位置=”rtsp://192.168.3.30:8554/rajvi“延迟=0 name=demux demux。!queue!rtpmp4gdepay!aacparse!avdec\u aac!audioconvert!audioresample!autoaudiosink demux。!queue!rtph264dep

  • 问题内容: 谁能推荐可靠的开源软件来在wav文件中记录英语语音?我研究过的两个主要程序是Sphinx和Julius,但是我从来都无法使用它们,并且每个转录文件的文档充其量都是粗略的。 我正在开发64位Ubuntu 10.04,其存储库包括sphinx2和julius,以及voxforge的英语julius声学模态。我专注于转录文件,而不是直接处理麦克风的声音,因为我已经放弃了期望像这样的项目可以与