微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

android – 如何将.pcm文件转换为.wav或.mp3?

我目前正在开发一个具有录音和播放功能Android应用程序.我是处理音频的新手,我在编码和格式方面遇到了一些麻烦.

我能够在我的应用程序中录制和播放音频,但在导出时我无法重现音频.我找到的唯一方法是导出我的.pcm文件并使用Audacity进行转换.

这是我记录音频的代码是:

private Thread recordingThread 
private AudioRecord mRecorder;
private boolean isRecording = false;

private void startRecording() {

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC,Constants.RECORDER_SAMPLERATE,Constants.RECORDER_CHANNELS,Constants.RECORDER_AUdio_ENCODING,Constants.BufferElements2Rec * Constants.BytesPerElement);

    mRecorder.startRecording();
    isRecording = true;

    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToFile();
        }
    },"AudioRecorder Thread");
    recordingThread.start();
}

private void writeAudioDataToFile() {
    // Write the output audio in byte

    FileOutputStream os = null;
    try {
        os = new FileOutputStream(mFileName);
    } catch (FileNotFoundException e) {
        e.printstacktrace();
    }

    while (isRecording) {
        // gets the voice output from microphone to byte format
        mRecorder.read(sData,Constants.BufferElements2Rec);
        try {
            // // writes the data to file from buffer
            // // stores the voice buffer

            byte bData[] = short2byte(sData);

            os.write(bData,Constants.BufferElements2Rec * Constants.BytesPerElement);

        } catch (IOException e) {
            e.printstacktrace();
        }
    }
    try {
        os.close();
    } catch (IOException e) {
        e.printstacktrace();
    }
}

要播放录制的音频,代码为:

private void startPlaying() {

    new Thread(new Runnable() {
        public void run() {

            try {

                File file = new File(mFileName);

                byte[] audioData = null;

                InputStream inputStream = new FileInputStream(mFileName);
                audioData = new byte[Constants.BufferElements2Rec];

                mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC,AudioFormat.CHANNEL_OUT_MONO,Constants.BufferElements2Rec * Constants.BytesPerElement,AudioTrack.MODE_STREAM);


                final float duration = (float) file.length() / Constants.RECORDER_SAMPLERATE / 2;

                Log.i(TAG,"PLAYBACK AUdio");
                Log.i(TAG,String.valueOf(duration));


                mPlayer.setPositionNotificationPeriod(Constants.RECORDER_SAMPLERATE / 10);
                mPlayer.setNotificationMarkerPosition(Math.round(duration * Constants.RECORDER_SAMPLERATE));

                mPlayer.play();

                int i = 0;
                while ((i = inputStream.read(audioData)) != -1) {
                    try {
                        mPlayer.write(audioData,i);
                    } catch (Exception e) {
                        Log.e(TAG,"Exception: " + e.getLocalizedMessage());
                    }
                }

            } catch (FileNotFoundException fe) {
                Log.e(TAG,"File not found: " + fe.getLocalizedMessage());
            } catch (IOException io) {
                Log.e(TAG,"IO Exception: " + io.getLocalizedMessage());
            }

        }

    }).start();


}

Constants类中定义的常量是:

public class Constants {

    final static public int RECORDER_SAMPLERATE = 44100;
    final static public int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
    final static public int RECORDER_AUdio_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

    final static public int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
    final static public int BytesPerElement = 2; // 2 bytes in 16bit format


}

如果我按原样导出文件,我将其转换为Audacity并播放.但是,我需要以可以自动播放的格式导出它.

我已经看到了实施Lame的答案,目前正在研究它.我也找到了使用以下方法转换它的答案:

