【Java】字节数组 pcm 与 wav 格式互转 (附原理概述)

前言

最近实现了一个文字转语音的功能,语音引擎返回的是pcm格式的数据。需要转化成wav格式前端才能播放。本文首先会给出解决方案,后续会讲背后的原理。

  • 场景
    在这里插入图片描述
  • git 仓库
    https://github.com/ChenghanY/pcm-wav-converter

1. pcm wav 转化工具类

入参和出参都为byte[],理论上有了 byte[] 就可以输出为文件,或者用于网络交互。
输出为文件的部分可以看 【Java】pcm 与 wav 格式互转工具类 (附测试用例)
在这里插入图片描述

  • 浏览器播放的短音频,区分一下声道数、采样率即可。
  • 讯飞api文档中 audio/L16;rate=8000 表示单声道8000的采样率
package com.james;import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;public class AudioFormatConverter {/*** 采样率*/private static final Integer RATE = 8000;/*** 声道*/private static final Integer CHANNELS = 1;public static byte[] pcmToWav(byte[] pcmBytes) {return addHeader(pcmBytes, buildHeader(pcmBytes.length));}public static byte[] wavToPcm(byte[] wavBytes) {return removeHeader(changeFormatToWav(wavBytes));}private static byte[] addHeader(byte[] pcmBytes, byte[] headerBytes) {byte[] result = new byte[44 + pcmBytes.length];System.arraycopy(headerBytes, 0, result, 0, 44);System.arraycopy(pcmBytes, 0, result, 44, pcmBytes.length);return result;}private static byte[] changeFormatToWav(byte[] audioFileContent) {AudioFormat format = new AudioFormat(8_000,16,CHANNELS,true,false);try (final AudioInputStream originalAudioStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(audioFileContent));final AudioInputStream formattedAudioStream = AudioSystem.getAudioInputStream(format, originalAudioStream);final AudioInputStream lengthAddedAudioStream = new AudioInputStream(formattedAudioStream, format, audioFileContent.length);final ByteArrayOutputStream convertedOutputStream = new ByteArrayOutputStream()) {AudioSystem.write(lengthAddedAudioStream, AudioFileFormat.Type.WAVE, convertedOutputStream);return convertedOutputStream.toByteArray();} catch (UnsupportedAudioFileException | IOException e) {throw new RuntimeException(e);}}private static byte[] removeHeader(byte[] audioFileContent) {return Arrays.copyOfRange(audioFileContent, 44, audioFileContent.length);}private static byte[] buildHeader(Integer dataLength) {try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {writeChar(bos, new char[]{'R', 'I', 'F', 'F'});writeInt(bos, dataLength + (44 - 8));writeChar(bos, new char[]{'W', 'A', 'V', 'E'});writeChar(bos, new char[]{'f', 'm', 't', ' '});writeInt(bos, 16);writeShort(bos, 0x0001);writeShort(bos, CHANNELS);writeInt(bos, AudioFormatConverter.RATE);writeInt(bos, (short) (CHANNELS * 2) * RATE);writeShort(bos, (short) (CHANNELS * 2));writeShort(bos, 16);writeChar(bos, new char[]{'d', 'a', 't', 'a'});writeInt(bos, dataLength);return bos.toByteArray();} catch (IOException e) {throw new RuntimeException(e);}}private static void writeShort(ByteArrayOutputStream bos, int s) throws IOException {byte[] arr = new byte[2];arr[1] = (byte) ((s << 16) >> 24);arr[0] = (byte) ((s << 24) >> 24);bos.write(arr);}private static void writeInt(ByteArrayOutputStream bos, int n) throws IOException {byte[] buf = new byte[4];buf[3] = (byte) (n >> 24);buf[2] = (byte) ((n << 8) >> 24);buf[1] = (byte) ((n << 16) >> 24);buf[0] = (byte) ((n << 24) >> 24);bos.write(buf);}private static void writeChar(ByteArrayOutputStream bos, char[] id) {for (char c : id) {bos.write(c);}}
}

2. 原理概述

在这里插入图片描述

wav格式实际上就是在pcm数据上加了头部,让浏览器能够解析pcm数据,进而能播放音频。可以类比 TCP协议的报文头,报文头携带了数据长度、偏移量等元信息。

