mirror of
https://github.com/Dadechin/Unity-WebSocket.git
synced 2025-07-03 03:44:34 +00:00
148 lines
4.5 KiB
C#
148 lines
4.5 KiB
C#
using UnityEngine;
|
||
using Concentus.Structs;
|
||
using Concentus.Enums;
|
||
|
||
public class OpusMicRecorder : MonoBehaviour
|
||
{
|
||
[Header("Audio Settings")]
|
||
public int sampleRate = 16000;
|
||
public int frameSizeMs = 20; // 20 میلیثانیه
|
||
|
||
[Header("Bandpass Filter Frequencies (Hz)")]
|
||
[Range(50f, 1000f)]
|
||
public float lowFreq = 300f;
|
||
|
||
[Range(1000f, 8000f)]
|
||
public float highFreq = 3400f;
|
||
|
||
private AudioClip micClip;
|
||
private int frameSizeSamples;
|
||
private int lastSamplePos = 0;
|
||
|
||
private OpusEncoder encoder;
|
||
private BandpassFilter voiceFilter;
|
||
|
||
public delegate void EncodedAudioReady(byte[] data);
|
||
public event EncodedAudioReady OnEncodedAudio;
|
||
|
||
void Start()
|
||
{
|
||
frameSizeSamples = (sampleRate / 1000) * frameSizeMs;
|
||
|
||
encoder = new OpusEncoder(sampleRate, 1, OpusApplication.OPUS_APPLICATION_VOIP);
|
||
encoder.Bitrate = 16000;
|
||
|
||
micClip = Microphone.Start(null, true, 1, sampleRate);
|
||
|
||
// اعتبارسنجی ورودی فرکانس ها
|
||
if (lowFreq >= highFreq)
|
||
{
|
||
Debug.LogWarning("lowFreq باید کمتر از highFreq باشد. تنظیم به مقادیر پیشفرض.");
|
||
lowFreq = 300f;
|
||
highFreq = 3400f;
|
||
}
|
||
|
||
voiceFilter = new BandpassFilter(sampleRate, lowFreq, highFreq);
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
int micPos = Microphone.GetPosition(null);
|
||
int available = micPos - lastSamplePos;
|
||
if (available < 0) available += micClip.samples;
|
||
if (available < frameSizeSamples) return;
|
||
|
||
float[] samples = new float[frameSizeSamples];
|
||
micClip.GetData(samples, lastSamplePos);
|
||
lastSamplePos = (lastSamplePos + frameSizeSamples) % micClip.samples;
|
||
|
||
// آپدیت فیلتر اگر کاربر در Inspector مقادیر را تغییر داد
|
||
if (voiceFilter.LowFreq != lowFreq || voiceFilter.HighFreq != highFreq)
|
||
{
|
||
voiceFilter.SetFrequencies(lowFreq, highFreq);
|
||
}
|
||
|
||
voiceFilter.Process(samples);
|
||
|
||
short[] pcm = new short[frameSizeSamples];
|
||
for (int i = 0; i < frameSizeSamples; i++)
|
||
pcm[i] = (short)Mathf.Clamp(samples[i] * short.MaxValue, short.MinValue, short.MaxValue);
|
||
|
||
byte[] encoded = new byte[1275];
|
||
int encodedLength = encoder.Encode(pcm, 0, frameSizeSamples, encoded, 0, encoded.Length);
|
||
|
||
byte[] packet = new byte[encodedLength];
|
||
System.Buffer.BlockCopy(encoded, 0, packet, 0, encodedLength);
|
||
OnEncodedAudio?.Invoke(packet);
|
||
}
|
||
}
|
||
|
||
// کلاس فیلتر میانگذر (Bandpass) با قابلیت تنظیم داینامیک فرکانسها
|
||
public class BandpassFilter
|
||
{
|
||
private float a0, a1, a2, b1, b2;
|
||
private float z1, z2;
|
||
|
||
private float sampleRate;
|
||
public float LowFreq { get; private set; }
|
||
public float HighFreq { get; private set; }
|
||
|
||
public BandpassFilter(float sampleRate, float lowFreq, float highFreq)
|
||
{
|
||
this.sampleRate = sampleRate;
|
||
SetFrequencies(lowFreq, highFreq);
|
||
z1 = 0;
|
||
z2 = 0;
|
||
}
|
||
|
||
public void SetFrequencies(float lowFreq, float highFreq)
|
||
{
|
||
// اعتبارسنجی ساده
|
||
if (lowFreq <= 0) lowFreq = 50f;
|
||
if (highFreq >= sampleRate / 2f) highFreq = sampleRate / 2f - 100;
|
||
if (lowFreq >= highFreq)
|
||
{
|
||
Debug.LogWarning("BandpassFilter: lowFreq must be less than highFreq");
|
||
return;
|
||
}
|
||
|
||
LowFreq = lowFreq;
|
||
HighFreq = highFreq;
|
||
|
||
float omegaL = 2.0f * Mathf.PI * LowFreq / sampleRate;
|
||
float omegaH = 2.0f * Mathf.PI * HighFreq / sampleRate;
|
||
|
||
float centerFreq = (omegaL + omegaH) / 2.0f;
|
||
float bandwidth = omegaH - omegaL;
|
||
float Q = centerFreq / bandwidth;
|
||
|
||
float alpha = Mathf.Sin(centerFreq) / (2.0f * Q);
|
||
float cosW0 = Mathf.Cos(centerFreq);
|
||
float norm = 1.0f + alpha;
|
||
|
||
a0 = alpha / norm;
|
||
a1 = 0;
|
||
a2 = -alpha / norm;
|
||
b1 = -2.0f * cosW0 / norm;
|
||
b2 = (1.0f - alpha) / norm;
|
||
|
||
// ریست فیلتر برای جلوگیری از artifact بعد تغییر فرکانس
|
||
z1 = 0;
|
||
z2 = 0;
|
||
}
|
||
|
||
public void Process(float[] samples)
|
||
{
|
||
for (int i = 0; i < samples.Length; i++)
|
||
{
|
||
float input = samples[i];
|
||
float output = a0 * input + a1 * z1 + a2 * z2 - b1 * z1 - b2 * z2;
|
||
|
||
z2 = z1;
|
||
z1 = output;
|
||
|
||
samples[i] = output;
|
||
}
|
||
}
|
||
}
|