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
以下是我的问题:
代码>以避免从麦克风到扬声器的延迟。如果我使用它,我的应用程序就会冻结。如果我添加允许超时的代码,它每次都有超时
Start
定义为
通过这种方式,您可以使用非阻塞
while (!Microphone.GetPosition(_deviceName) > 0))
{
yield return null;
}
while (!Microphone.GetPosition(_deviceName) > 0))
{
yield return null;
}