我一直在尝试在Android上合并两个WAVE文件,但实际上似乎无法使其正常工作。
一切看起来不错,读取文件并将其写入输出文件,该文件在以后也可以读取,并且具有我期望看到的文件大小。
该问题在应用程序完成合并后立即发生。该消息将显示在日志中:在updateListener中发生错误,记录被终止,这是 extAudioRecorder
发出的消息,并在OnRecordPositionUpdateListener
到达catch子句时出现(该异常具有以下详细信息:写失败:EBADF(错误的文件号))。这似乎没有破坏任何东西,因此我对此不太担心。
当我尝试创建 MediaPlayer
并在MediaPlayer实例上调用 setDataSource(String path)
时,就会出现真正的问题。每当我对合并的文件执行此操作时,日志中都会显示以下错误消息:无法创建媒体播放器(抛出的IOException
包含以下detailMessage: setDataSourceFD失败。:status = 0x80000000 )。请注意,该文件第一次可以完美播放(此第一个文件不是combineWaveFiles()
方法创建的)。该错误消息似乎表明音频文件的格式不正确和/或MediaPlayer无法读取。
我的问题是,是否有人看到下面的代码有任何实际问题(我知道它在许多方面都不是最优的,但我更喜欢先使其工作然后再考虑性能)。
public static String MergeRecordings(String cumulativeFile, String recordFile, int sampleRate, int bpp, int bufferSize, int channels) {
if (cumulativeFile == null) {
return recordFile;
} else if (recordFile == null) {
return cumulativeFile;
}
String outputFile = FileUtils.getFilePath(null, MDSettings.shared().getMainActivity());
FileUtils.combineWaveFiles(cumulativeFile, recordFile, outputFile, sampleRate, bpp, bufferSize, channels);
//FileUtils.removeFile(cumulativeFile);
//FileUtils.removeFile(recordFile);
return outputFile;
}
//creates a new file containing file1 + file2 stuck together as such.
private static void combineWaveFiles(String file1, String file2, String outputFile, int sampleRate, int bpp, int bufferSize, int channels) {
FileInputStream in1 = null, in2 = null;
FileOutputStream out = null;
long longSampleRate = sampleRate;
long byteRate = sampleRate * channels * bpp / 8;
byte[] data;
try {
try {
in1 = new FileInputStream(file1);
} catch (Exception e) { }
try {
in2 = new FileInputStream(file2);
} catch (FileNotFoundException e) { }
out = new FileOutputStream(outputFile);
long file1Size = 0;
long file2Size = 0;
if (in1 != null) { file1Size = in1.getChannel().size() - 44; }
if (in2 != null) { file2Size = in2.getChannel().size() - 44; }
long totalAudioLen = file1Size + file2Size;
long totalDataLen = totalAudioLen + 36;
FileUtils.writeWaveFileHeader(out, totalAudioLen, totalDataLen, longSampleRate, channels, byteRate, bpp);
if (in1 != null) {
in1.skip(44);
data = new byte[bufferSize];
if (file1Size < bufferSize) {
data = new byte[(int)file1Size];
}
while (in1.read(data) != -1) {
out.write(data);
file1Size -= bufferSize;
if (file1Size <= 0) {
break;
} else if (file1Size < bufferSize) {
data = new byte[(int)file1Size];
}
}
}
if (in2 != null) {
in2.skip(44);
data = new byte[bufferSize];
if (file2Size < bufferSize) {
data = new byte[(int)file2Size];
}
while (in2.read(data) != -1) {
out.write(data);
file2Size -= bufferSize;
if (file2Size <= 0) {
break;
} else if (file2Size < bufferSize) {
data = new byte[(int)file2Size];
}
}
}
out.close();
if (in1 != null) { in1.close(); }
if (in2 != null) { in2.close(); }
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeWaveFileHeader(FileOutputStream out, long totalAudioLen, long totalDataLen, long longSampleRate, int channels, long byteRate, int bpp)
throws IOException {
byte[] header = new byte[44];
header[0] = 'R';
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';
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16;
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 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)(channels * bpp); //(2 * 16 / 8);
header[33] = 0;
header[34] = (byte)bpp;
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte)(totalAudioLen & 0xff);
header[41] = (byte)((totalAudioLen >> 8) & 0xff);
header[42] = (byte)((totalAudioLen >> 16) & 0xff);
header[43] = (byte)((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
该代码的大部分来自this answer。
参考方案
我正是在我的Android应用程序中执行此操作。而不是两个,我根据用户选择合并多个文件。我使用AsyncTask在后台合并示例。在这里看看。只需过滤所需的部分。如果您对我的应用程序Sound Recorder + Pro感到好奇,除了合并,我还会混合,添加回显和放大样本:
@Override
protected Void doInBackground(Void... params) {
isProcessingOn=true;
try {
DataOutputStream amplifyOutputStream = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/" + year +"-"+ month +"-"+ date +"-"+ hour+"-" + min +"-"+ sec+"ME.wav")));
DataInputStream[] mergeFilesStream = new DataInputStream[selection.size()];
long[] sizes=new long[selection.size()];
for(int i=0; i<selection.size(); i++) {
File file = new File(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/" +selection.get(i));
sizes[i] = (file.length()-44)/2;
}
for(int i =0; i<selection.size(); i++) {
mergeFilesStream[i] =new DataInputStream(new BufferedInputStream(new FileInputStream(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/" +selection.get(i))));
if(i == selection.size()-1) {
mergeFilesStream[i].skip(24);
byte[] sampleRt = new byte[4];
mergeFilesStream[i].read(sampleRt);
ByteBuffer bbInt = ByteBuffer.wrap(sampleRt).order(ByteOrder.LITTLE_ENDIAN);
RECORDER_SAMPLERATE = bbInt.getInt();
mergeFilesStream[i].skip(16);
}
else {
mergeFilesStream[i].skip(44);
}
}
for(int b=0; b<selection.size(); b++) {
for(int i=0; i<(int)sizes[b]; i++) {
byte[] dataBytes = new byte[2];
try {
dataBytes[0] = mergeFilesStream[b].readByte();
dataBytes[1] = mergeFilesStream[b].readByte();
}
catch (EOFException e) {
amplifyOutputStream.close();
}
short dataInShort = ByteBuffer.wrap(dataBytes).order(ByteOrder.LITTLE_ENDIAN).getShort();
float dataInFloat= (float) dataInShort/37268.0f;
short outputSample = (short)(dataInFloat * 37268.0f);
byte[] dataFin = new byte[2];
dataFin[0] = (byte) (outputSample & 0xff);
dataFin[1] = (byte)((outputSample >> 8) & 0xff);
amplifyOutputStream.write(dataFin, 0 , 2);
}
}
amplifyOutputStream.close();
for(int i=0; i<selection.size(); i++) {
mergeFilesStream[i].close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
long size =0;
try {
FileInputStream fileSize = new FileInputStream(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/"+year +"-"+ month +"-"+ date +"-"+ hour+"-" + min +"-"+ sec+"ME.wav");
size = fileSize.getChannel().size();
fileSize.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final int RECORDER_BPP = 16;
long datasize=size+36;
long byteRate = (RECORDER_BPP * RECORDER_SAMPLERATE)/8;
long longSampleRate = RECORDER_SAMPLERATE;
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (datasize & 0xff);
header[5] = (byte) ((datasize >> 8) & 0xff);
header[6] = (byte) ((datasize >> 16) & 0xff);
header[7] = (byte) ((datasize >> 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) 1;
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) ((RECORDER_BPP) / 8); // block align
header[33] = 0;
header[34] = RECORDER_BPP; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (size & 0xff);
header[41] = (byte) ((size >> 8) & 0xff);
header[42] = (byte) ((size >> 16) & 0xff);
header[43] = (byte) ((size >> 24) & 0xff);
// out.write(header, 0, 44);
try {
RandomAccessFile rFile = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/Soundrecpluspro/" +year +"-"+ month +"-"+ date +"-"+ hour+"-" + min +"-"+ sec+ "ME.wav", "rw");
rFile.seek(0);
rFile.write(header);
rFile.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Java-如何将此字符串转换为日期? - java我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM…
JAVA:字节码和二进制有什么区别? - javajava字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…
在Java中用'\\'替换单个'\' - java如何用'\'替换单个'\\'?当我运行replaceAll()时,我收到此错误消息。Exception in thread "main" java.util.regex.PatternSyntaxException: Unexpected internal error near index 1 \ …
错误:任务':app:lintVitalRelease'的执行失败,任何人都可以解决吗? - java为什么我收到此错误,我尝试清理和重建应用程序并制作应用程序发布为真,并且出现相同的错误 错误:任务':app:lintVitalRelease'的执行失败。 java.lang.IllegalStateException:预期为BEGIN_ARRAY,但位于第1行第1列路径$ apply plugin: 'com.android.applicati…
为什么`if(guess!='a'|| guess!='A'||…)`不起作用? - javaImprove this question 这是我的代码,我知道if语句真的很长,代码可能会更高效,但是我只是想知道答案,因为它使我发疯。while (whileloop == 1) { if (guess != 'a' || guess != 'A' || guess != 'b' || gues…