Java 程序为音频文件创建 PNG 波形

2023-12-31

如何使用 Java 将 Wav 文件转换为 PNG 波形图像文件?

java MyProgram.class [path to wav file] [path where to write png file]

预期成绩:

指定路径中保存的png是传入的wav文件的波形。


下面是一个可以做这件事的 java 类。我在这里对某些参数进行硬编码,例如图像宽度、图像高度、图像背景颜色等等。如果你想把它们拉出来,你可以。

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Vector;

import javax.imageio.ImageIO;
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 AudioWaveformCreator {
    AudioInputStream audioInputStream;
    Vector<Line2D.Double> lines = new Vector<Line2D.Double>();
    String errStr;
    Capture capture = new Capture();
    double duration, seconds;
    File file;
    String fileName;
    SamplingGraph samplingGraph;
    String waveformFilename;
    Color imageBackgroundColor = new Color(20,20,20);

    public AudioWaveformCreator(String fileName, String waveformFilename) throws UnsupportedAudioFileException, IOException {
        file = new File(fileName);
        this.waveformFilename = waveformFilename;
    }

    public void createAudioInputStream() throws Exception {
        if (file != null && file.isFile()) {
            try {
                errStr = null;
                audioInputStream = AudioSystem.getAudioInputStream(file);
                fileName = file.getName();
                long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / audioInputStream.getFormat().getFrameRate());
                duration = milliseconds / 1000.0;
                samplingGraph = new SamplingGraph();
                samplingGraph.createWaveForm(null);                
            } catch (Exception ex) { 
                reportStatus(ex.toString());
                throw ex;
            }
        } else {
            reportStatus("Audio file required.");
        }
    }
    /**
     * Render a WaveForm.
     */
    class SamplingGraph implements Runnable {

        private Thread thread;
        private Font font10 = new Font("serif", Font.PLAIN, 10);
        private Font font12 = new Font("serif", Font.PLAIN, 12);
        Color jfcBlue = new Color(000, 000, 255);
        Color pink = new Color(255, 175, 175);


        public SamplingGraph() {
        }


        public void createWaveForm(byte[] audioBytes) {

            lines.removeAllElements();  // clear the old vector

            AudioFormat format = audioInputStream.getFormat();
            if (audioBytes == null) {
                try {
                    audioBytes = new byte[
                        (int) (audioInputStream.getFrameLength() 
                        * format.getFrameSize())];
                    audioInputStream.read(audioBytes);
                } catch (Exception ex) { 
                    reportStatus(ex.getMessage());
                    return; 
                }
            }
            int w = 500;
            int h = 200;
            int[] audioData = null;
            if (format.getSampleSizeInBits() == 16) {
                 int nlengthInSamples = audioBytes.length / 2;
                 audioData = new int[nlengthInSamples];
                 if (format.isBigEndian()) {
                    for (int i = 0; i < nlengthInSamples; i++) {
                         /* First byte is MSB (high order) */
                         int MSB = (int) audioBytes[2*i];
                         /* Second byte is LSB (low order) */
                         int LSB = (int) audioBytes[2*i+1];
                         audioData[i] = MSB << 8 | (255 & LSB);
                     }
                 } else {
                     for (int i = 0; i < nlengthInSamples; i++) {
                         /* First byte is LSB (low order) */
                         int LSB = (int) audioBytes[2*i];
                         /* Second byte is MSB (high order) */
                         int MSB = (int) audioBytes[2*i+1];
                         audioData[i] = MSB << 8 | (255 & LSB);
                     }
                 }
             } else if (format.getSampleSizeInBits() == 8) {
                 int nlengthInSamples = audioBytes.length;
                 audioData = new int[nlengthInSamples];
                 if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
                     for (int i = 0; i < audioBytes.length; i++) {
                         audioData[i] = audioBytes[i];
                     }
                 } else {
                     for (int i = 0; i < audioBytes.length; i++) {
                         audioData[i] = audioBytes[i] - 128;
                     }
                 }
            }

            int frames_per_pixel = audioBytes.length / format.getFrameSize()/w;
            byte my_byte = 0;
            double y_last = 0;
            int numChannels = format.getChannels();
            for (double x = 0; x < w && audioData != null; x++) {
                int idx = (int) (frames_per_pixel * numChannels * x);
                if (format.getSampleSizeInBits() == 8) {
                     my_byte = (byte) audioData[idx];
                } else {
                     my_byte = (byte) (128 * audioData[idx] / 32768 );
                }
                double y_new = (double) (h * (128 - my_byte) / 256);
                lines.add(new Line2D.Double(x, y_last, x, y_new));
                y_last = y_new;
            }
            saveToFile(waveformFilename);
        }


        public void saveToFile(String filename) {            
            int w = 500;
            int h = 200;
            int INFOPAD = 15;

            BufferedImage bufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2 = bufferedImage.createGraphics();

            createSampleOnGraphicsContext(w, h, INFOPAD, g2);            
            g2.dispose();
            // Write generated image to a file
            try {
                // Save as PNG
                File file = new File(filename);
                ImageIO.write(bufferedImage, "png", file);
            } catch (IOException e) {
            }
        }


        private void createSampleOnGraphicsContext(int w, int h, int INFOPAD, Graphics2D g2) {            
            g2.setBackground(imageBackgroundColor);
            g2.clearRect(0, 0, w, h);
            g2.setColor(Color.white);
            g2.fillRect(0, h-INFOPAD, w, INFOPAD);

            if (errStr != null) {
                g2.setColor(jfcBlue);
                g2.setFont(new Font("serif", Font.BOLD, 18));
                g2.drawString("ERROR", 5, 20);
                AttributedString as = new AttributedString(errStr);
                as.addAttribute(TextAttribute.FONT, font12, 0, errStr.length());
                AttributedCharacterIterator aci = as.getIterator();
                FontRenderContext frc = g2.getFontRenderContext();
                LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
                float x = 5, y = 25;
                lbm.setPosition(0);
                while (lbm.getPosition() < errStr.length()) {
                    TextLayout tl = lbm.nextLayout(w-x-5);
                    if (!tl.isLeftToRight()) {
                        x = w - tl.getAdvance();
                    }
                    tl.draw(g2, x, y += tl.getAscent());
                    y += tl.getDescent() + tl.getLeading();
                }
            } else if (capture.thread != null) {
                g2.setColor(Color.black);
                g2.setFont(font12);
                //g2.drawString("Length: " + String.valueOf(seconds), 3, h-4);
            } else {
                g2.setColor(Color.black);
                g2.setFont(font12);
                //g2.drawString("File: " + fileName + "  Length: " + String.valueOf(duration) + "  Position: " + String.valueOf(seconds), 3, h-4);

                if (audioInputStream != null) {
                    // .. render sampling graph ..
                    g2.setColor(jfcBlue);
                    for (int i = 1; i < lines.size(); i++) {
                        g2.draw((Line2D) lines.get(i));
                    }

                    // .. draw current position ..
                    if (seconds != 0) {
                        double loc = seconds/duration*w;
                        g2.setColor(pink);
                        g2.setStroke(new BasicStroke(3));
                        g2.draw(new Line2D.Double(loc, 0, loc, h-INFOPAD-2));
                    }
                }
            }
        }

        public void start() {
            thread = new Thread(this);
            thread.setName("SamplingGraph");
            thread.start();
            seconds = 0;
        }

        public void stop() {
            if (thread != null) {
                thread.interrupt();
            }
            thread = null;
        }

        public void run() {
            seconds = 0;
            while (thread != null) {
                if ( (capture.line != null) && (capture.line.isActive()) ) {
                    long milliseconds = (long)(capture.line.getMicrosecondPosition() / 1000);
                    seconds =  milliseconds / 1000.0;
                }
                try { thread.sleep(100); } catch (Exception e) { break; }                              
                while ((capture.line != null && !capture.line.isActive())) 
                {
                    try { thread.sleep(10); } catch (Exception e) { break; }
                }
            }
            seconds = 0;
        }
    } // End class SamplingGraph

    /** 
     * Reads data from the input channel and writes to the output stream
     */
    class Capture implements Runnable {

        TargetDataLine line;
        Thread thread;

        public void start() {
            errStr = null;
            thread = new Thread(this);
            thread.setName("Capture");
            thread.start();
        }

        public void stop() {
            thread = null;
        }

        private void shutDown(String message) {
            if ((errStr = message) != null && thread != null) {
                thread = null;
                samplingGraph.stop();                
                System.err.println(errStr);
            }
        }

        public void run() {

            duration = 0;
            audioInputStream = null;

            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

            AudioFormat format = audioInputStream.getFormat();
            DataLine.Info info = new DataLine.Info(TargetDataLine.class, 
                format);

            if (!AudioSystem.isLineSupported(info)) {
                shutDown("Line matching " + info + " not supported.");
                return;
            }

            // get and open the target data line for capture.

            try {
                line = (TargetDataLine) AudioSystem.getLine(info);
                line.open(format, line.getBufferSize());
            } catch (LineUnavailableException ex) { 
                shutDown("Unable to open the line: " + ex);
                return;
            } catch (SecurityException ex) { 
                shutDown(ex.toString());
                JavaSound.showInfoDialog();
                return;
            } catch (Exception ex) { 
                shutDown(ex.toString());
                return;
            }

            // play back the captured audio data
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int frameSizeInBytes = format.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead;

            line.start();

            while (thread != null) {
                if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
                    break;
                }
                out.write(data, 0, numBytesRead);
            }

            // we reached the end of the stream.  stop and close the line.
            line.stop();
            line.close();
            line = null;

            // stop and close the output stream
            try {
                out.flush();
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }

            // load bytes into the audio input stream for playback

            byte audioBytes[] = out.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
            audioInputStream = new AudioInputStream(bais, format, audioBytes.length / frameSizeInBytes);

            long milliseconds = (long)((audioInputStream.getFrameLength() * 1000) / format.getFrameRate());
            duration = milliseconds / 1000.0;

            try {
                audioInputStream.reset();
            } catch (Exception ex) { 
                ex.printStackTrace(); 
                return;
            }

            samplingGraph.createWaveForm(audioBytes);
        }
    } // End class Capture    

    public static void main(String [] args) throws Exception {
        if (args.length != 2) {
            printUsage();
            System.exit(1);
        }                
        AudioWaveformCreator awc = new AudioWaveformCreator(args[0], args[1]);
        awc.createAudioInputStream();
    }

    private void reportStatus(String msg) {
        if ((errStr = msg) != null) {
            System.out.println(errStr);            
        }
    }

    private static void printUsage() {
        System.out.println("AudioWaveformCreator usage: java AudioWaveformCreator.class [path to audio file for generating the image] [path to save waveform image to]");
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 程序为音频文件创建 PNG 波形 的相关文章

  • 使用 mongoose 通过 React 应用程序将图像上传到 mongodb 数据库

    我正在为找到的对象创建一个反应应用程序 我想允许用户上传这些对象的照片 我尝试使用 axios 通过 post 请求将图像发送到猫鼬服务器 但它不起作用 这就是我如何将图像存储在带有预览的 React 组件中 handleImage eve
  • 在Windows上安装Java 11 OpenJDK(系统路径问题)

    Java 11 最近发布了 众所周知 这个版本没有安装文件 当然 要在没有安装程序的情况下安装 Java 我将系统设置 PATH 和 JAVA HOME 设置为解压缩 Java 11 的文件夹的地址 根据对类似问题的已接受回复建议 唯一的事
  • 在浏览器中点击应用程序时播放框架挂起

    我正在 Play 中运行一个应用程序activator run 也许 5 次中有 3 次 它会挂起 当我去http localhost 9000 它就永远坐在那里旋转 我看到很多promise timed out错误也 我应该去哪里寻找这个
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 如何为 Gson 编写自定义 JSON 反序列化器?

    我有一个 Java 类 用户 public class User int id String name Timestamp updateDate 我收到一个包含来自 Web 服务的用户对象的 JSON 列表 id 1 name Jonas
  • hibernate总是自己删除表中的所有数据

    您好 我正在开发一个 spring mvc 应用程序 它使用 hibernate 连接到存储文件的 mysql 数据库 我有两个方法 一个方法添加我选择的特定文件路径中的所有文件 另一种方法调用查询以返回从 mysql 存储的文件列表 问题
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 请求位置更新参数

    这就是 requestLocationUpdates 的样子 我使用它的方式 requestLocationUpdates String provider long minTime float minDistance LocationLis
  • 从 android 简单上传到 S3

    我在网上搜索了从 android 上传简单文件到 s3 的方法 但找不到任何有效的方法 我认为这是因为缺乏具体步骤 1 https mobile awsblog com post Tx1V588RKX5XPQB TransferManage
  • 制作java包

    我的 Java 类组织变得有点混乱 所以我要回顾一下我在 Java 学习中跳过的东西 类路径 我无法安静地将心爱的类编译到我为它们创建的包中 这是我的文件夹层次结构 com david Greet java greeter SayHello
  • Java直接内存:在自定义类中使用sun.misc.Cleaner

    在 Java 中 NIO 直接缓冲区分配的内存通过以下方式释放 sun misc Cleaner实例 一些比对象终结更有效的特殊幻像引用 这种清洁器机制是否仅针对直接缓冲区子类硬编码在 JVM 中 或者是否也可以在自定义组件中使用清洁器 例
  • 将多模块 Maven 项目导入 Eclipse 时出现问题 (STS 2.5.2)

    我刚刚花了最后一个小时查看 Stackoverflow com 上的线程 尝试将 Maven 项目导入到 Spring ToolSuite 2 5 2 中 Maven 项目有多个模块 当我使用 STS 中的 Import 向导导入项目时 所
  • Java中未绑定通配符泛型的用途和要点是什么?

    我不明白未绑定通配符泛型有什么用 具有上限的绑定通配符泛型 stuff for Object item stuff System out println item Since PrintStream println 可以处理所有引用类型 通
  • 使用 Flyway 和 Hibernate 的 hbm2ddl 在应用程序的生命周期中管理数据库模式

    我正在开发 Spring Hibernate MySql 应用程序 该应用程序尚未投入生产 我目前使用 Hibernatehbm2ddl该功能对于管理域上的更改非常方便 我也打算用Flyway用于数据库迁移 在未来的某个时候 该应用程序将首
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • 当单元格内的 JComboBox 中有 ItemEvent 时,如何获取 CellRow

    我有一个 JTable 其中有一列包含 JComboBox 我有一个附加到 JComboBox 的 ItemListener 它会根据任何更改进行操作 但是 ItemListener 没有获取更改的 ComboBox 所在行的方法 当组合框
  • 运行 Jar 文件时出现问题

    我已将 java 项目编译成 Jar 文件 但运行它时遇到问题 当我跑步时 java jar myJar jar 我收到以下错误 Could not find the main class myClass 类文件不在 jar 的根目录中 因
  • Keycloak - 自定义 SPI 未出现在列表中

    我为我的 keycloak 服务器制作了一个自定义 SPI 现在我必须在管理控制台上配置它 我将 SPI 添加为模块 并手动安装 因此我将其放在 module package name main 中 并包含 module xml 我还将其放
  • 如何配置eclipse以保持这种代码格式?

    以下代码来自 playframework 2 0 的示例 Display the dashboard public static Result index return ok dashboard render Project findInv
  • JAVA - 如何从扫描仪读取文件中检测到“\n”字符

    第一次海报 我在读取文本文件的扫描仪中读取返回字符时遇到问题 正在读取的文本文件如下所示 test txt start 2 0 30 30 1 1 90 30 0 test txt end 第一行 2 表示两个点 第二行 位置索引 0 xp

随机推荐

  • Android:深度睡眠的时间间隔(System.nanoTime()、System.currentTimeMillis()、SystemClock.elapsedRealtimeNanos())

    我正在实现一个应用程序 其 API 级别最低为 14 这很重要 并且需要一致的间隔测量 不需要毫秒精度 它只需要始终计算时间 经过的秒数 到目前为止 为了处理时间间隔 我知道这些解决方案 System nanoTime 如果 Android
  • 为什么 Ruby on Rails 在每次点击时(有时)都会创建新的会话?

    由于某种原因 我的 RoR 应用程序中的会话处理程序对于许多用户来说在生产中似乎表现得很奇怪 我正在使用默认的 RoR ActiveRecord 会话存储 并且在开发过程中一切正常 只要我保持浏览器打开 每次修改会话时都会更新一个现有数据行
  • 对 SLF4J 日志消息进行单元测试的最佳方法是什么?

    我正在使用 slf4j 我想对我的代码进行单元测试 以确保在某些条件下生成警告 错误日志消息 我宁愿这些是严格的单元测试 所以我不希望必须从文件中提取日志配置来测试是否生成日志消息 我使用的模拟框架是 Mockito 创建测试规则 impo
  • 有效的访问参数

    如何查找有效的访问参数 我查看了 menu router 但我相信这只给出了其中的一些 items admin page array access arguments gt array access administration pages
  • HMT collection_singular_ids=直接删除连接模型,不触发销毁回调

    刚刚遇到了 has many through 关联的问题 并且未触发 after before destroy 回调 假设我有用户 组和称为成员资格的中间关系 我有一个表单 允许用户在选中关联的复选框时通过创建新的成员记录来注册到组中 基本
  • 如何使用构建名称设置器插件?

    有谁知道是否有关于如何使用 jenkins 的构建名称设置器插件的用户手册 jenkins 插件网站似乎只有一个下载插件的链接 没有关于如何使用它的信息 https wiki jenkins ci org display JENKINS B
  • Jquery JQGrid - 如何设置网格标题单元格的对齐方式?

    jqgrid 中是否可以对齐网格列标题 例如左对齐或居中对齐 在 jqrid 文档中http www trirand com jqgridwiki doku php id wiki colmodel options http www tri
  • 是否可以在 sed 地址中进行简单的算术运算?

    是否可以在 sed 地址中进行简单的算术运算 判断通过 地址 手册部分 http www gnu org software sed manual sed html Addresses 答案似乎不是 但也许有一个解决方法 例如 如何打印文件的
  • 如何在给定范围内插入 1000 个随机日期?

    我是 SQL Server 新手 我需要生成从给定日期范围中选择的随机日期 就像雇员的受雇日期应该介于2011 01 01 and 2011 12 31 生成的日期应随机插入到 1000 行表中 任何人都可以指导我解答我的疑问吗 decla
  • Spring 集成和重试:我是否需要为每个服务激活器使用单独的重试 bean?

    我有一个 spring 集成管道 并且有许多不同的服务激活器 我想启用重试 我想使用相同的重试策略 即重试次数 退避策略等 我可以只使用一个实现重试策略的 bean 并将其用于多个不同的服务激活器 还是每个服务激活器都需要自己的重试 bea
  • 使用 sketch.js 为移动网页绘制画布会重置 ontouch

    我正在使用sketch js用于在 HTML5 画布上绘图的插件 虽然它在台式电脑上运行良好 但在移动浏览器上似乎存在一些问题 问题是如果我画两个不同的形状 一旦我触摸画布 它就会重置为空白 为了完全清楚 我会做并且example 绘制数字
  • 具有 ClipboardData 属性的 Angular2 组件

    我有一个 Angular2 组件 它具有从剪贴板粘贴数据的方法 inputPaste event let clipboardData event clipboardData 这种方式不适用于 IE10 但 IE 有一个带有属性 Clipbo
  • Firebase - 用户对事物的评论[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在构建一个 Android 应用程序 允许用户对广告牌前 100 名上的每首歌曲发表评论 我从 JSON 文件中解析了该信息 我将
  • 可以“跳过”行的数组公式

    我需要在谷歌电子表格中引入功能 该功能将允许用户编辑数组公式的结果 提出此要求的原因是 ARRAYFORMULA 为一组单元格设置默认值 但用户有时需要覆盖这些默认值 我想知道这是否有可能 example Row Array 1 Array
  • 算法:从一组游戏中选择成对的球队

    我正在尝试为体育联盟创建一个调度程序 我想将球队分组 以便每个球队每组进行一场比赛 我认为我正在尝试做的事情是计算机科学中现有的问题 但我不知道它叫什么 而且我很难找到有关它的信息 不管怎样 情况如下 假设我有一组团队A 1 2 3 n 以
  • 您在编写单元测试时最常犯的错误是什么? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 您在编写单元测试时最常犯的错误是什么 耦合 缺乏凝聚力 尝试一次测试太多功能 没有测试足够的功能 如果您有该错误的示例 请发布一些示例代码 根本
  • 如何防止用户代理显示无法识别的 MIME 类型的下载窗口?

    如果您设置Content Disposition标头至attachment 这会导致用户代理始终显示该文件的下载窗口 我想做与此相反的事情 强制用户代理始终直接显示响应 在这种特殊情况下 我有一个发送 JSON 的 API 我想把它作为ap
  • Flexbox 项目多行文本溢出

    我有一个弹性物品 里面有很长的绳子 我想把它包裹起来 但这不起作用 I set flex 1 1 500px 例如 flex basis 500px 并且它应该用以下内容包裹字符串word wrap break word 但事实并非如此 而
  • Kinesis 流待处理消息计数

    我正在尝试将 AWS Kinesis 流用于我们的数据流之一 我想出于操作目的监视流上的待处理消息 根据积压向下游扩展 但无法找到任何在我的流中提供 大约 待处理消息的 API 这看起来很奇怪 因为消息在 7 天后就会过期 如果生产者和消费
  • Java 程序为音频文件创建 PNG 波形

    如何使用 Java 将 Wav 文件转换为 PNG 波形图像文件 java MyProgram class path to wav file path where to write png file 预期成绩 指定路径中保存的png是传入的