在安卓系统中如何录制.wav格式的文件

19

我想在安卓设备上录制.wav文件。有没有什么方法可以实现这个功能?


2
您已经提出了这个问题,请勿重复提问。 - user146043
5个回答

10

在快速搜索之后,我发现有直接支持波形记录的方法。最常见的波形格式是PCM。android.media.AudioRecord支持PCM输出。您只需要将这些数据写入文件即可。

在创建了文件之后,您需要编写自己的转换器来将其转换为波形格式(或寻找在线库进行转换)。

如果您需要一个已经准备好可以直接录制波形的应用程序,可以下载此应用:

附加链接:


8

您需要使用AudioRecord类,并自行编写wav头数据。以下代码应该包含您需要的所有内容。

class WavRecorder(val context: Context) {
    private var recorder: AudioRecord? = null
    private var isRecording = false

    private var recordingThread: Thread? = null

    fun startRecording(_filename: String? = null, internalStorage: Boolean = false) {
        val filename = _filename ?: "recording-${System.currentTimeMillis()}.wav"

        val path = if (internalStorage) context.filesDir?.path + "/$filename"
        else context.externalCacheDir?.path + "/$filename"

        recorder = AudioRecord(MediaRecorder.AudioSource.MIC,
                RECORDER_SAMPLE_RATE, RECORDER_CHANNELS,
                RECORDER_AUDIO_ENCODING, 512)

        recorder?.startRecording()
        isRecording = true

        recordingThread = thread(true) {
            writeAudioDataToFile(path)
        }
    }


    fun stopRecording() {
        recorder?.run {
            isRecording = false;
            stop()
            release()
            recordingThread = null
            recorder = null
        }
    }

    private fun short2byte(sData: ShortArray): ByteArray {
        val arrSize = sData.size
        val bytes = ByteArray(arrSize * 2)
        for (i in 0 until arrSize) {
            bytes[i * 2] = (sData[i] and 0x00FF).toByte()
            bytes[i * 2 + 1] = (sData[i].toInt() shr 8).toByte()
            sData[i] = 0
        }
        return bytes
    }

