如何解决android中合并WAV格式2音频录制文件时的失真噪声问题



我有一个应用程序,可以录制WAV格式的音频。它有编辑选项,如:

  • 在开头插入
  • 末端插入
  • 插入中间
  • 超控
  • 删除直到结束

观察到,如果我们多次执行上述任何编辑操作,就会出现失真噪声

以下是WAV文件配置详细信息:

- ENCODING_PCM_16BIT
- CHANNEL_IN_MONO
- 8000(sample rate)

WAV文件头:

fileWriter.setLength(0); // Set file length to 0, to prevent unexpected behavior in case the file already existed
fileWriter.writeBytes("RIFF");
fileWriter.writeInt(0); // Final file size not known yet, write 0
fileWriter.writeBytes("WAVE"); // format
fileWriter.writeBytes("fmt "); // subchunk 1 id
fileWriter.writeInt(Integer.reverseBytes(16)); // Sub-chunk size, 16 for PCM
fileWriter.writeShort(Short.reverseBytes((short) 1)); // AudioFormat, 1 for PCM
fileWriter.writeShort(Short.reverseBytes(samplingSpec.numberOfChannels()));// Number of channels, 1 for mono, 2 for stereo
fileWriter.writeInt(Integer.reverseBytes(samplingSpec.sampleRate())); // Sample rate
fileWriter.writeInt(Integer.reverseBytes(samplingSpec.sampleRate() * samplingSpec.sampleSizeInBytes() * samplingSpec.numberOfChannels())); // Byte rate, SampleRate*NumberOfChannels*BitsPerSample/8
fileWriter.writeShort(Short.reverseBytes((short) (samplingSpec.numberOfChannels() * samplingSpec.sampleSizeInBytes()))); // Block align, NumberOfChannels*BitsPerSample/8
fileWriter.writeShort(Short.reverseBytes(samplingSpec.sampleSizeInBits())); // Bits per sample
fileWriter.writeBytes("data");
fileWriter.writeInt(0); // Data chunk size not known yet, write 0

录制完成后,我们将更新WAV文件头:

byte[] sizes = ByteBuffer
.allocate(8)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt((int) (fileWriter.length() - 8)) // ChunkSize
.putInt((int) (fileWriter.length() - 44)) // Subchunk2Size
.array();
try {
fileWriter.seek(4);
fileWriter.write(sizes, 0, 4);
// Subchunk2Size
fileWriter.seek(40);
fileWriter.write(sizes, 4, 4);
} catch (IOException ex) {
// Rethrow but we still close accessWave in our finally
throw ex;
} finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException ex) {
//
}
}
}

场景:

我正在录制音频,然后执行第一次编辑操作,在末尾插入。代码如下:

