代码之家  ›  专栏  ›  技术社区  ›  user3454910

Android音频录制到wav

  •  1
  • user3454910  · 技术社区  · 10 年前

    我用Android上的录音机录制了一段音频,它生成了一个原始PCM文件。我正在尝试将其转换为我可以听的格式(例如wav或mp3)。

    我从这个例子开始,但不知道从这里开始: Android AudioRecord example

    尝试以下操作: http://computermusicblog.com/blog/2008/08/29/reading-and-writing-wav-files-in-java

    Recording .Wav with Android AudioRecorder

    这是我要录制的代码(注意,我正在使用倒计时来告诉它何时开始和停止录制。

    public class AudioRecordService extends Service {
        Toast toast;
        private static final int RECORDER_SAMPLERATE = 44100;
        private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
        private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
        private AudioRecord record = null;
        int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
        int BytesPerElement = 2; // 2 bytes in 16bit format
        private Thread recordingThread = null;
        private boolean isRecording = false;
        int buffsize = 0;
    
        public AudioRecordService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        public int onStartCommand(Intent intent, int flags, int startId)
        {
            try {
                buffsize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    
                record = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    RECORDER_SAMPLERATE, RECORDER_CHANNELS,
                    RECORDER_AUDIO_ENCODING, buffsize);
    
                record.startRecording();
    
                CountDownTimer countDowntimer = new CountDownTimer(15000, 1000) {
                    public void onTick(long millisUntilFinished) {
                        toast = Toast.makeText(AudioRecordService.this, "Recording", Toast.LENGTH_SHORT);
                        toast.show();
                        isRecording = true;
                        recordingThread = new Thread(new Runnable() {
                            public void run() {
                                writeAudioDataToFile();
                            }
                        }, "AudioRecorder Thread");
                        recordingThread.start();
                    }
    
                    public void onFinish() {
                        try {
                            toast.cancel();
                            Toast.makeText(AudioRecordService.this, "Done Recording ", Toast.LENGTH_SHORT).show();
                            isRecording = false;
                            record.stop();
                            record.release();
                            record = null;
                            recordingThread = null;
                        } catch (Exception e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
    
    
                }};
                countDowntimer.start();
            }
            catch (Exception ex)
            {
                ex.printStackTrace();
            }
            return Service.START_STICKY;
        }
    
        private byte[] short2byte(short[] sData) {
            int shortArrsize = sData.length;
            byte[] bytes = new byte[shortArrsize * 2];
            for (int i = 0; i < shortArrsize; i++) {
                bytes[i * 2] = (byte) (sData[i] & 0x00FF);
                bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
                sData[i] = 0;
            }
            return bytes;
    
        }
    
        private void writeAudioDataToFile() {
            try {
                //String filePath = "/sdcard/voice8K16bitmono.pcm";
                String extState = Environment.getExternalStorageState();
                // Path to write files to
                String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "/test").getAbsolutePath();
    
                String fileName = "audio.pcm";
                String externalStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
                File file = new File(externalStorage + File.separator + fileName);
    
                // if file doesnt exists, then create it
                if (!file.exists()) {
                    file.createNewFile();
                }
                short sData[] = new short[BufferElements2Rec];
    
                FileOutputStream os = null;
                try {
                    os = new FileOutputStream(file);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
    
                while (isRecording) {
                    // gets the voice output from microphone to byte format
    
                    record.read(sData, 0, BufferElements2Rec);
                    System.out.println("Short wirting to file" + sData.toString());
                    try {
                        // // writes the data to file from buffer
                        // // stores the voice buffer
                        byte bData[] = short2byte(sData);
                        os.write(bData, 0, BufferElements2Rec * BytesPerElement);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    

    我的音频。创建pcm。但是我不知道怎么玩。我假设bDate[]是正在写入的字节数组。我创建的链接说他们使用了这些文件,但没有显示如何实现的示例。

    如果重要的话,我已经用GoldWave打开了文件。它打开了,但音频被打乱了。

    我还注意到我的文件是2秒,我认为这是因为BytesPerElement和BufferElements2Rec。如果你能帮我,那么15秒就好了。

    提前感谢!

    2 回复  |  直到 8 年前
        1
  •  3
  •   jaket    10 年前

    PCM文件和WAV文件之间的唯一区别是PCM文件没有头,而WAV文件有头。WAV报头具有用于回放的关键信息,例如采样率、每个采样的比特数和信道数。当您加载PCM文件时,应用程序必须事先了解此信息,或者您必须告诉它。例如,如果您将PCM文件加载到audacity中,它将提示您填写所有这些内容。

    为了使现有的保存文件成为.WAV,您需要预先准备一个适当的头文件。我不打算详细介绍它,因为关于SO的详细信息已经有很多答案了,而且在网上很容易找到( https://en.wikipedia.org/wiki/WAV )

    关于文件长度的第二个问题可能与以下事实有关 AudioRecord.read 返回一个int,它是实际读取的样本数,因为它可能比您要求的要少。这确实是第二个问题

        2
  •  0
  •   Nilesh Deokar    7 年前

    这是一个示例 .WAV 标题格式提取自 OMRECORDER :

    private byte[] wavFileHeader(long totalAudioLen, long totalDataLen, long longSampleRate,
          int channels, long byteRate, byte bitsPerSample) {
        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (channels * (bitsPerSample / 8)); //
        // block align
        header[33] = 0;
        header[34] = bitsPerSample; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        return header;
      }
    

    以下是标题格式 .aac 提取自 WhatsappAudioRecorder :

    private byte[] createAdtsHeader(int length) {
            int frameLength = length + 7;
            byte[] adtsHeader = new byte[7];
    
            adtsHeader[0] = (byte) 0xFF; // Sync Word
            adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
            adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
            adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
            adtsHeader[2] |= (((byte) CHANNELS) >> 2);
            adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
            adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
            adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
            adtsHeader[6] = (byte) 0xFC;
    
            return adtsHeader;
        }
    
    推荐文章