    private fun writeAudioDataToFile(path: String) {
        val sData = ShortArray(BufferElements2Rec)
        var os: FileOutputStream? = null
        try {
            os = FileOutputStream(path)
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
        }

        val data = arrayListOf<Byte>()

        for (byte in wavFileHeader()) {
            data.add(byte)
        }

        while (isRecording) {
            // gets the voice output from microphone to byte format
            recorder?.read(sData, 0, BufferElements2Rec)
            try {
                val bData = short2byte(sData)
                for (byte in bData)
                    data.add(byte)
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }

        updateHeaderInformation(data)

        os?.write(data.toByteArray())

        try {
            os?.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }


    /**
     * Constructs header for wav file format
     */
    private fun wavFileHeader(): ByteArray {
        val headerSize = 44
        val header = ByteArray(headerSize)

        header[0] = 'R'.toByte() // RIFF/WAVE header
        header[1] = 'I'.toByte()
        header[2] = 'F'.toByte()
        header[3] = 'F'.toByte()

        header[4] = (0 and 0xff).toByte() // Size of the overall file, 0 because unknown
        header[5] = (0 shr 8 and 0xff).toByte()
        header[6] = (0 shr 16 and 0xff).toByte()
        header[7] = (0 shr 24 and 0xff).toByte()

        header[8] = 'W'.toByte()
        header[9] = 'A'.toByte()
        header[10] = 'V'.toByte()
        header[11] = 'E'.toByte()

        header[12] = 'f'.toByte() // 'fmt ' chunk
        header[13] = 'm'.toByte()
        header[14] = 't'.toByte()
        header[15] = ' '.toByte()

        header[16] = 16 // Length of format data
        header[17] = 0
        header[18] = 0
        header[19] = 0

        header[20] = 1 // Type of format (1 is PCM)
        header[21] = 0

        header[22] = NUMBER_CHANNELS.toByte()
        header[23] = 0

        header[24] = (RECORDER_SAMPLE_RATE and 0xff).toByte() // Sampling rate
        header[25] = (RECORDER_SAMPLE_RATE shr 8 and 0xff).toByte()
        header[26] = (RECORDER_SAMPLE_RATE shr 16 and 0xff).toByte()
        header[27] = (RECORDER_SAMPLE_RATE shr 24 and 0xff).toByte()

        header[28] = (BYTE_RATE and 0xff).toByte() // Byte rate = (Sample Rate * BitsPerSample * Channels) / 8
        header[29] = (BYTE_RATE shr 8 and 0xff).toByte()
        header[30] = (BYTE_RATE shr 16 and 0xff).toByte()
        header[31] = (BYTE_RATE shr 24 and 0xff).toByte()

        header[32] = (NUMBER_CHANNELS * BITS_PER_SAMPLE / 8).toByte() //  16 Bits stereo
        header[33] = 0

        header[34] = BITS_PER_SAMPLE.toByte() // Bits per sample
        header[35] = 0

        header[36] = 'd'.toByte()
        header[37] = 'a'.toByte()
        header[38] = 't'.toByte()
        header[39] = 'a'.toByte()

        header[40] = (0 and 0xff).toByte() // Size of the data section.
        header[41] = (0 shr 8 and 0xff).toByte()
        header[42] = (0 shr 16 and 0xff).toByte()
        header[43] = (0 shr 24 and 0xff).toByte()

        return header
    }

    private fun updateHeaderInformation(data: ArrayList<Byte>) {
        val fileSize = data.size
        val contentSize = fileSize - 44

        data[4] = (fileSize and 0xff).toByte() // Size of the overall file
        data[5] = (fileSize shr 8 and 0xff).toByte()
        data[6] = (fileSize shr 16 and 0xff).toByte()
        data[7] = (fileSize shr 24 and 0xff).toByte()

        data[40] = (contentSize and 0xff).toByte() // Size of the data section.
        data[41] = (contentSize shr 8 and 0xff).toByte()
        data[42] = (contentSize shr 16 and 0xff).toByte()
        data[43] = (contentSize shr 24 and 0xff).toByte()
    }

    companion object {
        const val RECORDER_SAMPLE_RATE = 8000
        const val RECORDER_CHANNELS: Int = android.media.AudioFormat.CHANNEL_IN_MONO
        const val RECORDER_AUDIO_ENCODING: Int = android.media.AudioFormat.ENCODING_PCM_16BIT
        const val BITS_PER_SAMPLE: Short = 16
        const val NUMBER_CHANNELS: Short = 1
        const val BYTE_RATE = RECORDER_SAMPLE_RATE * NUMBER_CHANNELS * 16 / 8

        var BufferElements2Rec = 1024
    }
}

我们可以立即播放保存的文件吗? - Prabhakaran

5

2

我最近制作了一个用于记录的库。你只需要这样做:

recorder = OmRecorder.wav(
new PullTransport.Default(mic(), new PullTransport.OnAudioChunkPulledListener() {
    @Override public void onAudioChunkPulled(AudioChunk audioChunk) {
      animateVoice((float) (audioChunk.maxAmplitude() / 200.0));
    }
  }), file());

你可以设置音频源的频率等,然后可以轻松地记录WAV文件。 你可以在此找到更多信息:

https://github.com/kailash09dabhi/OmRecorder


0
这对我有用...结果图片
private void setUpMediaRec(String path) {
    Log.i(TAG, "[Start]setting up media recoder![Start]");
    mediaRecorder = new MediaRecorder();
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    mediaRecorder.setOutputFormat(AudioFormat.ENCODING_PCM_16BIT);
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    mediaRecorder.setOutputFile(path);
    Log.i(TAG, "[END]setting up media recoder![END]");}

并提供文件地址(任何您喜欢的地方)以保存记录的文件

mFileName = Environment.getExternalStorageDirectory().getAbsolutePath();
    mFileName += "/my_rec_ext_dir.wav";

5
我会小心使用“AudioFormat.ENCODING_PCM_16BIT”,因为它与“MediaRecorder.OutputFormat.MPEG_4”具有相同的值。 - ChristianoBolla
MediaRecorder不支持WAV格式。实际上,它生成的并不是一个WAV文件,而是一个带有错误的.WAV扩展名的MP4文件。如果能播放,那是因为媒体播放器识别出它实际上是一个MP4文件,并按照MP4格式进行播放。 - Samwise Ganges
@SamwiseGanges 我怎么才能录制原始的PCM数据呢? - undefined
@SazzadHissainKhan 使用AudioRecord类。https://developer.android.com/reference/android/media/AudioRecord.html - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接