想写一个将双声道的 wav 转成 单声道的 wav,生成的却是噪音,不知哪里错了。

幽饮烛 2011-11-12 01:28:04

package test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Test1
{
public static void main(String[] args) throws Exception
{
File file = new File("T:\\temp\\tada.wav").getAbsoluteFile();
System.out.println(file.getName());
BufferedInputStream input = new BufferedInputStream(new FileInputStream(file));
RIFFHeader riff = new RIFFHeader(input);
System.out.println(riff.getID());
System.out.println(riff.getSize());
System.out.println(riff.getFormat());
WAVEHeader wave = new WAVEHeader(input);
System.out.println(wave.getID());
System.out.println(wave.getSize());
System.out.println(wave.getFormatTag());
System.out.println(wave.getChannels());
System.out.println(wave.getSamplesPerSec());
System.out.println(wave.getAvgBytesPerSec());
System.out.println(wave.getBlockAlign());
System.out.println(wave.getBitsPerSample());
System.out.println(wave.getOther());
DataHeader data = new DataHeader(input);
System.out.println(data.getID());
System.out.println(data.getSize());
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(new File(file.getParentFile(), file.getName() + ".out")));
writeString(output, riff.getID());
writeInteger(output, 4, data.getSize() / wave.getChannels() + 8 + wave.getSize() + 8 + 4);
writeString(output, riff.getFormat());
writeString(output, wave.getID());
writeInteger(output, 4, wave.getSize());
writeInteger(output, 2, wave.getFormatTag());
writeInteger(output, 2, 1);
writeInteger(output, 4, wave.getSamplesPerSec());
writeInteger(output, 4, wave.getAvgBytesPerSec() / wave.getChannels());
writeInteger(output, 2, wave.getBlockAlign() / wave.getChannels());
writeInteger(output, 2, wave.getBitsPerSample());
if (wave.getSize() != 16)
{
writeString(output, wave.getOther());
}
writeString(output, data.getID());
writeInteger(output, 4, data.getSize() / wave.getChannels());
int byteCount = wave.getBitsPerSample() / 8;
int frameCount = data.getSize() / wave.getChannels() / byteCount;
int[] frames = new int[wave.getChannels()];
int frame;
for (int i = 0; i < frameCount; i++)
{
for (int f = 0; f < frames.length; f++)
{
frame = 0;
for (int d = 0; d < byteCount; d++)
{
frame += input.read() << (d * 8);
}
frames[f] = frame;
}
frame = 0;
for (int f : frames)
{
frame += f;
}
frame /= frames.length;
writeInteger(output, byteCount, frame);
}
input.close();
output.close();
}

private static void writeInteger(final OutputStream stream, final int size, final int value) throws IOException
{
for (int i = 0; i < size; i++)
{
stream.write((value >>> (i * 8)) & 0xFF);
}
}

public static void writeString(final OutputStream stream, final String string) throws IOException
{
char[] chars = string.toCharArray();
for (char c : chars)
{
stream.write(c);
}
}

public static class DataHeader
{
private final String id;
private final int size;

public String getID()
{
return id;
}

public int getSize()
{
return size;
}

public DataHeader(final InputStream stream) throws Exception
{
byte[] buffer = new byte[4];
stream.read(buffer);
char[] chars = new char[buffer.length];
for (int i = 0; i < chars.length; i++)
{
chars[i] = (char) buffer[i];
}
id = new String(chars);
size = (stream.read() & 255) + ((stream.read() & 255) << 8) + ((stream.read() & 255) << 16) + ((stream.read() & 255) << 24);
}
}

public static class WAVEHeader
{
private final String id;
private final int size;
private final int formatTag;
private final int channels;
private final int samplesPerSec;
private final int avgBytesPerSec;
private final int blockAlign;
private final int bitsPerSample;
private final String other;

public int getBlockAlign()
{
return blockAlign;
}

public int getBitsPerSample()
{
return bitsPerSample;
}

public String getOther()
{
return other;
}

public int getSize()
{
return size;
}

public int getFormatTag()
{
return formatTag;
}

public int getChannels()
{
return channels;
}

public int getSamplesPerSec()
{
return samplesPerSec;
}

public int getAvgBytesPerSec()
{
return avgBytesPerSec;
}

public String getID()
{
return id;
}

public WAVEHeader(final InputStream stream) throws Exception
{
byte[] buffer = new byte[4];
stream.read(buffer);
char[] chars = new char[buffer.length];
for (int i = 0; i < chars.length; i++)
{
chars[i] = (char) buffer[i];
}
id = new String(chars);
size = (stream.read() & 255) + ((stream.read() & 255) << 8) + ((stream.read() & 255) << 16) + ((stream.read() & 255) << 24);
formatTag = (stream.read() & 255) + ((stream.read() & 255) << 8);
channels = (stream.read() & 255) + ((stream.read() & 255) << 8);
samplesPerSec = (stream.read() & 255) + ((stream.read() & 255) << 8) + ((stream.read() & 255) << 16) + ((stream.read() & 255) << 24);
avgBytesPerSec = (stream.read() & 255) + ((stream.read() & 255) << 8) + ((stream.read() & 255) << 16) + ((stream.read() & 255) << 24);
blockAlign = (stream.read() & 255) + ((stream.read() & 255) << 8);
bitsPerSample = (stream.read() & 255) + ((stream.read() & 255) << 8);
if (size == 16)
{
other = "";
}
else
{
buffer = new byte[size - 16];
stream.read(buffer);
chars = new char[buffer.length];
for (int i = 0; i < chars.length; i++)
{
chars[i] = (char) buffer[i];
}
other = new String(chars);
}
}
}

