Unity Microphone 無限時長錄製
阿新 • • 發佈:2019-01-03
原創文章:轉載請標明出處--部落格園 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(); } }
如果這篇文章對您有所幫助,打賞一下作者吧,碼字也挺辛苦的