1. 程式人生 > >Unity Microphone 無限時長錄製

Unity Microphone 無限時長錄製

 

原創文章:轉載請標明出處--部落格園 Jason_c

 

Unity可以很方便的通過 Microphone.Start()方法來呼叫麥克風,但是有一個弊端是,必須傳入時長,這就很尷尬了,因為大多數時間,我們是不知道使用者需要何時關閉麥克風的,

這裡提供一個解決思路:

1、將microphone設定為迴圈錄製,即:

Microphone.Start(micName, true,2,16000);  

  

2、每隔一定間隔讀取錄製好的資料,並將它快取起來。

這裡值得一提的是,如果每隔2秒儲存一下音訊資料(因為我設定的錄製時間是2秒),

因為程式碼執行也需要時間,會導致音訊資料損壞,聲音會出現明顯的斷層現象,所以這裡將它分段儲存就能解決這種問題,

當麥克風錄製的位置大於音訊的一半的時候,儲存上一段音訊,當麥克風錄製完時,儲存後一段音訊。

 

     bool isSaveFirstHalf = true;//將音訊從中間分生兩段,然後分段儲存
        int micPosition;
        while (!isMicRecordFinished)
        {
            if (isSaveFirstHalf)
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName);return micPosition > length * 6 / 10 && micPosition < length; });//儲存前半段
                micDataTemp = new float[length / 2];
                micClip.GetData(micDataTemp, 0);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }
            else
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName); return micPosition > length / 10 && micPosition < length / 2; });//儲存後半段
                micDataTemp = new float[length/2];
                micClip.GetData(micDataTemp, length / 2);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }

        }

最後處理一下結束時的音訊

     micPosition = Microphone.GetPosition(micName);
        if (micPosition <= length)//前半段
        {
            micDataTemp = new float[micPosition/2];
            micClip.GetData(micDataTemp, 0);
        }
        else
        {
            micDataTemp = new float[micPosition - length/2];
            micClip.GetData(micDataTemp, length/2);
        }

  

3、最後通過儲存的資料生成新的音訊,即:

AudioClip.Create("RecordClip", micDataList.Count, 1, 16000, false);

newAudioClip.SetData(micDataList.ToArray(), 0);

 

 

完整程式碼如下:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MicUnlimitedDuration : MonoBehaviour {
    public delegate void AudioRecordHandle(AudioClip audioClip);
    public AudioSource audioSource;

    AudioClip micClip;


    bool isMicRecordFinished= true;

    List<float> micDataList = new List<float>();
    float[] micDataTemp;

    string micName;

    public void StartMicrophone() {
        StopCoroutine(StartMicrophone(null, PlayAudioRecord));
        StartCoroutine(StartMicrophone(null, PlayAudioRecord));
    }


    IEnumerator StartMicrophone(string microphoneName,AudioRecordHandle  audioRecordFinishedEvent) {
        Debug.Log("Start Mic");
        micDataList = new List<float>();
        micName = microphoneName;
        micClip = Microphone.Start(micName, true,2,16000);
        isMicRecordFinished = false;
        int length = micClip.channels * micClip.samples;
        bool isSaveFirstHalf = true;//將音訊從中間分生兩段,然後分段儲存
        int micPosition;
        while (!isMicRecordFinished)
        {
            if (isSaveFirstHalf)
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName);return micPosition > length * 6 / 10 && micPosition < length; });//儲存前半段
                micDataTemp = new float[length / 2];
                micClip.GetData(micDataTemp, 0);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }
            else
            {
                yield return new WaitUntil(() => { micPosition = Microphone.GetPosition(micName); return micPosition > length / 10 && micPosition < length / 2; });//儲存後半段
                micDataTemp = new float[length/2];
                micClip.GetData(micDataTemp, length / 2);
                micDataList.AddRange(micDataTemp);
                isSaveFirstHalf = !isSaveFirstHalf;
            }

        }
        micPosition = Microphone.GetPosition(micName);
        if (micPosition <= length)//前半段
        {
            micDataTemp = new float[micPosition/2];
            micClip.GetData(micDataTemp, 0);
        }
        else
        {
            micDataTemp = new float[micPosition - length/2];
            micClip.GetData(micDataTemp, length/2);
        }
        micDataList.AddRange(micDataTemp);
        Microphone.End(micName);
        AudioClip newAudioClip = AudioClip.Create("RecordClip", micDataList.Count, 1, 16000, false);
        newAudioClip.SetData(micDataList.ToArray(), 0);
        audioRecordFinishedEvent(newAudioClip);
        Debug.Log("RecordEnd");
    }



    public void StopMicrophone()
    {
        Debug.Log("Stop mic");
        isMicRecordFinished = true;
    }

    void PlayAudioRecord(AudioClip newAudioClip)
    {
        audioSource.clip = newAudioClip;
        audioSource.Play();
    }
}

 

如果這篇文章對您有所幫助,打賞一下作者吧,碼字也挺辛苦的