首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >理解Android RingDroid WAV的计算

理解Android RingDroid WAV的计算
EN

Stack Overflow用户
提问于 2014-06-06 06:27:03
回答 1查看 303关注 0票数 1

我一直在研究RingDroid的源代码,试图找出如何在安卓设备上绘制波形。然而,我被困在关于在CheapWAV.java中读取WAV文件的部分。

代码语言:javascript
复制
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;
        }
    }
}

一切似乎都向前看,直到我到达

代码语言:javascript
复制
int frameSamples = (mSampleRate * mChannels) / 50;
mFrameBytes = frameSamples * 2;

mNumFrames = (chunkLen + (mFrameBytes - 1)) / mFrameBytes;

Q1.50个魔法数字是从哪里来的?它只是假设帧持续时间是50吗?

Q2.为什么mFrameBytes = frameSample * 2?假设每个样本是2字节吗?但为什么?

代码语言:javascript
复制
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实际上是什么意思?我已经读过一些文章/博客,比如

  1. https://ccrma.stanford.edu/courses/422/projects/WaveFormat/2
  2. http://blogs.msdn.com/b/dawate/archive/2009/06/23/intro-to-audio-programming-part-2-demystifying-the-wav-format.aspx
  3. http://www.speakingcode.com/2011/12/31/primer-on-digital-audio-and-pulse-code-modulation-pcm/

但我没有看到任何地方提到过这样的术语。

希望有人能对这件事有所了解。谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-06 07:41:07

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获得:音频增益。

这也会有帮助:https://ccrma.stanford.edu/courses/422/projects/WaveFormat/

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24075547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档