Java實現(xiàn)多個wav文件合成一個的方法示例
本文實例講述了Java實現(xiàn)多個wav文件合成一個的方法。分享給大家供大家參考,具體如下:
前面一篇介紹了java切割wav音頻文件的方法,這里再給出合并多個wav音頻文件的方法。
package com.cmos.nomsapp.utils.wavmeger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
/**
* 獲取wav頭文件然后合并成單個wav
* @author zcf
* @date 2017-10-17
*/
public class WavMergeUtil {
/**
* meger多個wav
* @param inputs 多個wav
* @param output 要生成的wav
* @throws IOException
*/
public static void mergeWav(File[] inputs, String output) throws IOException {
if (inputs.length < 1) {
return;
}
try(FileInputStream fis = new FileInputStream(inputs[0]);
FileOutputStream fos = new FileOutputStream(new File(output))){
byte[] buffer = new byte[1024 * 4];
int total = 0;
int count;
while ((count = fis.read(buffer)) > -1) {
fos.write(buffer, 0, count);
total += count;
}
fis.close();
for (int i = 1; i < inputs.length; i++) {
File file = inputs[i];
try(FileInputStream fisH = new FileInputStream(file)){
Header header = resolveHeader(fisH);
FileInputStream dataInputStream = header.dataInputStream;
while ((count = dataInputStream.read(buffer)) > -1) {
fos.write(buffer, 0, count);
total += count;
}
}
}
fos.flush();
fos.close();
FileInputStream fisHo = new FileInputStream(new File(output));
Header outputHeader = resolveHeader(fisHo);
outputHeader.dataInputStream.close();
try(RandomAccessFile res = new RandomAccessFile(output, "rw")){
res.seek(4);
byte[] fileLen = intToByteArray(total + outputHeader.dataOffset - 8);
res.write(fileLen, 0, 4);
res.seek(outputHeader.dataSizeOffset);
byte[] dataLen = intToByteArray(total);
res.write(dataLen, 0, 4);
}
}
}
/**
* 解析頭部,并獲得文件指針指向數(shù)據(jù)開始位置的InputStreram,記得使用后需要關(guān)閉
*/
private static Header resolveHeader(FileInputStream fis) throws IOException {
byte[] byte4 = new byte[4];
byte[] buffer = new byte[2048];
int readCount = 0;
Header header = new Header();
fis.read(byte4);// RIFF
fis.read(byte4);
readCount += 8;
header.fileSizeOffset = 4;
header.fileSize = byteArrayToInt(byte4);
fis.read(byte4);// WAVE
fis.read(byte4);// fmt
fis.read(byte4);
readCount += 12;
int fmtLen = byteArrayToInt(byte4);
fis.read(buffer, 0, fmtLen);
readCount += fmtLen;
fis.read(byte4);// data or fact
readCount += 4;
if (isFmt(byte4, 0)) {// 包含fmt段
fis.read(byte4);
int factLen = byteArrayToInt(byte4);
fis.read(buffer, 0, factLen);
fis.read(byte4);// data
readCount += 8 + factLen;
}
fis.read(byte4);// data size
int dataLen = byteArrayToInt(byte4);
header.dataSize = dataLen;
header.dataSizeOffset = readCount;
readCount += 4;
header.dataOffset = readCount;
header.dataInputStream = fis;
return header;
}
private static boolean isRiff(byte[] bytes, int start) {
if (bytes[start + 0] == 'R' && bytes[start + 1] == 'I' && bytes[start + 2] == 'F' && bytes[start + 3] == 'F') {
return true;
} else {
return false;
}
}
private static boolean isFmt(byte[] bytes, int start) {
if (bytes[start + 0] == 'f' && bytes[start + 1] == 'm' && bytes[start + 2] == 't' && bytes[start + 3] == ' ') {
return true;
} else {
return false;
}
}
private static boolean isData(byte[] bytes, int start) {
if (bytes[start + 0] == 'd' && bytes[start + 1] == 'a' && bytes[start + 2] == 't' && bytes[start + 3] == 'a') {
return true;
} else {
return false;
}
}
/**
* 將int轉(zhuǎn)化為byte[]
*/
private static byte[] intToByteArray(int data) {
return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data).array();
}
/**
* 將short轉(zhuǎn)化為byte[]
*/
private static byte[] shortToByteArray(short data) {
return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort(data).array();
}
/**
* 將byte[]轉(zhuǎn)化為short
*/
private static short byteArrayToShort(byte[] b) {
return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getShort();
}
/**
* 將byte[]轉(zhuǎn)化為int
*/
private static int byteArrayToInt(byte[] b) {
return ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
/**
* 頭部部分信息
*/
static class Header {
public int fileSize;
public int fileSizeOffset;
public int dataSize;
public int dataSizeOffset;
public int dataOffset;
public FileInputStream dataInputStream;
}
}
更多關(guān)于java算法相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java文件與目錄操作技巧匯總》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點技巧總結(jié)》和《Java緩存操作技巧匯總》
希望本文所述對大家java程序設(shè)計有所幫助。
相關(guān)文章
SpringSecurity+Mysql數(shù)據(jù)庫實現(xiàn)用戶安全登錄認證的實踐
Spring Security 是一個提供身份認證、授權(quán)和防范常見攻擊的安全權(quán)限框架,本文主要介紹了SpringSecurity+Mysql數(shù)據(jù)庫實現(xiàn)用戶安全登錄認證的實踐,具有一定的參考價值,感興趣的可以了解一下2024-08-08
mybatis中一對一關(guān)系association標簽的使用
這篇文章主要介紹了mybatis中一對一關(guān)系association標簽的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
淺談Java實現(xiàn)面向?qū)ο缶幊蘪ava oop
這篇文章主要介紹了淺談Java實現(xiàn)面向?qū)ο缶幊蘪ava oop,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
SpringBoot重啟后,第一次請求接口請求慢的問題及解決
這篇文章主要介紹了SpringBoot重啟后,第一次請求接口請求慢的問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
Spring Boot Mysql 數(shù)據(jù)庫操作示例
本篇文章主要介紹了Spring Boot Mysql 數(shù)據(jù)庫操作示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
springboot應(yīng)用中靜態(tài)資源訪問與接口請求沖突問題解決
這篇文章主要介紹了springboot應(yīng)用中靜態(tài)資源訪問與接口請求沖突,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-06-06
JDBC如何訪問MySQL數(shù)據(jù)庫,并增刪查改
這篇文章主要介紹了JDBC如何訪問MySQL數(shù)據(jù)庫,幫助大家更好的理解和學(xué)習(xí)java與MySQL,感興趣的朋友可以了解下2020-08-08
Java數(shù)據(jù)結(jié)構(gòu)之二叉排序樹的實現(xiàn)
二叉排序樹(Binary Sort Tree),又稱二叉查找樹(Binary Search Tree),亦稱二叉搜索樹。本文詳細介紹了二叉排序樹的原理,并且提供了Java代碼的完全實現(xiàn)。需要的可以參考一下2022-01-01

