Unity 自动录音并截取音频保存

本章和之前的讯飞文章有关联

之前我们做了讯飞的语音识别功能。现在我们做进一步的优化,做成自动录音。

思路

当麦克风的音量值大于一个值时,我们录音开启。
当麦克风的音量值连续小于一个值N次时,我们就当作说完话了,停止录音。

主要部分:

获取麦克风音量

private float GetVolume(AudioClip clip,int lengthVolume)
   {
       if (Microphone.IsRecording(null))
       {
           float maxVolume = 0f;
           //用于储存一段时间内的音频信息
           float[] volumeData = new float[lengthVolume];
           //获取录制的音频的开头位置
           int offset = Microphone.GetPosition(null) - (lengthVolume + 1);
           if (offset < 0)
               return 0f;
           //获取数据
           clip.GetData(volumeData, offset);
           //解析数据
           for (int i = 0; i < lengthVolume; i++)
           {
               float tempVolume = volumeData[i];
               if (tempVolume > maxVolume)
                   maxVolume = tempVolume;
           }
           return maxVolume * 99;
       }
       return 0;
   }

Clip转Byte[]

 /// 
    /// clip转byte[]
    /// 
    /// 音频片段
    /// 开始点
    /// 结束点
    /// 
    public byte[] AudioClipToByte(AudioClip clip, int star, int end)
    {
        float[] data = new float[end - star];
        clip.GetData(data, star);
        int rescaleFactor = 32767; //to convert float to Int16
        byte[] outData = new byte[data.Length * 2];
        for (int i = 0; i < data.Length; i++)
        {
            short temshort = (short)(data[i] * rescaleFactor);
            byte[] temdata = BitConverter.GetBytes(temshort);
            outData[i * 2] = temdata[0];
            outData[i * 2 + 1] = temdata[1];
        }
        return outData;
    }

star开始点就是记录录音开启时的第一个点
end结束点就是记录录音关闭前的最后一个点

点的获取方式就是

Microphone.GetPosition(Microphone.devices[0]);

完整部分

using System;
using System.IO;
using UnityEngine;

public class AutomaticRecord : MonoBehaviour
{
    public float volume;//音量

    private const int VOLUME_DATA_LENGTH = 128;    //录制的声音长度
    private const int frequency = 16000; //码率
    private const int lengthSec = 600;   //录制时长
    private const float minVolume = 3;//录音关闭音量值
    private const float maxVolume = 8;//录音开启音量值
    private const int minVolume_Sum = 15;//小音量总和值

    private AudioSource audioSource;  //录制的音频
    private bool isRecord;//录音开关
    private bool isStart;//录音开启的起点
    private int minVolume_Number;//记录的小音量数量
    private int start;//录音起点
    private int end;//录音终点

    private void Start()
    {
        audioSource = GetComponent();
        audioSource.clip = Microphone.Start(null, true, lengthSec, frequency);
    }

    private void Update()
    {
        volume = GetVolume(audioSource.clip, VOLUME_DATA_LENGTH);
        RecordOpenClose();
    }

    /// 
    /// 录音自动开关
    /// 
    private void RecordOpenClose()
    {
        //开
        if (GetVolume(audioSource.clip, VOLUME_DATA_LENGTH) >= maxVolume)
        {
            if (!isStart)
            {
                isStart = true;
                start = Microphone.GetPosition(Microphone.devices[0]);
            }
            minVolume_Number = 0;
            isRecord = true;
        }
        //关
        if (isRecord && GetVolume(audioSource.clip, VOLUME_DATA_LENGTH) < minVolume)
        {
            if (minVolume_Number > minVolume_Sum)
            {
                end = Microphone.GetPosition(Microphone.devices[0]);
                minVolume_Number = 0;
                isRecord = false;
                isStart = false;
                byte[] playerClipByte = AudioClipToByte(audioSource.clip, start, end);
                File.WriteAllBytes(Application.streamingAssetsPath + "/audio.wav", playerClipByte);
            }
            minVolume_Number++;
        }
    }

    /// 
    /// 获取音量
    /// 
    /// 音频片段
    /// 长度
    /// 
    private float GetVolume(AudioClip clip,int lengthVolume)
    {
        if (Microphone.IsRecording(null))
        {
            float maxVolume = 0f;
            //用于储存一段时间内的音频信息
            float[] volumeData = new float[lengthVolume];
            //获取录制的音频的开头位置
            int offset = Microphone.GetPosition(null) - (lengthVolume + 1);
            if (offset < 0)
                return 0f;
            //获取数据
            clip.GetData(volumeData, offset);
            //解析数据
            for (int i = 0; i < lengthVolume; i++)
            {
                float tempVolume = volumeData[i];
                if (tempVolume > maxVolume)
                    maxVolume = tempVolume;
            }
            return maxVolume * 99;
        }
        return 0;
    }

    /// 
    /// clip转byte[]
    /// 
    /// 音频片段
    /// 开始点
    /// 结束点
    /// 
    public byte[] AudioClipToByte(AudioClip clip, int star, int end)
    {
        float[] data;
        if (end > star)
            data = new float[end - star];
        else
            data = new float[clip.samples - star + end];
        clip.GetData(data, star);
        int rescaleFactor = 32767; //to convert float to Int16
        byte[] outData = new byte[data.Length * 2];
        for (int i = 0; i < data.Length; i++)
        {
            short temshort = (short)(data[i] * rescaleFactor);
            byte[] temdata = BitConverter.GetBytes(temshort);
            outData[i * 2] = temdata[0];
            outData[i * 2 + 1] = temdata[1];
        }
        return outData;
    }
}

这里我是设定的600秒音频循环录制。然后只截取自己最新的录音部分,录多长就生成多长的音频文件。不会是600秒的音频。

待优化部分

1.当噪音值达到录音开启时(目前能想到的是Start点到End点过短过滤,但无法过滤持续噪音)
2.当Start点接近设定的音频长度时(600秒),录音的长度超过设定的长度,End点到起始点(0秒)的位置。

有想法的小伙伴可以共同讨论喔!

你可能感兴趣的:(音频)