RandomAccessFile temp = null;
RandomAccessFile origin = null;
int length;
byte[] sizes = new byte[0];
isUrgent = getUrgentFl();
try {
try {
temp = new RandomAccessFile(tempFile, "rw");
origin = new RandomAccessFile(originalFile, "rw");
} catch (Exception e) {
Log.e("combineWaveFile1 : ", "combineWaveFile1_Exception" + e.getMessage());
}
byte[] buffer = new byte[1024]; // 8192
try {
try {
origin.seek(origin.length());
} catch (Exception e) {
Log.e("combineWaveFile1 : ", "combineWaveFile1_Exception" + e.getMessage());
}
try {
while ((length = temp.read(buffer)) > 0) {
origin.write(buffer, 0, length);
}
} catch (Exception e) {
Log.e("combineWaveFile2 : ", "combineWaveFile2_Exception" + e.getMessage());
}
//////////////////
try {
sizes = ByteBuffer
.allocate(8)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt((int) (origin.length() - 8)) // ChunkSize
.putInt((int) (origin.length() - 44)) // Subchunk2Size
.array();
} catch (Exception e) {
Log.e("combineWaveFile3 : ", "combineWaveFile3_Exception" + e.getMessage());
}
//noinspection CaughtExceptionImmediatelyRethrown
try {
//accessWave = new RandomAccessFile(fileWriter, "rw");
// ChunkSize
//originFile.write(0);
origin.seek(4);
origin.write(sizes, 0, 4);
// Subchunk2Size
origin.seek(40);
origin.write(sizes, 4, 4);
//originFile.write(0);
} catch (Exception e) {
Log.e("combineWaveFile4 : ", "combineWaveFile4_Exception" + e.getMessage());
} finally {
if (tempFile != null) {
try {
temp.close();
File f = new File(tempFile);
if (f.exists()) {
f.delete();
}
} catch (Exception e) {
Log.e("combineWaveFile5 : ", "combineWaveFile5_Exception" + e.getMessage());
}
}
if (origin != null) {
try {
origin.close();
} catch (Exception e) {
Log.e("combineWaveFile6 : ", "combineWaveFile6_Exception" + e.getMessage());
}
}
} 

在结束操作时完成第一次插入后,我将执行介于之间的插入操作。代码如下:

RandomAccessFile temp = null;
RandomAccessFile origin = null;
RandomAccessFile newRecordFile = null;
int length;
long seekBytesLength = 0;
byte[] sizes = new byte[0];
try {
try {
temp = new RandomAccessFile(tempFile, "rw");
origin = new RandomAccessFile(originalFile, "rw");
} catch (Exception e) {
Log.e("insertInBetween1 : ", "insertInBetween1_Exception" + e.getMessage());
}
byte[] buffer = new byte[1024];
try {
try {
long totalLength = origin.length();
long oneByteOfLength = totalLength / 100;
seekBytesLength = oneByteOfLength * Constants.seekPosition;
//long skipBytesFromLength = totalLength - seekBytesLength;
} catch (Exception e) {
Log.e("insertInBetween2 : ", "insertInBetween2_Exception" + e.getMessage());
}
if (seekBytesLength != 0) {
try {
origin.seek(seekBytesLength);
} catch (Exception e) {
Log.e("insertInBetween3 : ", "insertInBetween3_Exception" + e.getMessage());
}
try {
temp.seek(temp.length());
while ((length = origin.read(buffer)) > 0) {
temp.write(buffer, 0, length);
}
} catch (Exception e) {
Log.e("insertInBetween4 : ", "insertInBetween4_Exception" + e.getMessage());
}
} else {
try {
origin.getChannel().position(0);
temp.seek(temp.length());
while ((length = origin.read(buffer)) > 0) {
temp.write(buffer, 0, length);
}
} catch (Exception e) {
Log.e("insertInBetween5 : ", "insertInBetween5_Exception" + e.getMessage());
}
try {
File originFile = new File(originalFile);
File tmpFile = new File(tempFile);
if (originFile.delete()) {
tmpFile.renameTo(originFile);
}
} catch (Exception e) {
Log.e("insertInBetween6 : ", "insertInBetween6_Exception" + e.getMessage());
}
}
/////////////////
try {
sizes = ByteBuffer
.allocate(8)
.order(ByteOrder.LITTLE_ENDIAN)
.putInt((int) (temp.length() - 8)) // ChunkSize
.putInt((int) (temp.length() - 44)) // Subchunk2Size
.array();
} catch (Exception e) {
Log.e("insertInBetween7 : ", "insertInBetween7_Exception" + e.getMessage());
}
//no inspection CaughtException Immediately Rethrown
try {
temp.seek(4);
temp.write(sizes, 0, 4);
// Subchunk2Size
temp.seek(40);
temp.write(sizes, 4, 4);
} catch (Exception e) {
Log.e("insertInBetween8 : ", "insertInBetween8_Exception" + e.getMessage());
}
/////////////////////
try {
if (seekBytesLength != 0) {
appendFiles(origin, temp, tempFile, seekBytesLength);
}
} catch (Exception e) {
Log.e("insertInBetween9 : ", "insertInBetween9_Exception" + e.getMessage());
}
} catch (Exception e) {
Log.e("insertInBetween10 : ", "insertInBetween10_Exception" + e.getMessage());
}
finally {
if (seekBytesLength == 0) {
File tmpFile = new File(tempFile);
if (tmpFile.exists()) {
tmpFile.delete();
}
}
}
} catch (Exception e) {
Log.e("insertInBetween11 : ", "insertInBetween11_Exception" + e.getMessage());
}
**// appendFiles method :**
int length;
byte[] sizes = new byte[0];
isUrgent = getUrgentFl();
try {
byte[] buffer = new byte[1024];
//            byte[] buffer = new byte[BUFFER_SIZE];
try {
try {
originFile.seek(seekBytesLength);
} catch (Exception e) {
Log.e("appendFiles1 : ", "appendFiles1_Exception" + e.getMessage());
}
try {
while ((length = tempFile.read(buffer)) > 0) {
originFile.write(buffer, 0, length);
}
} catch (Exception e) {
Log.e("appendFiles2 : ", "appendFiles2_Exception" + e.getMessage());
}
//////////////////
try {
sizes = ByteBuffer
.allocate(8)
.order(ByteOrder.LITTLE_ENDIAN)
// There are probably a bunch of different/better ways to calculate
// these two given your circumstances. Cast should be safe since if the WAV is
// > 4 GB we've already made a terrible mistake.
.putInt((int) (originFile.length() - 8)) // ChunkSize
.putInt((int) (originFile.length() - 44)) // Subchunk2Size
.array();
} catch (Exception e) {
Log.e("appendFiles3 : ", "appendFiles3_Exception" + e.getMessage());
}
//noinspection CaughtExceptionImmediatelyRethrown
try {
originFile.seek(4);
originFile.write(sizes, 0, 4);
// Subchunk2Size
originFile.seek(40);
originFile.write(sizes, 4, 4);
//originFile.write(0);
} catch (Exception e) {
Log.e("appendFiles4 : ", "appendFiles4_Exception" + e.getMessage());
} finally {
if (originFile != null) {
try {
originFile.close();
} catch (Exception e) {
Log.e("appendFiles6 : ", "appendFiles6_Exception" + e.getMessage());
}
}
if (tempFile != null) {
try {
tempFile.close();
File f = new File(tempFileName);
if (f.exists()) {
f.delete();
}
} catch (Exception e) {
Log.e("appendFiles5 : ", "appendFiles5_Exception" + e.getMessage());
}
}
}

对于任何编辑操作,此处都会随机出现失真问题。那么,请指导我,如何处理这个问题

抱歉我英语不好。

不确定这会有多大帮助,但从音频工程师的角度来看,除非在音频的末尾和添加的部分都搜索过零点,否则在编辑点会出现失真。

虽然我不知道如何编码,但我发现这个GitHub页面可能会有所帮助。https://gist.github.com/endolith/129445

最新更新