Unity3d 麦克风、增益值和频谱值不使用Unity同步

Unity3d 麦克风、增益值和频谱值不使用Unity同步,unity3d,audio-recording,Unity3d,Audio Recording,我正在制作一个简单的语音可视化程序。我的目标是: 回放麦克风输入 实时显示语音频谱和增益 这是我的密码: using System.Collections; using System.Collections.Generic; using UnityEngine; public class VisualizeVoice : MonoBehaviour { private const int NUM_SPECTRUM_SAMPLES = 256; private const int

我正在制作一个简单的语音可视化程序。我的目标是:

  • 回放麦克风输入

  • 实时显示语音频谱和增益

  • 这是我的密码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class VisualizeVoice : MonoBehaviour
    {
        private const int NUM_SPECTRUM_SAMPLES = 256;
        private const int NUM_SPECTRUM_BARS = 32;
        private const int NUM_PCM_SAMPLES = 16000;
        private const float BAR_DROP_SPEED = 1e-3f;
        private const int NUM_SAMPLES_TO_AVERAGE = 8;
    
        private string _deviceName;
        private float[] _spectrumData = new float[NUM_SPECTRUM_SAMPLES];
        private float[] _fPCMData = new float[NUM_PCM_SAMPLES];
        private float _gain = 0;
    
        private AudioClip _audio;           // Audio from microphone
        private AudioSource _playback;      // To play the audio from microphone
    
        // For visualization
        private GameObject[] _spectrumBars = new GameObject[NUM_SPECTRUM_BARS];
        private GameObject _gainBar;
    
        // Start is called before the first frame update
        void Start()
        {
            if (Microphone.devices.Length == 0) {
                Debug.LogError("No Microphone");
                return;
            }
            _deviceName = Microphone.devices[0];
            Debug.Log("Current microphone is " + _deviceName);
    
            if ((_playback = this.GetComponent<AudioSource>()) == null) {
                _playback = this.gameObject.AddComponent<AudioSource>();
            }
            _playback.loop = true;
            _playback.bypassEffects = true;
            _playback.bypassListenerEffects = true;
            _playback.bypassReverbZones = true;
            _playback.priority = 0;
            _playback.pitch = 1;
            _playback.clip = _audio = Microphone.Start(_deviceName, true, 1, AudioSettings.outputSampleRate);
            // Sync microphone and playback, but it always fails
            float waitTime = 0;
            while (!(Microphone.GetPosition(_deviceName) > 0) && waitTime <= 2)
                waitTime += Time.deltaTime;
            if (waitTime > 2) {
                Debug.LogError("time out waiting for microphone");
            }
            _playback.Play();
    
            InitVisualization();
        }
    
        // Update is called once per frame
        void Update()
        {
            // Get PCM data and calculate gain
            var audioPosition = Microphone.GetPosition(_deviceName);
            _audio.GetData(_fPCMData, audioPosition);
            UpdateGain();
            // Get spectrum data
            _playback.GetSpectrumData(_spectrumData, 0, FFTWindow.BlackmanHarris);
            // Update visualization
            UpdateVisualization();
        }
    
        private void InitVisualization() 
        {
            // Initialize spectrum bars
            for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
                _spectrumBars[ibar] = GameObject.CreatePrimitive(PrimitiveType.Cube);
                _spectrumBars[ibar].transform.parent = this.transform;
                _spectrumBars[ibar].transform.localPosition = new Vector3(ibar, 0, 0);
                _spectrumBars[ibar].transform.localScale = new Vector3(1, 0, 1);
            }
            // Initialize gain bar
            _gainBar = GameObject.CreatePrimitive(PrimitiveType.Cube);
            _gainBar.transform.parent = this.transform;
            _gainBar.transform.localPosition = new Vector3(-5, 0, 0);
            _gainBar.transform.localScale = new Vector3(4, 0, 1);
    
            // Overall dimension
            this.transform.localScale = new Vector3(0.2f, 10.0f, 0.2f);
        }
    
        private void UpdateVisualization() 
        {
            // Update spectrum bars
            int nSamplesPerBar = NUM_SPECTRUM_SAMPLES / NUM_SPECTRUM_BARS;
            for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
                // Calculate value of each bar
                float value = 0;
                for (int isample = 0; isample < nSamplesPerBar; isample++) {
                    value += _spectrumData[ibar * nSamplesPerBar + isample];
                }
                value /= nSamplesPerBar;
                // Use current value if increasing, or slowly drop previous value if decreasing
                float prevValue = _spectrumBars[ibar].transform.localScale.y;
                if (value < prevValue)
                    value = prevValue - BAR_DROP_SPEED;
                // Y scale is set to value
                _spectrumBars[ibar].transform.localScale = new Vector3(1, value, 1);
            }
            // Update gain bar
            _gainBar.transform.localScale = new Vector3(4, _gain, 1);
        }
    
        private void UpdateGain() 
        {
            _gain = 0;
            for(int i = 0; i < NUM_SAMPLES_TO_AVERAGE; i++) {
                _gain += Mathf.Abs(_fPCMData[NUM_PCM_SAMPLES - i - 1]);
            }
            _gain /= NUM_SAMPLES_TO_AVERAGE;
        }
    }
    
    使用系统集合;
    使用System.Collections.Generic;
    使用UnityEngine;
    公共阶层的声音:单一行为
    {
    私有常量int NUM_SPECTRUM_SAMPLES=256;
    私有常数int NUM_SPECTRUM_bar=32;
    私有常量int NUM_PCM_SAMPLES=16000;
    专用恒流浮动条下降速度=1e-3f;
    private const int NUM_SAMPLES_TO_AVERAGE=8;
    私有字符串_deviceName;
    私有浮点[]_spectrumData=新浮点[NUM_SPECTRUM_SAMPLES];
    私有浮点[]_fPCMData=新浮点[NUM_PCM_SAMPLES];
    私人浮动_增益=0;
    专用音频剪辑_audio;//来自麦克风的音频
    专用音频源_playback;//从麦克风播放音频
    //用于可视化
    私有GameObject[]_spectrumBars=新GameObject[NUM_SPECTRUM_BARS];
    私人游戏对象(u gainBar),;
    //在第一帧更新之前调用Start
    void Start()
    {
    如果(麦克风.devices.Length==0){
    调试日志错误(“无麦克风”);
    返回;
    }
    _deviceName=麦克风。设备[0];
    Log(“当前麦克风为”+_deviceName);
    如果(_playback=this.GetComponent())==null){
    _播放=this.gameObject.AddComponent();
    }
    _playback.loop=true;
    _playback.bypassEffects=true;
    _playback.bypassListenerEffects=true;
    _playback.bzones=true;
    _播放优先级=0;
    _playback.pitch=1;
    _playback.clip=\u audio=麦克风.Start(\u deviceName,true,1,AudioSettings.outputSampleRate);
    //同步麦克风和播放,但总是失败
    浮动等待时间=0;
    同时(!(麦克风.GetPosition(_deviceName)>0)和等待时间2){
    Debug.LogError(“等待麦克风超时”);
    }
    _playback.Play();
    初始化可视化();
    }
    //每帧调用一次更新
    无效更新()
    {
    //获取PCM数据并计算增益
    var audioPosition=麦克风.GetPosition(_deviceName);
    _获取数据(_fPCMData,audioPosition);
    UpdateGain();
    //获取光谱数据
    _playback.GetSpectrumData(_spectrumData,0,FFTWindow.BlackmanHarris);
    //更新可视化
    UpdateVisualization();
    }
    私有void InitVisualization()
    {
    //初始化频谱条
    对于(int-ibar=0;ibar
    以下是我的问题:

  • 当(!microscope.GetPosition(_deviceName)>0)时,我无法使用
    以避免从麦克风到扬声器的延迟。如果我使用它,我的应用程序就会冻结。如果我添加允许超时的代码,它每次都有超时

  • 增益条似乎与我的声音无关。我不知道我的计算是否正确

  • 我不确定是否需要在计算收益时对多个样本进行平均,以及需要对多少样本进行平均。我以后需要这个增益值来检测静默时刻和剪切音频数据

  • 对1

    你可以。Unity允许将
    Start
    定义为

    通过这种方式,您可以使用非阻塞

    while (!Microphone.GetPosition(_deviceName) > 0))
    {
        yield return null;
    }
    
    while (!Microphone.GetPosition(_deviceName) > 0))
    {
        yield return null;
    }