【问题标题】:AudioRecord PCM data of no use?AudioRecord PCM数据没用?
【发布时间】:2011-03-06 22:15:59
【问题描述】:

我已经在我的 android 应用程序中使用麦克风进行录制,当使用 AudioPlayer 类将数据流式传输时,它播放得非常好。我的问题是我想在这些数据上附加一个 wav 标头,以便它可以在外部播放应用。我很确定在十六进制编辑器中播放其他音频文件后创建标头的方法可以工作,这会导致记录的 pcm 数据不能用作 wav 文件中的原始数据?

任何人都可以对此有所了解吗?我可以将 pcm/wav 文件作为原始文件导入 audacity,它可以完美播放,但是当我尝试打开 wav 时,我只会听到噪音,再次暗示 pcm 数据有问题。

录音设置:

int frequency = 22050;
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;

标题变量:

byte[] clipData = data;
long myDataSize = clipData.length;
long mySubChunk1Size = 16;
int myBitsPerSample= 16;
int myFormat = 1;
long myChannels = 1;
long mySampleRate = 22050;
long myByteRate = mySampleRate * myChannels * myBitsPerSample/8;
int myBlockAlign = (int) (myChannels * myBitsPerSample/8);
long myChunk2Size =  myDataSize * myChannels * myBitsPerSample/8;
long myChunkSize = 36 + myChunk2Size;

try
        {
            File audioDirectory = new File(Environment
                    .getExternalStorageDirectory().getAbsolutePath()
                    + "/Directory/");
            audioDirectory.mkdir();
            File file = new File(audioDirectory, "test.wav");
            if (file.exists())
                file.delete();

            // Create the new file.
            try {
                file.createNewFile();
            } catch (IOException e) {
                throw new IllegalStateException("Failed to create "
                        + file.toString());
            }
            OutputStream os = new FileOutputStream(file);
            BufferedOutputStream bos = new BufferedOutputStream(os);
            DataOutputStream outFile = new DataOutputStream(bos);

            // write the wav file per the wav file format
            outFile.writeBytes("RIFF");                 // 00 - RIFF
            outFile.write(intToByteArray((int)myChunkSize), 0, 4);      // 04 - how big is the rest of this file?
            outFile.writeBytes("WAVE");                 // 08 - WAVE
            outFile.writeBytes("fmt ");                 // 12 - fmt 
            outFile.write(intToByteArray((int)mySubChunk1Size), 0, 4);  // 16 - size of this chunk
            outFile.write(shortToByteArray((short)myFormat), 0, 2);     // 20 - what is the audio format? 1 for PCM = Pulse Code Modulation
            outFile.write(shortToByteArray((short)myChannels), 0, 2);   // 22 - mono or stereo? 1 or 2?  (or 5 or ???)
            outFile.write(intToByteArray((int)mySampleRate), 0, 4);     // 24 - samples per second (numbers per second)
            outFile.write(intToByteArray((int)myByteRate), 0, 4);       // 28 - bytes per second
            outFile.write(shortToByteArray((short)myBlockAlign), 0, 2); // 32 - # of bytes in one sample, for all channels
            outFile.write(shortToByteArray((short)myBitsPerSample), 0, 2);  // 34 - how many bits in a sample(number)?  usually 16 or 24
            outFile.writeBytes("data");                 // 36 - data
            outFile.write(intToByteArray((int)myDataSize), 0, 4);       // 40 - how big is this data chunk
            outFile.write(clipData);                        // 44 - the actual data itself - just a long string of numbers
        }

转换器

public static int byteArrayToInt(byte[] b)
    {
        int start = 0;
        int low = b[start] & 0xff;
        int high = b[start+1] & 0xff;
        return (int)( high << 8 | low );
    }


    // these two routines convert a byte array to an unsigned integer
    public static long byteArrayToLong(byte[] b)
    {
        int start = 0;
        int i = 0;
        int len = 4;
        int cnt = 0;
        byte[] tmp = new byte[len];
        for (i = start; i < (start + len); i++)
        {
            tmp[cnt] = b[i];
            cnt++;
        }
        long accum = 0;
        i = 0;
        for ( int shiftBy = 0; shiftBy < 32; shiftBy += 8 )
        {
            accum |= ( (long)( tmp[i] & 0xff ) ) << shiftBy;
            i++;
        }
        return accum;
    }


// ===========================
// CONVERT JAVA TYPES TO BYTES
// ===========================
    // returns a byte array of length 4
    private static byte[] intToByteArray(int i)
    {
        byte[] b = new byte[4];
        b[0] = (byte) (i & 0x00FF);
        b[1] = (byte) ((i >> 8) & 0x000000FF);
        b[2] = (byte) ((i >> 16) & 0x000000FF);
        b[3] = (byte) ((i >> 24) & 0x000000FF);
        return b;
    }

    // convert a short to a byte array
    public static byte[] shortToByteArray(short data)
    {
        return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)};
    }

【问题讨论】:

    标签: java android pcm


    【解决方案1】:

    您可能只是设置了错误的标题属性。 WAV 格式标头应为 44 字节,后跟原始音频数据。以下是WAV格式的说明:

    http://www.sonicspot.com/guide/wavefiles.html

    如果您创建了一个标头并附加了原始数据,并且生成的文件可以正常播放,但听起来像噪音,那么最可能的罪魁祸首是原始音频每个样本使用 2 个字节,但是您将 Bi​​tsPerSample 属性设置为标题为 8。

    您使用的方法(将 WAV 标头添加到原始音频)完全有效,应该可以正常工作。

    更新:嘿,你的转换方法不应该是

        // convert a short to a byte array
        public static byte[] shortToByteArray(short data)
        {
            return new byte[]{(byte)(data & 0xff),(byte)((data >> 8) & 0xff)};
        }
    

    ?我不确定&gt;&gt;&gt; 在位移世界中的含义。

    【讨论】:

    • 我很确定我正确设置了标题,我已经用我用来记录的代码编辑了问题,然后创建了标题。
    • @Sam:您绝对不应该在标题中包含任何类型为“long”的内容。 WAV 标头的属性都是 4 字节整数或 2 字节整数。包含更多代码,让我看看您实际上是如何将标头和数据写入结果文件的。
    • @MusiGenesis - 我已经添加了几乎所有用于创建标头的代码,是的,我了解长数据类型,这就是我在其中使用 Convertor 方法的原因。该文件被识别为 .wav 文件,播放时充满静电和噪音。
    • 您编写标题和数据的方法看起来是正确的。同样,几乎任何标题中的错误都会产生一个损坏的文件,玩家会吐槽,所以你的 shortToByteArray 方法可能有问题。
    • 感谢您在这个问题上坚持我,将数据类型转换为字节并再次返回的方法来自该网站:computermusicblog.com/blog/2008/08/29/… 我很确定它们是正确的。我真的不知道现在出了什么问题。
    【解决方案2】:

    看看写wav头的排练助手代码here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-29
      • 1970-01-01
      • 1970-01-01
      • 2011-05-31
      • 2017-06-12
      • 2014-03-16
      • 1970-01-01
      相关资源
      最近更新 更多