public static class RIFFHeader
{
private final String id;
private final int size;
private final String format;

public String getID()
{
return id;
}

public int getSize()
{
return size;
}

public String getFormat()
{
return format;
}

public RIFFHeader(final InputStream stream) throws Exception
{
byte[] buffer = new byte[4];
stream.read(buffer);
char[] chars = new char[buffer.length];
for (int i = 0; i < chars.length; i++)
{
chars[i] = (char) buffer[i];
}
id = new String(chars);
size = (stream.read() & 255) + ((stream.read() & 255) << 8) + ((stream.read() & 255) << 16) + ((stream.read() & 255) << 24);
stream.read(buffer);
for (int i = 0; i < chars.length; i++)
{
chars[i] = (char) buffer[i];
}
format = new String(chars);
}
}
}
...全文
822 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
gaosunqiong 2014-04-07
  • 打赏
  • 举报
回复
大侠,你是怎样将立体声PCM数据转换为单声道立体声的?说一下原理咯?
zhangbole725 2014-02-28
  • 打赏
  • 举报
回复
很好很好~~~~~~~~~~~
Richelprince 2012-03-18
  • 打赏
  • 举报
回复
大侠!!能不能给出这些代码的注释呢?谢谢了!感激不尽!!!
Richelprince 2012-03-17
  • 打赏
  • 举报
回复
这个要好好学!
幽饮烛 2011-11-14
  • 打赏
  • 举报
回复

int frame;
for (int i = 0; i < frameCount; i++)
{
for (int f = 0; f < frames.length; f++)
{
frame = 0;
for (int d = 0; d < byteCount; d++)
{
frame += input.read() << (d * 8);
}
frames[f] = frame;
}
frame = 0;
for (int f : frames)
{
frame += f;
}
frame /= frames.length;
writeInteger(output, byteCount, frame);
}

改为

int frame;
byte[] bytes = new byte[byteCount];
for (int i = 0; i < frameCount; i++)
{
for (int f = 0; f < frames.length; f++)
{
input.read(bytes);
frame = bytes[0] & 255;
for (int b = 1; b < bytes.length; b++)
{
frame += bytes[b] << (b * 8);
}
frames[f] = frame;
}
frame = 0;
for (int f : frames)
{
frame += f;
}
frame /= frames.length;
writeInteger(output, byteCount, frame);
}

就可以了,
大概已经知道原因了,还得去学位操作才行啊。
lfp001 2011-11-12
  • 打赏
  • 举报
回复
路过,你算是问着了。说说WAV文件中PCM数据的存储格式吧。

16位PCM,每一个样本2字节。立体声的PCM数据左右声道交替存储,用L表示左声道的一个PCM样本,R表示右声道的一个PCM样本,PCM数据在WAV文件中的存放序列是这样的:LRLRLRLR……

16位PCM样本用2字节表示一个值域为-32768至32767的一个样本,这2字节表示的16位整数可能是大头在上,也可能是小头在上。

将这段代码:
int frameCount = data.getSize() / wave.getChannels() / byteCount;
int[] frames = new int[wave.getChannels()];
int frame;
for (int i = 0; i < frameCount; i++)
{
for (int f = 0; f < frames.length; f++)
{
frame = 0;
for (int d = 0; d < byteCount; d++)
{
frame += input.read() << (d * 8);
}
frames[f] = frame;
}
frame = 0;
for (int f : frames)
{
frame += f;
}
frame /= frames.length;
writeInteger(output, byteCount, frame);
}


改为:
int frameCount = data.getSize() / wave.getChannels() / byteCount;
int frame;
byte[] b = new byte[wave.getBitsPerSample() / 4];
for (int i = 0; i < frameCount; i++)
{
input.read(b); //读入4字节
frame = (((b[1] << 8) | (b[0] & 0xff))
+ (b[3] << 8) | (b[2] & 0xff)) >> 1;
writeInteger(output, byteCount, frame);
}


就可以将立体声的WAV文件中的PCM改为16位的单声道的PCM了。我没有测试,应该没得错吧。

kouyiSC 2011-11-12
  • 打赏
  • 举报
回复
哎。以前接触呼叫中心的时候,,wav语音文件都是通过工具转换的。。。没有去注意。。。只能帮你顶了。。。。
jiakai0419 2011-11-12
  • 打赏
  • 举报
回复
帮你顶一下帖子。
我也没接触过。
Michaelbest1 2011-11-12
  • 打赏
  • 举报
回复
还没接触过用Java处理音频的。学习

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