java 代码转换音频数据格式(字节数组转换)
来源:互联网 发布:普京2018年连任知乎 编辑:程序博客网 时间:2024/05/21 11:28
目前音频格式有很多,本文针对PCM 音频文件进行转换
所谓pcm 就是将声音等模拟信号变成符号化的脉冲列,再予以记录。PCM信号是由[1]、[0]等符号构成的数字信号。与模拟信号比,它不易受传送系统的杂波及失真的影响。动态范围宽,可得到音质相当好的影响效果。PCM轨迹与视频轨迹不同,故也可用于后期录音。但在Hi8的摄像机中要实现PCM,必须通过其他的专业器材,仅靠摄像机是无法达到该效果的。
alaw 与 ulaw 都为pcm 文件编码格式
参考:
https://www.2cto.com/kf/201504/390076.html
8k8bit pcm 文件指的是采样点为8000,采用精度为8bit, bit可以理解为每个采样点大小
这种音频格式的录音为 8000*8*1(声道数)/8/1024 = 8kbs
同理8k16bit pcm,16k16bit pcm文件
下面介绍下 这些音频格式利用java代码相互转换的过程
由于网上有很多工具能够直接将完整的音频文件直接转换为相应的格式,这里就不多介绍了,
下面介绍的是如果音频文件并非完整的,而是一段二进制的数组
比如说实时的语音流转换
1 声道数的转换
8K8bit立体音 分离 成单声道(立体语音是8kAlaw)
立体音本身的采样就是左声道采样一个点,右声道采样一个记录在一起,知道这个原理,分离就很简单了。
/** * 立体音 分离 成单声道(立体语音是8kAlaw) * * @param stereoBytes * @return * @throws IOException */public static byte[][] stereo2MonoForAlaw(byte[] stereoBytes) throws IOException { byte[][] objList = new byte[2][]; try (ByteArrayOutputStream outputStreamL = new ByteArrayOutputStream()) { try (ByteArrayOutputStream outputStreamR = new ByteArrayOutputStream()) { for (int i = 0; i < stereoBytes.length; i = i + 2) { outputStreamL.write(stereoBytes[i]); outputStreamR.write(stereoBytes[i + 1]); } outputStreamL.flush(); outputStreamR.flush(); objList[0] = outputStreamL.toByteArray(); objList[1] = outputStreamR.toByteArray(); } } return objList;}
16K16bit立体音 分离 成单声道(立体语音是16k16bit)
16k16bit的录音文件,只是用两个字节16bit描述一个采样点,采样的规则和8k8bit一致
/** * 立体音 分离 成单声道(立体语音是16k16bit) * * @param stereoBytes * @return * @throws IOException */public static byte[][] stereo2MonoFor16Bit(byte[] stereoBytes) throws IOException { byte[][] objList = new byte[2][]; try (ByteArrayOutputStream outputStreamL = new ByteArrayOutputStream()) { try (ByteArrayOutputStream outputStreamR = new ByteArrayOutputStream()) { for (int i = 0; i < stereoBytes.length; i = i + 4) { outputStreamL.write(stereoBytes[i]); outputStreamL.write(stereoBytes[i + 1]); outputStreamR.write(stereoBytes[i + 2]); outputStreamR.write(stereoBytes[i + 3]); } outputStreamL.flush(); outputStreamR.flush(); objList[0] = outputStreamL.toByteArray(); objList[1] = outputStreamR.toByteArray(); } } return objList;}
单声道合成立体音(单声道为8k16bit 音频格式)
同理,将两个单声道录音按照左声道采样一个点后,右声道在采样一个排列的规则
/** * 单声道(8K16bit) 合成 立体音 * * @param left * @param right * @return byte数组 */public static byte[] line2stereo(byte[] left, byte[] right) { int length = Math.min(left.length, right.length) * 2; byte[] stereoBytes = new byte[length]; for (int i = 0, j = 0, k = 0; i < length;) { stereoBytes[i++] = left[j++]; stereoBytes[i++] = left[j++]; stereoBytes[i++] = right[k++]; stereoBytes[i++] = right[k++]; } return stereoBytes;}
2 采样点转换
8k16bit -->16k16bit
策略1:将采样点复制一份
/** * 将采用点复制,8k-->16k * @param orig * @return */ public static byte[] convert8kTo16k(byte[] orig) { byte[] dest = new byte[] {}; for (int j = 0; j < orig.length; j = j + 2) { byte[] byte2 = new byte[2]; byte2[1] = orig[j + 1]; byte2[0] = orig[j]; dest = append(dest, byte2); dest = append(dest, byte2); } return dest; }
策略2:取两个采样点中间值添加到音频数据,提升转换后效果
/** * 取两个采样点中间值添加到音频数据,增加转换后效果 * 8k16bit->16k16bit * @param orig * @return */ public static byte[] convert8000To16000(byte[] orig){ byte[] dest = new byte[]{}; for (int j = 0; j < orig.length; j = j + 2) { byte[] byte1 = new byte[2]; byte1[1] = orig[j + 1]; byte1[0] = orig[j]; dest = append(dest, byte1); if (j+2>=orig.length){ dest = append(dest,byte1); }else { short sample = toShort(byte1); byte[] byte2 = new byte[2]; byte2[0] = orig[j+2]; byte2[1] = orig[j+3]; short sample1 = toShort(byte2); short sample2 = (short) ((sample+sample1)/2); byte[] byte3= toByte(sample2); dest = append(dest, byte3); } } return dest; }
3采样精度转换
采样精度8bit 可以理解为一个byte 描述了一个采样点,而采样精度为16bit 则可以理解16bit即2个byte 描述一个采样点
8k8bit -->8k16bit
/** * 8bit ->16bit * @param orig * @return */ public static byte[] convert8bitTo16bit(byte[] orig){ byte[] dest = new byte[]{}; for (int i=0;i<orig.length;i++){ // 转无符号整数// int sample = orig[i] & 0xff;// sample = sample - 128;// int s1 = (int) (sample * 1.0 / 256 * Short.MAX_VALUE); int s1 = (orig[i]+128)<<8; byte[] byte2 = new byte[2]; byte2[1] = (byte) ((s1 << 16) >> 24); byte2[0] = (byte) ((s1 << 24) >> 24); dest = append(dest, byte2); } return dest; }
4 采样点和采样精度同时转换
/** * 拼接8k8bit byte[] 转换成16k6bit byte[] * * @param orig 原始byte[] */ public static byte[] convertTo16k16Bit(byte[] orig) { byte[] dest = new byte[] {}; for (int j = 0; j < orig.length; j++) { // 转无符号整数 int sample = orig[j] & 0xff; // 转成正负值 sample = sample - 128; // 等比缩放,转化成16bit int s1 = (int) (sample * 1.0 / 256 * Short.MAX_VALUE); byte[] byte2 = new byte[2]; byte2[1] = (byte) ((s1 << 16) >> 24); byte2[0] = (byte) ((s1 << 24) >> 24); // TODO 采样点 8k->16k,复制一个采样点,可使用其他算法实现(统计学公式,计算趋势)// dest = append(dest, byte2);// dest = append(dest, byte2); dest = append(dest, byte2); // TODO 采样点 8k->16k int sample2 = (orig[j + 2 > orig.length ? j : j + 1] & 0xff) - 128; int s2 = (int) ((sample2 * 1.0 / 256 * Short.MAX_VALUE) + s1) / 2; byte2 = new byte[2]; byte2[1] = (byte) ((s2 << 16) >> 24); byte2[0] = (byte) ((s2 << 24) >> 24); dest = append(dest, byte2); } return dest; }
java 代码将音频格式按照字节方式转换的代码到此也差不多了,下面补全上述方法中可能用到的一些其他方法
/** * short->byte * @param s * @return */public static byte[] toByte(short s){ byte[] byte2 = new byte[2]; byte2[1] = (byte) ((s << 16) >> 24); byte2[0] = (byte) ((s << 24) >> 24); return byte2;}/** * 拼接byte[] * * @param orig 原始byte[] * @param dest 需要拼接的数据 * @return byte[] */public static byte[] append(byte[] orig, byte[] dest) { byte[] newByte = new byte[orig.length + dest.length]; System.arraycopy(orig, 0, newByte, 0, orig.length); System.arraycopy(dest, 0, newByte, orig.length, dest.length); return newByte;}
阅读全文
0 0
- java 代码转换音频数据格式(字节数组转换)
- 如何转换音频数据格式1
- c++ 数据格式转换代码
- java 数据格式相互转换
- java数据格式转换
- Java中文件与字节数组转换
- java对象转换为字节数组
- Java中文件与字节数组转换
- java对象转换为字节数组
- java中二进制转换为字节数组
- java对象转换为字节数组
- Java将字节数组转换成字符串
- java中字节数组转换为字符串
- Java 对象与字节数组相互转换
- 字符串转换字节数组
- C#基础数据类型与字节数组(内存中的数据格式)相互转换(BitConverter 类)
- Java与Json数据格式转换
- 字节数组byte[]和整型,浮点型数据的转换——Java代码
- 线程优先级
- redis3.0踩坑经历
- 树结构(有id和pid字段)数组,生成多层嵌套的json对象
- java并发编程
- 3年工作经验的程序员应该具备的技能
- java 代码转换音频数据格式(字节数组转换)
- laravel框架 创建控制器
- 在屏幕上输出以下图案*
- Python的正则表达式
- 使用EM算法估计GMM参数的原理及matlab实现
- js :zoomin ,out
- ssl2295-暗黑破坏神【dp练习】
- HtmlAgilityPack使用(二)【爬取每日一文】
- 简单爬虫