我正在尝试混合两个 WAV 文件。
WAV 文件可用作字节数组,我使用下面的代码将两者混合。
byte[] byte1 , byte[] byte2
// 44 is header of wav file
for( int i = 44 ; i < byte1.length ; i++){
byte1[i] = byte1[i] + byte2[i];
}
上面的代码大部分都有效。但是当结果超过最大波(16 位音频文件)时,它就会有噪音。如何标准化混合声音?
首先,如果你的音频确实是 16 位,那么逐字节添加它是行不通的。其他人对此发表了评论。您可以在此处查看我的回答,了解如何处理此问题。
使用 Android 的 AudioTrack 来组合声音样本的字节会产生噪音
其次,要“标准化”它,您必须先找到峰值,然后将所有结果缩放到该值。这意味着两个循环:一个是找到“峰值”,一个是添加值,缩放到新的峰值。像这样的东西:
//this is the raw audio data -- no header
short[] audioData1 , short[] audioData2
//find the max:
float max = 0;
for( int i = 0 ; i < audioData1.length ; i++) {
if( Math.abs( audioData1[i] + audioData2[i] ) > max )
max = Math.abs( audioData1[i] + audioData2[i] );
}
//now find the result, with scaling:
for( int i = 0 ; i < audioData1.length ; i++) {
audioData1[i] = Math.Round(Short.MAX_VALUE * ( audioData1[i] + audioData2[i] ) / max) ;
}
//normalized result in audioData1
short[] audioData1 = null;
short[] audioData2 = null;
int n = 0;
try {
DataInputStream in1;
in1 = new DataInputStream(new FileInputStream("v1.wav"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData1 = new short[sb.capacity()];
for (int i = 0; i < sb.capacity(); i++) {
audioData1[i] = sb.get(i);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
DataInputStream in1;
in1 = new DataInputStream(new FileInputStream("v2.wav"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
while ((n = in1.read()) != -1) {
bos.write(n);
}
} catch (IOException e) {
e.printStackTrace();
}
ByteBuffer bb = ByteBuffer.wrap(bos.toByteArray());
bb.order(ByteOrder.LITTLE_ENDIAN);
ShortBuffer sb = bb.asShortBuffer();
audioData2= new short[sb.capacity()];
sb.get(audioData2);
System.out.println();
} catch (IOException e) {
e.printStackTrace();
}
// find the max:
float max = 0;
for (int i = 22; i < audioData1.length; i++) {
if (Math.abs(audioData1[i] + audioData2[i]) > max)
max = Math.abs(audioData1[i] + audioData2[i]);
}
System.out.println("" + (Short.MAX_VALUE - max));
int a, b, c;
// now find the result, with scaling:
for (int i = 22; i < audioData1.length; i++) {
a = audioData1[i];
b = audioData2[i];
c = Math.round(Short.MAX_VALUE * (audioData1[i] + audioData2[i])
/ max);
if (c > Short.MAX_VALUE)
c = Short.MAX_VALUE;
if (c < Short.MIN_VALUE)
c = Short.MIN_VALUE;
audioData1[i] = (short) c;
}
// to turn shorts back to bytes.
byte[] end = new byte[audioData1.length * 2];
ByteBuffer.wrap(end).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(audioData1);
try {
OutputStream out = new FileOutputStream("mixer.wav");
for (int i = 0; i < end.length; i++) {
out.write(end[i]);
out.flush();
}
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这行得通,谢谢大家的回答
short[] audioData1 = null;
short[] audioData2 = null;
int n = 0;
DataInputStream in1;
try {
in1 = new DataInputStream(new FileInputStream("audio1.wav"));
audioData1 = new short[in1.available() / 2];
ShortBuffer b1 = ShortBuffer.wrap(audioData1);
try {
while (true) {
n = in1.readShort();
b1.put((short) n);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
DataInputStream in2;
try {
in2 = new DataInputStream(new FileInputStream("audio2.wav"));
audioData2 = new short[in2.available() / 2];
ShortBuffer b2 = ShortBuffer.wrap(audioData2);
try {
while (true) {
n = in2.readShort();
b2.put((short) n);
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
// find the max:
float max = 0;
for (int i = 44; i < audioData1.length; i++) {
if (Math.abs(audioData1[i] + audioData2[i]) > max)
max = Math.abs(audioData1[i] + audioData2[i]);
}
// now find the result, with scaling:
for (int i = 44; i < audioData1.length; i++) {
audioData1[i] = (short) Math.round(Short.MAX_VALUE
* (audioData1[i] + audioData2[i]) / max);
}
DataOutputStream out;
try {
out = new DataOutputStream(new FileOutputStream("mix.wav"));
for (int i = 0; i < audioData1.length; i++) {
out.writeShort(audioData1[i]);
out.flush();
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
现在简而言之,它不会工作,因为最大值是 32768(最大短)并且没有任何改变