0
public TargetDataLine targetDataLine;
private static AudioFormat getAudioFormat() 
{
        return new AudioFormat(16000, 16, 2, true, false);
}
AudioFormat a = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, a);
targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
targetDataLine.open(a);
targetDataLine.start();
AudioInputStream ais = new AudioInputStream(targetDataLine); 
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("record.wav"));
  1. 如何同时计算音频的分贝?
  2. 如何计算现有 wav 文件的分贝?
4

1 回答 1

3

假设一:您想在记录结束时处理和保存数据。

  • 使用TargetDataLine.read()将数据读入临时短缓冲区
  • ByteArrayOutputStream使用ByteArrayOutputStream.write()将数据写入
  • 转换ByteArrayOutputStreambyte[]数组。
  • 将字节数据编码为样本
  • 计算 RMS、Peak 等并将它们转换为分贝。
  • ByteArrayInputStream使用您的byte[]数组构建
  • 使用制作您的音频文件AudioSystem.write()

    int numBytesRead = 0;
    byte[] buffer = new byte[1024]; 
    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    boolean stopRecording = false;
    
    while (!stopRecording) {
        numBytesRead =  targetDataLine.read(buffer, 0, buffer.length);
        //short[] samples = encodeToSample(buffer, buffer.length);
        // process samples - calculate decibels
    
        if (numBytesRead > 0) {
            outStream.write(buffer, 0, numBytesRead);
        }
    }
    
    outStream.close();
    
    byte[] data = outStream.toByteArray();
    ByteArrayInputStream bais = new ByteArrayInputStream(data);
    AudioInputStream ais = new AudioInputStream(bais, a, data.length);
    
    AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("record.wav"));
    

假设二:您希望连续读取、处理和保存数据。

您需要一个中间类才能转换ByteArrayOutputStreamByteArrayInputStream. 在后台线程捕获音频数据,并在另一个线程处理并在您所需的数据量可用时保存数据。

编码:您可以对byte[]阵列中的音频样本进行编码。在您的情况下,两个连续的字节产生一个样本。您将一个接一个地获得两个通道的样本。如果您有任何特定于通道的处理,那么您需要为每个通道分离样本。以下代码片段可以帮助您进行编码 -

public static short[] encodeToSample(byte[] srcBuffer, int numBytes) {
    byte[] tempBuffer = new byte[2];
    int nSamples = numBytes / 2;        
    short[] samples = new short[nSamples];  // 16-bit signed value

    for (int i = 0; i < nSamples; i++) {
        tempBuffer[0] = srcBuffer[2 * i];
        tempBuffer[1] = srcBuffer[2 * i + 1];
        samples[i] = bytesToShort(tempBuffer);
    }

    return samples;
}

public static short bytesToShort(byte [] buffer) {
    ByteBuffer bb = ByteBuffer.allocate(2);
    bb.order(ByteOrder.BIG_ENDIAN);
    bb.put(buffer[0]);
    bb.put(buffer[1]);
    return bb.getShort(0);
}

分贝: Db 是给定电平与参考电平的对数比。例如,如果您想以 dBFS 为单位计算 RMS/Peak,以下代码片段可能会对您有所帮助。

public static void calculatePeakAndRms(short [] samples) {
    double sumOfSampleSq = 0.0;    // sum of square of normalized samples.
    double peakSample = 0.0;     // peak sample.

    for (short sample : samples) {
        double normSample = (double) sample / 32767;  // normalized the sample with maximum value.
        sumOfSampleSq += (normSample * normSample);
        if (Math.abs(sample) > peakSample) {
            peakSample = Math.abs(sample);
        }
    }

    double rms = 10*Math.log10(sumOfSampleSq / samples.length);
    double peak = 20*Math.log10(peakSample / 32767);
}
于 2018-03-06T21:18:07.250 回答