diff --git a/riis-system/pom.xml b/riis-system/pom.xml index c3eb415..e17185b 100644 --- a/riis-system/pom.xml +++ b/riis-system/pom.xml @@ -213,7 +213,17 @@ ${project.basedir}/src/main/resources/lib/slf4j-api-1.7.25.jar - + + + com.github.wendykierp + JTransforms + 3.1 + + + com.github.axet + TarsosDSP + 2.4 + diff --git a/riis-system/src/main/java/com/yfd/platform/utils/AudioSpectrumAnalyzer.java b/riis-system/src/main/java/com/yfd/platform/utils/AudioSpectrumAnalyzer.java new file mode 100644 index 0000000..bf41468 --- /dev/null +++ b/riis-system/src/main/java/com/yfd/platform/utils/AudioSpectrumAnalyzer.java @@ -0,0 +1,175 @@ +package com.yfd.platform.utils; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jtransforms.fft.DoubleFFT_1D; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +public class AudioSpectrumAnalyzer { + + public static void main(String[] args) throws Exception { + File audioFile = new File("D:\\riis\\video\\010203040506-02-20250313094706.wav"); + AudioData audioData = readAudioData(audioFile); + SpectrumData spectrumData = calculateSpectrum(audioData); + String[] headers = {"Hz", "dB"}; + // 写入excel + writerExcel(headers, spectrumData); + + } + + // 读取音频数据 + static AudioData readAudioData(File file) throws Exception { + AudioInputStream audioStream = AudioSystem.getAudioInputStream(file); + AudioFormat format = audioStream.getFormat(); + + // 转换为PCM格式 + if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) { + AudioFormat newFormat = new AudioFormat( + AudioFormat.Encoding.PCM_SIGNED, + format.getSampleRate(), + 16, + format.getChannels(), + format.getChannels() * 2, + format.getSampleRate(), + false); + audioStream = AudioSystem.getAudioInputStream(newFormat, audioStream); + format = newFormat; + } + + // 2. 读取PCM数据 + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int bytesRead; + try { + while ((bytesRead = audioStream.read(buffer)) != -1) { + baos.write(buffer, 0, bytesRead); + } + } finally { + audioStream.close(); + } + byte[] bytes = baos.toByteArray(); + audioStream.close(); + + // 转换为double数组(处理16-bit样本) + int sampleSize = format.getSampleSizeInBits() / 8; + double[] samples = new double[bytes.length / sampleSize]; + ByteBuffer bb = ByteBuffer.wrap(bytes) + .order(format.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + + for (int i = 0; i < samples.length; i++) { + samples[i] = bb.getShort() / 32768.0; // 16-bit PCM归一化 + } + + return new AudioData(samples, format.getSampleRate()); + } + + // 计算频谱 + static SpectrumData calculateSpectrum(AudioData audioData) { + double[] samples = audioData.samples; + double sampleRate = audioData.sampleRate; + int n = samples.length; + + // 应用汉明窗 + applyHammingWindow(samples); + + // 执行FFT + DoubleFFT_1D fft = new DoubleFFT_1D(n); + double[] fftData = new double[n * 2]; + System.arraycopy(samples, 0, fftData, 0, n); + fft.realForwardFull(fftData); + + // 计算幅度和分贝 + List frequencies = new ArrayList<>(); + List amplitudesDb = new ArrayList<>(); + double maxAmplitude = 0; + + for (int k = 0; k < n / 2; k++) { + double real = fftData[2 * k]; + double imag = fftData[2 * k + 1]; + double magnitude = Math.sqrt(real * real + imag * imag); + // 归一化分贝值 + double db = 20 * Math.log10(magnitude / n); + + double frequency = k * sampleRate / n; + frequencies.add(frequency); + amplitudesDb.add(db); + } + + // 转换为数组 + SpectrumData result = new SpectrumData(); + result.frequencies = frequencies.stream().mapToDouble(d -> d).toArray(); + result.amplitudesDb = amplitudesDb.stream().mapToDouble(d -> d).toArray(); + + return result; + } + + public static void writerExcel(String[] headers, SpectrumData spectrumData) { + // 创建Excel工作簿 + try (Workbook workbook = new XSSFWorkbook()) { + Sheet sheet = workbook.createSheet("数据表"); + + // 写入标题行 + Row headerRow = sheet.createRow(0); + for (int i = 0; i < headers.length; i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers[i]); + } + // 写入数据行 + for (int i = 0; i < spectrumData.frequencies.length; i++) { + Row row = sheet.createRow(i + 1); + Cell cell = row.createCell(0); + cell.setCellValue(spectrumData.frequencies[i]); + Cell cell1 = row.createCell(1); + cell1.setCellValue(spectrumData.amplitudesDb[i]); + } + + // 保存到文件 + try (FileOutputStream outputStream = new FileOutputStream("D:\\output.xlsx")) { + workbook.write(outputStream); + System.out.println("Excel文件已保存!"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + // 应用汉明窗 + static void applyHammingWindow(double[] data) { + int n = data.length; + for (int i = 0; i < n; i++) { + data[i] *= 0.54 - 0.46 * Math.cos(2 * Math.PI * i / (n - 1)); + } + } + + // 数据载体类 + static class AudioData { + + double[] samples; + double sampleRate; + + AudioData(double[] samples, double sampleRate) { + this.samples = samples; + this.sampleRate = sampleRate; + } + } + + static class SpectrumData { + + double[] frequencies; + double[] amplitudesDb; + } +}