3. 重回代码

根据原理概述,把网上的代码重构了一下,明确语义后的形式,也就是上文的两个方法。

    public static byte[] pcmToWav(byte[] pcmBytes) {return addHeader(pcmBytes, buildHeader(pcmBytes.length));}public static byte[] wavToPcm(byte[] wavBytes) {return removeHeader(changeFormatToWav(wavBytes));}

后记

把一些测试资源放上来,后续整合到仓库中,提供完整的测试用例:

  1. 音频文件的下载地址
    https://samplelib.com/zh/sample-wav.html
    https://support.huaweicloud.com/sdkreference-sis/sis_05_0039.html

  2. pcm转mp3,播放后用于验证pcm文件的正确性
    https://www.yayapeiyin.com/pcm-to-mp3/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/363612.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人脑计算机技术与Neuroplatform:未来计算的革命性进展

引言 想象一下&#xff0c;你在某个清晨醒来&#xff0c;准备开始一天的工作&#xff0c;而实际上你的大脑正作为一台生物计算机的核心&#xff0c;处理着大量复杂的信息。这并非科幻电影的情节&#xff0c;而是人脑计算机技术即将带来的现实。本文将深入探讨FinalSpark公司的…

明明设置允许跨域,为什么还会出现跨域请求的问题

一、问题 在微服务项目中&#xff0c;明明已经设置允许跨域访问&#xff1a; 为什么还会出现跨域请求问题&#xff1f; 二、为什么 仔细查看错误提示信息&#xff1a;When allowCredentials is true, allowedOrigins cannot contain the special value "*" since t…

pytest测试框架pytest-html插件生成HTML格式测试报告

Pytest提供了丰富的插件来扩展其功能&#xff0c;pytest-html插件帮助我们生成HTML格式的测试报告&#xff0c;为我们提供直观、有效的测试结果展示。 为了使用 pytest-html&#xff0c;需要满足以下条件&#xff1a; Python 3.6 或更高版本 pytest-html安装 使用pip命令安…

【Linux】服务器被work32病毒入侵CPU占用99%

文章目录 一、问题发现二、问题解决2.1 清楚病毒2.2 开启防火墙2.3 修改SSH端口2.4 仅使用凭据登录&#xff08;可选&#xff09; 一、问题发现 我的一台海外服务器&#xff0c;一直只运行一项服务&#xff08;你懂的&#xff09;&#xff0c;但是前不久我发现CPU占用99%。没在…

【漏洞复现】宏景HCM人力资源信息管理系统——任意文件读取漏洞

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现测试工具 漏洞描述 宏景HCM人力资源信息管理系统是一款全面覆盖人力资源管理各模块…

“Hello, World!“ 历史由来

布莱恩W.克尼汉&#xff08;Brian W. Kernighan&#xff09;—— Unix 和 C 语言背后的巨人 布莱恩W.克尼汉在 1942 年出生在加拿大多伦多&#xff0c;他在普林斯顿大学取得了电气工程的博士学位&#xff0c;2000 年之后取得普林斯顿大学计算机科学的教授教职。 1973 年&#…

Java--回顾方法的定义

1.修饰符 public 公共的 修饰String类型 2.返回类型 返回的值得类型 返回值为String&#xff08;字符串&#xff09;类型 3.break continue return的区别 break&#xff0c;结束整个循环 continue&#xff0c;结束本次循环 return&#xff0c;结束整…

21、matlab生成脉冲序列:pulstran()函数

1、matlab生成脉冲序列简介 MATLAB生成脉冲序列通常涉及到使用MATLAB中的函数或编程来创建具有特定时间间隔和幅度的脉冲信号。脉冲序列通常用于数字信号处理、通信系统测试等应用中。 生成脉冲序列可以采用以下方法之一&#xff1a; 使用MATLAB中的函数&#xff0c;例如squ…

mfc140.dll怎么安装?mfc140.dll丢失安装详细解决方法

当电脑出现找不到mfc140.dll丢失问题&#xff0c;我们需要怎么办&#xff1f;怎么解决mfc140.dll丢失问题&#xff1f;mfc140.dll到底是什么&#xff1f;下面我给大家详细介绍与分析&#xff0c;最重要的是mfc140.dll的解决方法&#xff01; 一、文件丢失原因分析 在分析mfc14…

