当前位置: 首页 > 面试题库 >

将PCM记录的数据写入.wav文件(java android)

魏旭
2023-03-14
问题内容

我正在使用AudioRecord在Android中记录16位PCM数据。记录数据并将其保存到文件后,我将其读回以将其另存为.wav文件。

问题是WAV文件可以被媒体播放器识别,但只能播放纯噪声。目前,我的最佳猜测是我的wav文件头不正确,但我一直无法确定问题出在哪里。(我认为这是因为我可以播放在Audacity中记录的原始PCM数据)

这是我的代码,用于读取原始PCM文件并将其另存为.wav:

private void properWAV(File fileToConvert, float newRecordingID){
    try {
        long mySubChunk1Size = 16;
        int myBitsPerSample= 16;
        int myFormat = 1;
        long myChannels = 1;
        long mySampleRate = 22100;
        long myByteRate = mySampleRate * myChannels * myBitsPerSample/8;
        int myBlockAlign = (int) (myChannels * myBitsPerSample/8);

        byte[] clipData = getBytesFromFile(fileToConvert);

        long myDataSize = clipData.length;
        long myChunk2Size =  myDataSize * myChannels * myBitsPerSample/8;
        long myChunkSize = 36 + myChunk2Size;

        OutputStream os;        
        os = new FileOutputStream(new File("/sdcard/onefile/assessor/OneFile_Audio_"+ newRecordingID+".wav"));
        BufferedOutputStream bos = new BufferedOutputStream(os);
        DataOutputStream outFile = new DataOutputStream(bos);

        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

        outFile.flush();
        outFile.close();

    } catch (IOException e) {
        e.printStackTrace();
    }

}


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)
    {
        /*
         * NB have also tried:
         * return new byte[]{(byte)(data & 0xff),(byte)((data >> 8) & 0xff)};
         * 
         */

        return new byte[]{(byte)(data & 0xff),(byte)((data >>> 8) & 0xff)};
    }

我没有包含getBytesFromFile(),因为它占用了太多空间,并且它是一种经过实践检验的方法。无论如何,这是执行实际记录的代码:

public void run() { 
    Log.i("ONEFILE", "Starting main audio capture loop...");

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

    final int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);

    AudioRecord audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, bufferSize);

    audioRecord.startRecording();
    ByteArrayOutputStream recData = new ByteArrayOutputStream(); 
    DataOutputStream dos = new DataOutputStream(recData);

    short[] buffer = new short[bufferSize];  
    audioRecord.startRecording();

    while (!stopped) {  
        int bufferReadResult = audioRecord.read(buffer, 0, bufferSize);

        for(int i = 0; i < bufferReadResult;i++) {
            try {
                dos.writeShort(buffer[i]);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }  
    audioRecord.stop();
    try {
        dos.flush();
        dos.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    }

    audioRecord.stop();

    byte[] clipData = recData.toByteArray();

    File file = new File(audioOutputPath);
    if(file.exists())
        file.delete();
    file = new File(audioOutputPath);
    OutputStream os;
    try {
        os = new FileOutputStream(file);

        BufferedOutputStream bos = new BufferedOutputStream(os);
        DataOutputStream outFile = new DataOutputStream(bos);

        outFile.write(clipData);

        outFile.flush();
        outFile.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

请提出可能出了什么问题。


问题答案:

几个小时以来,我一直在努力解决这个完全相同的问题,而我的问题主要是,当以16位记录时,您必须非常小心写到输出中的内容。WAV文件需要使用Little
Endian格式的数据,但是使用writeShort会将其作为Big
Endian写入到输出中。使用其他功能时,我也得到了有趣的结果,所以我返回以正确的顺序写入字节,并且可以正常工作。

在调试时,我广泛使用了十六进制编辑器。我可以建议您也这样做。另外,上面答案中的标头有效,我用它来检查我自己的代码,并且此标头相当安全。



 类似资料:
  • 我想在Python脚本中使用SOX之类的工具将。PCM文件转换为。wav文件。该工具需要跨平台兼容(Windows和Linux)。有什么建议吗?

  • 问题内容: 在这里和其他地方,我已经看到许多对此的部分答案,但是我非常适合作为新手程序员,并希望找到一个彻底的解决方案。我已经能够在Chrome Canary(v。29.x)中设置笔记本电脑麦克风的录制音频,并且可以使用recorder.js相对容易地设置录制.wav文件并将其保存在本地,例如: http://webaudiodemos.appspot.com/AudioRecorder/inde

  • 问题内容: 好的,这是我设置所有内容的代码: 发生的是 error.log被创建 没有写任何东西 尽管未添加StreamHandler并将debug设置为false,但我仍然将所有内容都添加到STDOUT中(这可能是正确的,但仍然看起来很奇怪) 我是完全离开这里还是发生了什么事? 问题答案: 为什么不这样做呢? 如果现在启动应用程序,你将看到error.log包含: 有关更多信息,请访问http:

  • 我正在阅读一个用一些分隔符分隔的文本文件。 我的文本文件内容示例 Avc def efg JKSJD 1 2 3 5 3 4 6 0 每次调用createRow和createCell时是否都会创建新对象? 如果是,有什么替代方案?。如何以更好的性能将大数据写入excel?

  • 问题内容: 我在变量中存储了JSON数据。 我想将其写入文本文件进行测试,因此不必每次都从服务器获取数据。 目前,我正在尝试: 我收到此错误: TypeError:必须是字符串或缓冲区,而不是dict 如何解决这个问题? 问题答案: 您忘记了实际的JSON部分- 是字典,尚未进行JSON编码。写这样的最大兼容性(Python 2和3): 在现代系统(即Python 3和UTF-8支持)上,您可以使

  • 我在pandas中有一个数据帧,我想把它写到CSV文件中。我使用的是: 并得到错误: 有没有什么方法可以很容易地解决这个问题(例如,我的数据帧中有unicode字符)?还有,有没有一种方法可以使用“to-tab”方法(我认为不存在)写入以制表符分隔的文件,而不是CSV?