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[]

 /// <summary>
    /// clip转byte[]
    /// </summary>
    /// <param name="clip">音频片段</param>
    /// <param name="star">开始点</param>
    /// <param name="end">结束点</param>
    /// <returns></returns>
    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>();
        audioSource.clip = Microphone.Start(null, true, lengthSec, frequency);
    }

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

    /// <summary>
    /// 录音自动开关
    /// </summary>
    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++;
        }
    }

    /// <summary>
    /// 获取音量
    /// </summary>
    /// <param name="clip">音频片段</param>
    /// <param name="lengthVolume">长度</param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// clip转byte[]
    /// </summary>
    /// <param name="clip">音频片段</param>
    /// <param name="star">开始点</param>
    /// <param name="end">结束点</param>
    /// <returns></returns>
    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秒)的位置。

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

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
要在Unity中实现手机相机拍照并保存,首先需要使用Unity的调用手机相机的API。我们可以通过Unity的Input类中的GetButtonDown函数来捕捉到手机相机按钮被按下的事件。 首先,我们需要在Unity中创建一个按钮对象用来触发拍照的操作。然后,在按钮的脚本中,我们可以编写如下代码: ``` using UnityEngine; using System.Collections; using System.IO; public class CameraController : MonoBehaviour { // 定义保存图片的路径和文件名 private string savePath = "/sdcard/DCIM/Camera/"; private string fileName = "photo.png"; // 第一次触发拍照按钮时调用 void OnMouseDown() { StartCoroutine(TakeAndSavePhoto()); } // 拍照并保存的协程函数 IEnumerator TakeAndSavePhoto() { // 调用手机相机 yield return Application.RequestUserAuthorization(UserAuthorization.WebCam); if (Application.HasUserAuthorization(UserAuthorization.WebCam)) { WebCamTexture webcamTexture = new WebCamTexture(); webcamTexture.Play(); // 拍照 yield return new WaitForEndOfFrame(); Texture2D photo = new Texture2D(webcamTexture.width, webcamTexture.height); photo.SetPixels(webcamTexture.GetPixels()); photo.Apply(); // 保存照片 byte[] bytes = photo.EncodeToPNG(); File.WriteAllBytes(savePath + fileName, bytes); Debug.Log("照片已保存至:" + savePath + fileName); // 停止相机 webcamTexture.Stop(); } } } ``` 以上的代码使用了Unity的协程函数来实现拍照和保存照片的操作。首先,我们使用Application.RequestUserAuthorization函数请求用户授权使用相机。如果授权成功,我们创建一个WebCamTexture对象并将其作为相机预览。 当按钮被按下后,我们调用WebCamTexture.GetPixels函数获取相机的当前帧数据并创建一个新的Texture2D对象用来保存照片。然后,我们使用Texture2D.EncodeToPNG函数将照片转换为PNG格式并使用File.WriteAllBytes函数将照片保存到指定路径。 最后,我们通过调用WebCamTexture.Stop函数停止相机预览。 在代码中,我们将照片保存到了"/sdcard/DCIM/Camera/"路径下的"photo.png"文件。你可以根据你的实际需求修改保存路径和文件名。 希望以上内容对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VAIN_K

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值