expandtabs()方法——tab符号转为空格

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 expandtabs()方法把字符串中的tab&#xff08;\t&#xff09;符号转为空格&#xff0c;tab&#xff08;\t&#xff09;符号默认的空格数是…

TS_开发一个项目

目录 一、编译一个TS文件 1.安装TypeScript 2.创建TS文件 3.编译文件 4.用Webpack打包TS ①下载依赖 ②创建文件 ③启动项目 TypeScript是微软开发的一个开源的编程语言&#xff0c;通过在JavaScript的基础上添加静态类型定义构建而成。TypeScript通过TypeScript编译器或…

Keil5中:出现:failed to execute ‘...\ARMCC\bin\ArmCC‘

点三个点&#xff0c;去自己的磁盘找自己的ARM\ARMCC\bin

HBuilder X 小白日记01

1.创建项目 2.右击项目&#xff0c;可创建html文件 3.保存CtrlS&#xff0c;运行一下 我们写的内容&#xff0c;一般是写在body里面 注释的快捷键&#xff1a;Ctrl/ h标签 <h1> 定义重要等级最高的(最大)的标题。<h6> 定义最小的标题。 H标签起侧重、强调的作用…

《数据结构与算法基础 by王卓老师》学习笔记——1.4算法与算法分析

一、算法 1.1算法的研究内容 1.2算法的定义 1.3算法的描述 以下是算法的自然语言描述 以下是算法的传统流程图表示 以下是NS流程图表示 1.4算法和程序的区别与联系 1.5算法的五个特性 1.6算法设计的要求 Robustness也称为鲁棒性 二、算法分析 2.1算法时间效率的度量 2.1.1事…

【C++课程设计——演讲比赛系统】

文章目录 前言一、演讲比赛程序需求二、每个功能模块的实现1. 创建管理类(.h文件)2.1. 创建管理类(.cpp文件)3.创建参赛选手类(.h)4.将整体逻辑进行封装 测试项目总结 前言 在学习完C的stl容器后&#xff0c;我们来写一下小项目对其进行应用&#xff01; 项目名称为&#xff1…

[渗透测试] 任意文件读取漏洞

任意文件读取漏洞 概述 漏洞成因 存在读取文件的功能&#xff08;Web应用开放了文件读取功能&#xff09;读取文件的路径客户端可控&#xff08;完全控制或者影响文件路径&#xff09;没有对文件路径进行校验或者校验不严格导致被绕过输出文件内容 漏洞危害 下载服务器中的…

入门机器视觉的正确打开方式——徒手撸一个python+opencv实现的机器视觉简易调试工具(下)

目录 1.引言2.框架思路3.图像处理流程化的实现3.1如何解析图像流程数据结构3.2 使用networkx网络图库3.3 python实现 4.结论5.python源码PS.扩展阅读ps1.六自由度机器人相关文章资源ps2.四轴机器相关文章资源ps3.移动小车相关文章资源 1.引言 在当今AI时代&#xff0c;关于视觉…

05 threeJs基础---阵列立方体和相机适配体验立方体

1.增加相机视角fov 注&#xff1a; 范围更大&#xff0c;意味着可以看到渲染范围更大&#xff0c;远小近大的视觉效果更明显 fov:眼球张开的角度&#xff0c;0时相当于闭眼。aspect:可视区域横纵比。near:眼睛能看到的最近垂直距离。far&#xff1a;眼睛能看到的最远垂直距离。…

天气网站爬虫及可视化

摘要&#xff1a;随着互联网的快速发展&#xff0c;人们对天气信息的需求也越来越高。本论文基于Python语言&#xff0c;设计并实现了一个天气网站爬虫及可视化系统。该系统通过网络爬虫技术从多个天气网站上获取实时的天气数据&#xff0c;并将数据进行清洗和存储。同时&#…

Vue2中管理$bus事件,统一移除事件

1. vue2中使用了,很多bus,在有些地方忘记清理了,导致重复事件bug. 对bus进行改造,实现清除遗留. 下面的简单实现. 1.eventbus.js // eventBus.js import Vue from vue;class EventBusClass extends Vue {constructor() {super();this.listeners [];}on(event, callback, con…