Unity 2018 - OnAudioFilterRead() 从缓冲区实时播放

Joa*_*erg 6 .net c# unity-game-engine

首先让我说这是我第一次在这里提出问题。如果我的代码格式不清楚或表达不佳,请告诉我,我很乐意进行调整。

我正在为要在 Unity (C#) 中使用的工具进行概念设计,以允许我们实时“流式传输”AudioSource 的输出,然后从不同的游戏对象播放相同的音频。从本质上讲,我们将一个并行信号存储在缓冲区中,而原始 AudioSource 功能如预期,将其播放的剪辑发送到混音器,就像正常一样。

为了实现这一点,我正在尝试使用音频线程和 OnAudioFilterRead() 函数。为了提取浮点音频数据以通过管道传输到 OnAudioFilterRead(),我正在使用 AudioSource.GetOutputData,将其存储到一个数组中,然后将该数组提供给音频过滤器。我还创建了一个空的 AudioClip,从同一个数组中设置它的数据并在新的 GameObject 上播放该 AudioClip。

现在我可以从新的 GameObject 播放音频,但结果非常失真和令人不快,我将其归结为以下一项或多项;

  1. 正在以不同步的方式写入/读取音频缓冲区

  2. Unity 采样率导致剪辑出现问题。尝试过 44.1khz 和 48khz 的结果都低于标准,以及在剪辑上使用导入设置。Unity 2018.2 的文档非常薄弱,许多旧方法现已弃用。

  3. 外星人。

理想情况下,我将能够在没有可听伪影的情况下回传音频。我可以忍受一些延迟(~30-50ms),但音频质量不差。

下面是正在使用的代码。该脚本附加到 GameObject 上,该对象将从原始发射器接收此音频信号,并且它有自己的 AudioSource 用于播放和定位。

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]
public class ECO_receiver : MonoBehaviour {


public AudioSource emitterSend;
private AudioSource audioSource;    
public AudioClip streamedClip;

public bool debugSampleData;
private float[] sampleDataArray;
public float sampleSize;
public float sampleFreq;

private int outputSampleRate;
public bool _bufferReady;                         


void Start () {

    audioSource = GetComponent<AudioSource>();
    sampleSize = emitterSend.clip.samples;
    sampleFreq = emitterSend.clip.frequency;
    sampleDataArray = new float[2048];
    streamedClip = AudioClip.Create("audiostream", (int)sampleSize, 1, (int)sampleFreq, false);
    audioSource.clip = streamedClip;
    audioSource.Play();
    _bufferReady = true;
}

 private void FixedUpdate()
{

    if (emitterSend.isPlaying && _bufferReady == true)
    {
        FillAudioBuffer();           

    }
    else if (!emitterSend.isPlaying)
    {
        Debug.Log("Emitter is not playing!");
    }

    if (debugSampleData && sampleDataArray != null && Input.GetKeyDown("p"))
    {
        for (int i = 0; i < sampleDataArray.Length; i++)
        {
        Debug.Log(sampleDataArray[i]);
        }

    }
    else if (sampleDataArray == null)
    {
        Debug.Log("No data in array!");
    }


}    

void FillAudioBuffer()
{

    emitterSend.GetOutputData(sampleDataArray, 0);             
    streamedClip.SetData(sampleDataArray, 0);
    _bufferReady = false;
}

void OnAudioFilterRead(float[] data, int channels)
{
    if (!_bufferReady)
    {

        for (int i = 0; i < data.Length; i++)
        {
            data[i] = (float)sampleDataArray[i];           

        }

        _bufferReady = true;
        }
    }        


}
Run Code Online (Sandbox Code Playgroud)

非常感谢我可能被授予的任何智慧!谢谢!