我一直在研究RingDroid源,试图弄清楚如何在Android设备上绘制波形。但是,我陷入了关于在CheapWAV.java阅读WAV文件的部分。
public void ReadFile(File inputFile)
throws java.io.FileNotFoundException,
java.io.IOException {
super.ReadFile(inputFile);
mFileSize = (int)mInputFile.length();
if (mFileSize < 128) {
throw new java.io.IOException("File too small to parse");
}
FileInputStream stream = new FileInputStream(mInputFile);
byte[] header = new byte[12];
stream.read(header, 0, 12);
mOffset += 12;
if (header[0] != 'R' ||
header[1] != 'I' ||
header[2] != 'F' ||
header[3] != 'F' ||
header[8] != 'W' ||
header[9] != 'A' ||
header[10] != 'V' ||
header[11] != 'E') {
throw new java.io.IOException("Not a WAV file");
}
mChannels = 0;
mSampleRate = 0;
while (mOffset + 8 <= mFileSize) {
byte[] chunkHeader = new byte[8];
stream.read(chunkHeader, 0, 8);
mOffset += 8;
int chunkLen =
((0xff & chunkHeader[7]) << 24) |
((0xff & chunkHeader[6]) << 16) |
((0xff & chunkHeader[5]) << 8) |
((0xff & chunkHeader[4]));
if (chunkHeader[0] == 'f' &&
chunkHeader[1] == 'm' &&
chunkHeader[2] == 't' &&
chunkHeader[3] == ' ') {
if (chunkLen < 16 || chunkLen > 1024) {
throw new java.io.IOException(
"WAV file has bad fmt chunk");
}
byte[] fmt = new byte[chunkLen];
stream.read(fmt, 0, chunkLen);
mOffset += chunkLen;
int format =
((0xff & fmt[1]) << 8) |
((0xff & fmt[0]));
mChannels =
((0xff & fmt[3]) << 8) |
((0xff & fmt[2]));
mSampleRate =
((0xff & fmt[7]) << 24) |
((0xff & fmt[6]) << 16) |
((0xff & fmt[5]) << 8) |
((0xff & fmt[4]));
if (format != 1) {
throw new java.io.IOException(
"Unsupported WAV file encoding");
}
} else if (chunkHeader[0] == 'd' &&
chunkHeader[1] == 'a' &&
chunkHeader[2] == 't' &&
chunkHeader[3] == 'a') {
if (mChannels == 0 || mSampleRate == 0) {
throw new java.io.IOException(
"Bad WAV file: data chunk before fmt chunk");
}
int frameSamples = (mSampleRate * mChannels) / 50;
mFrameBytes = frameSamples * 2;
mNumFrames = (chunkLen + (mFrameBytes - 1)) / mFrameBytes;
mFrameOffsets = new int[mNumFrames];
mFrameLens = new int[mNumFrames];
mFrameGains = new int[mNumFrames];
byte[] oneFrame = new byte[mFrameBytes];
int i = 0;
int frameIndex = 0;
while (i < chunkLen) {
int oneFrameBytes = mFrameBytes;
if (i + oneFrameBytes > chunkLen) {
i = chunkLen - oneFrameBytes;
}
stream.read(oneFrame, 0, oneFrameBytes);
int maxGain = 0;
for (int j = 1; j < oneFrameBytes; j += 4 * mChannels) {
int val = java.lang.Math.abs(oneFrame[j]);
if (val > maxGain) {
maxGain = val;
}
}
mFrameOffsets[frameIndex] = mOffset;
mFrameLens[frameIndex] = oneFrameBytes;
mFrameGains[frameIndex] = maxGain;
frameIndex++;
mOffset += oneFrameBytes;
i += oneFrameBytes;
if (mProgressListener != null) {
boolean keepGoing = mProgressListener.reportProgress(
i * 1.0 / chunkLen);
if (!keepGoing) {
break;
}
}
}
} else {
stream.skip(chunkLen);
mOffset += chunkLen;
}
}
}
在我达到
之前,一切似乎都很直接int frameSamples = (mSampleRate * mChannels) / 50;
mFrameBytes = frameSamples * 2;
mNumFrames = (chunkLen + (mFrameBytes - 1)) / mFrameBytes;
Q1。 50魔法数字来自哪里?是假设帧持续时间是50?
Q2。为什么mFrameBytes = frameSample * 2?是假设每个样本是2个字节?但为什么呢?
for (int j = 1; j < oneFrameBytes; j += 4 * mChannels) {
int val = java.lang.Math.abs(oneFrame[j]);
if (val > maxGain) {
maxGain = val;
}
}
Q3。为什么j增加4 * mChannels? 4如何合理?
Q4。 frameGains实际上是什么意思?我已经通过了文章/博客,如
但是我没有看到任何地方提到这个词。
希望有人可以对此有所了解。谢谢。
答案 0 :(得分:2)
Q1。 50魔法数字来自哪里?是假设帧持续时间是50?
A1。计算1/50秒作为帧。因此,如果每秒音频数据,应用程序必须处理50帧缓冲区。
Q2。为什么mFrameBytes = frameSample * 2?是假设每个样本是2个字节?但为什么呢?
A2。我猜这是因为他假设16位样本。
Q3。为什么j增加4 * mChannels? 4如何合理?
A3。我认为这里的关键是要注意它从偏移量1开始。这意味着他只对样本的高阶字节进行采样。 4可能只是一个优化,所以他只处理一半的缓冲区(记住他假设每个样本2个字节)
Q4。 frameGains实际意味着什么?
它正是它所说的。这是该帧的增益(1/50秒)请参阅http://en.m.wikipedia.org/wiki/Gain或Google:Audio Gain。
这也应该有所帮助:https://ccrma.stanford.edu/courses/422/projects/WaveFormat/