我一直在尝试向我的应用程序添加一些代码,以将我记录的pcm文件转换为.wav文件。 我有编写标题的代码,但出于某种原因,当我通过音频播放器播放转换后的.wav文件时,您只能听到噪音。
这是我转换方法的代码:
public void writeWavHeader(){
try {
File pcmFile = new File(Environment.getExternalStorageDirectory() + File.separator + "TimeShiftRecorder" + File.separator + "Recording.pcm");
File wavFile = new File(Environment.getExternalStorageDirectory() + File.separator + "TimeShiftRecorder" + File.separator + "Recording_test.wav");
OutputStream os = new FileOutputStream(wavFile);
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream out = new DataOutputStream(bos);
FileInputStream fis = new FileInputStream(pcmFile);
InputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
short mBitsPerSample = 16;
long audioLength = fis.getChannel().size();
long byteRate = sampleRate * bitsPerSample/8 * channels;
short format = 1;
long totalDataLen = audioLength + 36;
long longSampleRate = 44100;
byte byteBitsPerSample = (byte) bitsPerSample; // = 16
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (bitsPerSample/8*channels); // block align
header[33] = 0;
header[34] = byteBitsPerSample; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (audioLength & 0xff);
header[41] = (byte) ((audioLength >> 8) & 0xff);
header[42] = (byte) ((audioLength >> 16) & 0xff);
header[43] = (byte) ((audioLength >> 24) & 0xff);
out.write(header, 0, 44);
while (dis.available() > 0) {
out.write(dis.read());
}
dis.close();
out.close();
//testHeader();
}catch(IOException e){
Log.v("recordService", "IOException");
}
}
从我在网上找到的所有例子中,这个标题应该是正确的。
如果有人能帮助我解决我出错的地方,我将非常感激。
由于 科里:)
答案 0 :(得分:0)
通常,WAV格式存储每个样本16位信息(跨两个字节的内存)。确保您阅读PCM并写入WAV并考虑到这一点。单个字节每个样本只能处理256个不同的值(通常每秒采集44100次),这将使8位格式的低保真度。相反,使用16位存储,您可以获得2 ^ 16个可能的不同值,这足以支持CD质量的音频。编写这样的代码时,它有两个程序:(1)将PCM转换为WAV,另一个(2)将WAV转换回PCM。通过这种方式,您可以使用(2)将已知良好的WAV读入PCM作为源数据,然后使用(1)输出WAV,然后比较两个WAV的相等性。
还要确保您读取/写入二进制文件而不是正常文件模式。
在您的情况下,由于WAV格式只是PCM数据,并且标题附加到文件的前面,如果您将PCM读取为二进制文件,请将标头输出到新的WAV文件,然后将内存缓冲区写为二进制文件对于WAV,你应该顺利去。
答案 1 :(得分:0)
这是一个完整的工作示例。
有关更多信息,请参见:http://soundfile.sapp.org/doc/WaveFormat/
/**
* overload using AudioFormat
*
* @param input raw PCM data
* limit of file size for wave file: < 2^(2*4) - 36 bytes (~4GB)
* @param output file to encode to in wav format
* @param format corresponding audioformat for PCM data
* @throws IOException in event of an error between input/output files
* @see <a href="http://soundfile.sapp.org/doc/WaveFormat/">soundfile.sapp.org/doc/WaveFormat</a>
*/
static public void PCMToWAV(File input, File output, AudioFormat format) throws IOException {
int bitsPerSample;
switch (format.getEncoding()) {
case AudioFormat.ENCODING_PCM_8BIT:
bitsPerSample = 8;
break;
case AudioFormat.ENCODING_PCM_FLOAT:
bitsPerSample = 32;
break;
case AudioFormat.ENCODING_PCM_16BIT:
default:
bitsPerSample = 16;
}
PCMToWAV(input, output, format.getChannelCount(), format.getSampleRate(), bitsPerSample);
}
/**
* @param input raw PCM data
* limit of file size for wave file: < 2^(2*4) - 36 bytes (~4GB)
* @param output file to encode to in wav format
* @param channelCount number of channels: 1 for mono, 2 for stereo, etc.
* @param sampleRate sample rate of PCM audio
* @param bitsPerSample bits per sample, i.e. 16 for PCM16
* @throws IOException in event of an error between input/output files
* @see <a href="http://soundfile.sapp.org/doc/WaveFormat/">soundfile.sapp.org/doc/WaveFormat</a>
*/
static public void PCMToWAV(File input, File output, int channelCount, int sampleRate, int bitsPerSample) throws IOException {
final int inputSize = (int) input.length();
try (OutputStream encoded = new FileOutputStream(output)) {
// WAVE RIFF header
writeToOutput(encoded, "RIFF"); // chunk id
writeToOutput(encoded, 36 + inputSize); // chunk size
writeToOutput(encoded, "WAVE"); // format
// SUB CHUNK 1 (FORMAT)
writeToOutput(encoded, "fmt "); // subchunk 1 id
writeToOutput(encoded, 16); // subchunk 1 size
writeToOutput(encoded, (short) 1); // audio format (1 = PCM)
writeToOutput(encoded, (short) channelCount); // number of channelCount
writeToOutput(encoded, sampleRate); // sample rate
writeToOutput(encoded, sampleRate * channelCount * bitsPerSample / 8); // byte rate
writeToOutput(encoded, (short) (channelCount * bitsPerSample / 8)); // block align
writeToOutput(encoded, (short) bitsPerSample); // bits per sample
// SUB CHUNK 2 (AUDIO DATA)
writeToOutput(encoded, "data"); // subchunk 2 id
writeToOutput(encoded, inputSize); // subchunk 2 size
copy(new FileInputStream(input), encoded);
}
}
/**
* Size of buffer used for transfer, by default
*/
private static final int TRANSFER_BUFFER_SIZE = 10 * 1024;
/**
* Writes string in big endian form to an output stream
*
* @param output stream
* @param data string
* @throws IOException
*/
public static void writeToOutput(OutputStream output, String data) throws IOException {
for (int i = 0; i < data.length(); i++)
output.write(data.charAt(i));
}
public static void writeToOutput(OutputStream output, int data) throws IOException {
output.write(data >> 0);
output.write(data >> 8);
output.write(data >> 16);
output.write(data >> 24);
}
public static void writeToOutput(OutputStream output, short data) throws IOException {
output.write(data >> 0);
output.write(data >> 8);
}
public static long copy(InputStream source, OutputStream output)
throws IOException {
return copy(source, output, TRANSFER_BUFFER_SIZE);
}
public static long copy(InputStream source, OutputStream output, int bufferSize) throws IOException {
long read = 0L;
byte[] buffer = new byte[bufferSize];
for (int n; (n = source.read(buffer)) != -1; read += n) {
output.write(buffer, 0, n);
}
return read;
}