2

我已经在我的 android 应用程序中使用 Mic 进行了录制,并且在使用 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)};
    }
4

2 回答 2

1

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

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

如果您创建了一个标头并附加了原始数据,并且生成的文件播放没有错误但听起来像噪音,那么最可能的罪魁祸首是原始音频每个样本使用 2 个字节,但是您将标头中的 BitsPerSample 属性设置为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)};
    }

? 我不确定>>>在位移世界中意味着什么。

于 2011-02-10T17:06:52.507 回答
0

在此处查看编写 wav 标头的排练助手代码

于 2011-03-06T14:15:59.957 回答