Unity 声音与录音与麦克风实时播放

Unity AudioSource与MicroPhone以及AudioClip之间的关系。

下面是一个声音,长度为7秒钟,声音的实际数据本质是由采样点组成的的列表,一秒钟内的采样点数就是采样频率,下面的采样频率是10,正常实际中是44100,根据需求设置;AudioSource播放声音时,设置其TimeSamples的意思就是从声音的第timeSamples个采样点位置开始播放,因此设置声音的播放的偏移位置的方式是设置timeSamples或者设置time。播放时timeSamples并不是一直固定的,跟随时间逐个指向每个对应的采样点的索引值。

接下来是设置麦克风的,麦克风的原理就是首先定义一个Clip,开始录音之后,就不断的将录音采样点值赋予clip的相对应的采样点,这点和Audiosource的timeSamples相同,区别是两者的操作相反,当前采样点的位置可以用MicroPhone的GetPosition()获得。因此如果想要像KTV那样实时的播放录音,就是让audiosource播放的时候,timeSamples的值刚好等于当前采样点的值,或者延迟不大的一段采样点距离(好吧,我这么干了,可是不知道为什么噪音很严重,有待研究,并且timeSamples的值不能大于当前录音采样点的值,不然没有声音(傻瓜都能想到为什么))。好吧,今日附贴,与公司大佬讨论了一下之后终于明白了,原来噪音出现的原因是我播出来的声音又实时的被录进去了,从而出现类似回音的效果,所以最好戴上耳机录音。

下面是实时播放的代码。

 

复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MicroPhoneTest : MonoBehaviour
{
    public AudioSource aud;

    bool isHaveMicroPhone;
    string device;
    public Text text;

    //Debug Text
    public Text clipLength;//记录音频文件的长度
    public Text devicePosition;//设备音频的位置
    public Text audioTime;//记录音频的时间
    public Text audioSampleTime;//

    
    // Start is called before the first frame update
    void Start()
    {
        aud = GetComponent<AudioSource>();
        string[] devices = Microphone.devices;

        if (devices.Length > 0)
        {
            isHaveMicroPhone = true;
            device = devices[0];
            text.text = devices[0];
        }
        else
        {
            isHaveMicroPhone = false;
            text.text = "没有获取到麦克风";
        }
    }

    //开始录音按钮
    public void OnclickButton()
    {
        if (!isHaveMicroPhone) return;

        aud.clip = Microphone.Start(device, true, 10, 10000);
        //aud.Play();
        //aud.timeSamples = Microphone.GetPosition(device);
        //aud.timeSamples = 0;
        Debug.Log("开始录音");
    }

    //开始播放按钮
    public void OnPlay()
    {
        aud.Play();
        aud.timeSamples = Microphone.GetPosition(device);//这里设置了之后就会近乎实时同步

        int min;
        int max;
        Microphone.GetDeviceCaps(device, out min,out max);
        //aud.timeSamples = 0;
        Debug.Log("开始播放"+min+" "+max);
    }




    private void Update()
    {
        //clipLength.text = "     clipLength:" + aud.clip.length;
        //devicePosition.text = " devicePosition:" + Microphone.GetPosition(device);
        //audioTime.text = "      audioTime:" + aud.time;
        //audioSampleTime.text = "audioSampleTime:" + aud.timeSamples;

        //Debug.Log("     clipLength:" + aud.clip.length);
        //Debug.Log(" devicePosition:" + Microphone.GetPosition(device));
        //Debug.Log("      audioTime:" + aud.time);
        //Debug.Log("audioSampleTime:" + aud.timeSamples);

        //aud.timeSamples = Microphone.GetPosition(device);
    }
}
复制代码

 

 

注意,实时录音播放后,可能会出现播放的采样点与录音的采样点的值越来越大的问题,因此可能需要在update函数中每隔一段时间进行处理。

 

posted @   小辉歌  阅读(6879)  评论(2编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示