private File rawToWave(final File rawFile,final String filePath) throws IOException {

    File waveFile = new File(filePath);

    byte[] rawData = new byte[(int) rawFile.length()];
    DataInputStream input = null;
    try {
        input = new DataInputStream(new FileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }

    DataOutputStream output = null;
    try {
        output = new DataOutputStream(new FileOutputStream(waveFile));
        // WAVE header
        // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
        writeString(output,"RIFF"); // chunk id
        writeInt(output,36 + rawData.length); // chunk size
        writeString(output,"WAVE"); // format
        writeString(output,"fmt "); // subchunk 1 id
        writeInt(output,16); // subchunk 1 size
        writeShort(output,(short) 1); // audio format (1 = PCM)
        writeShort(output,(short) 1); // number of channels
        writeInt(output,Constants.RECORDER_SAMPLERATE); // sample rate
        writeInt(output,Constants.RECORDER_SAMPLERATE * 2); // byte rate
        writeShort(output,(short) 2); // block align
        writeShort(output,(short) 16); // bits per sample
        writeString(output,"data"); // subchunk 2 id
        writeInt(output,rawData.length); // subchunk 2 size
        // Audio data (conversion big endian -> little endian)
        short[] shorts = new short[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
        for (short s : shorts) {
            bytes.putShort(s);
        }
        output.write(bytes.array());
    } finally {
        if (output != null) {
            output.close();
        }
    }

    return waveFile;

}

private void writeInt(final DataOutputStream output,final int value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
    output.write(value >> 16);
    output.write(value >> 24);
}

private void writeShort(final DataOutputStream output,final short value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
}

private void writeString(final DataOutputStream output,final String value) throws IOException {
    for (int i = 0; i < value.length(); i++) {
        output.write(value.charat(i));
    }
}

但是,这在导出时会播放正确的持续时间,但只是白噪声.

我尝试但无法工作的一些答案:

> Android:Creating Wave file using Raw PCM,the wave file does not play
> How to convert PCM raw data to mp3 file?
> converting pcm file to mp3 using liblame in android

任何人都可以指出什么是最好的解决方案?它是真的实施跛脚还是可以更直接的方式完成?如果是这样,为什么代码示例将文件转换为白噪声?

解决方法

你已经掌握了大部分代码.我能看到的唯一问题是将PCM数据写入WAV文件的部分.这应该很简单,因为WAV =元数据PCM(按此顺序).这应该工作:
private void rawToWave(final File rawFile,final File waveFile) throws IOException {

    byte[] rawData = new byte[(int) rawFile.length()];
    DataInputStream input = null;
    try {
        input = new DataInputStream(new FileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }

    DataOutputStream output = null;
    try {
        output = new DataOutputStream(new FileOutputStream(waveFile));
        // WAVE header
        // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
        writeString(output,44100); // sample rate
        writeInt(output,RECORDER_SAMPLERATE * 2); // byte rate
        writeShort(output,rawData.length); // subchunk 2 size
        // Audio data (conversion big endian -> little endian)
        short[] shorts = new short[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
        for (short s : shorts) {
            bytes.putShort(s);
        }

        output.write(fullyReadFiletoBytes(rawFile));
    } finally {
        if (output != null) {
            output.close();
        }
    }
}
    byte[] fullyReadFiletoBytes(File f) throws IOException {
    int size = (int) f.length();
    byte bytes[] = new byte[size];
    byte tmpBuff[] = new byte[size];
    FileInputStream fis= new FileInputStream(f);
    try { 

        int read = fis.read(bytes,size);
        if (read < size) {
            int remain = size - read;
            while (remain > 0) {
                read = fis.read(tmpBuff,remain);
                System.arraycopy(tmpBuff,bytes,size - remain,read);
                remain -= read;
            } 
        } 
    }  catch (IOException e){
        throw e;
    } finally { 
        fis.close();
    } 

    return bytes;
} 
private void writeInt(final DataOutputStream output,final String value) throws IOException {
    for (int i = 0; i < value.length(); i++) {
        output.write(value.charat(i));
    }
}

如何使用

它使用起来非常简单.只需将其称为:

File f1 = new File("/sdcard/44100Sampling-16bit-mono-mic.pcm"); // The location of your PCM file
  File f2 = new File("/sdcard/44100Sampling-16bit-mono-mic.wav"); // The location where you want your WAV file
  try {
    rawToWave(f1,f2);
} catch (IOException e) {
    e.printstacktrace();
}

这一切是如何运作的

如您所见,WAV标头是WAV和PCM文件格式之间的唯一区别.假设您正在录制16位PCM MONO音频(根据您的代码,您是). rawToWave函数只是巧妙地将标题添加到WAV文件中,以便音乐播放器知道打开文件时会发生什么,然后在标题之后,它只会从最后一位开始写入PCM数据.

提示

如果你想改变你的声音音调,或者做一个语音转换器应用程序,你所要做的就是增加/减少writeInt的值(输出,44100); //代码中的采样率减小它将告诉玩家以不同的速率播放它,从而改变输出音高.只是一点额外的’好知道’的事情.

原文地址:https://www.jb51.cc/android/314065.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