2025-01-03 19:53:38 +08:00
|
|
|
|
using System;
|
2025-02-18 13:21:54 +08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
2025-01-03 01:07:11 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
|
|
|
|
|
{
|
2025-01-03 19:53:38 +08:00
|
|
|
|
[SerializeField]
|
|
|
|
|
private AudioSource m_as;
|
2025-02-18 17:44:30 +08:00
|
|
|
|
private RingBuffer<float> _buffer = new RingBuffer<float>(44100 * 2);
|
2025-01-03 19:53:38 +08:00
|
|
|
|
private TimeSpan lastElapsed;
|
|
|
|
|
public double audioFPS { get; private set; }
|
2025-02-18 13:21:54 +08:00
|
|
|
|
public bool IsRecording { get; private set; }
|
|
|
|
|
|
2025-02-18 17:44:30 +08:00
|
|
|
|
void Awake()
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 17:44:30 +08:00
|
|
|
|
// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
|
|
|
|
|
AudioConfiguration config = AudioSettings.GetConfiguration();
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
|
|
|
|
|
config.sampleRate = 44100; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ 44100Hz
|
|
|
|
|
config.numRealVoices = 32; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƵԴ<C6B5><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>
|
|
|
|
|
config.numVirtualVoices = 512; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƵԴ<C6B5><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>
|
|
|
|
|
config.dspBufferSize = 1024; // <20><><EFBFBD><EFBFBD> DSP <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>
|
|
|
|
|
config.speakerMode = AudioSpeakerMode.Stereo; // <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
// Ӧ<><D3A6><EFBFBD>µ<EFBFBD><C2B5><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>
|
|
|
|
|
if (AudioSettings.Reset(config))
|
|
|
|
|
{
|
|
|
|
|
Debug.Log("Audio settings updated successfully.");
|
|
|
|
|
Debug.Log("Sample Rate: " + config.sampleRate + "Hz");
|
|
|
|
|
Debug.Log("Speaker Mode: " + config.speakerMode);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Failed to update audio settings.");
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-03 19:53:38 +08:00
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-18 13:21:54 +08:00
|
|
|
|
private Queue<float> sampleQueue = new Queue<float>();
|
|
|
|
|
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-18 13:21:54 +08:00
|
|
|
|
// Unity <20><>Ƶ<EFBFBD>̻߳ص<CCBB>
|
|
|
|
|
void OnAudioFilterRead(float[] data, int channels)
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 17:44:30 +08:00
|
|
|
|
for (int i = 0; i < data.Length; i++)
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 17:44:30 +08:00
|
|
|
|
if (_buffer.TryRead(out float rawData))
|
|
|
|
|
data[i] = rawData;
|
|
|
|
|
else
|
|
|
|
|
data[i] = 0; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>
|
2025-01-03 19:53:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-18 13:21:54 +08:00
|
|
|
|
|
|
|
|
|
public void Initialize()
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 13:21:54 +08:00
|
|
|
|
if (!m_as.isPlaying)
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 13:21:54 +08:00
|
|
|
|
m_as.Play();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-18 13:21:54 +08:00
|
|
|
|
public void StopPlay()
|
|
|
|
|
{
|
|
|
|
|
if (m_as.isPlaying)
|
|
|
|
|
{
|
|
|
|
|
m_as.Stop();
|
2025-01-03 19:53:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-08 10:12:58 +08:00
|
|
|
|
public unsafe void SubmitSamples(short* buffer, short*[] ChannelSamples, int samples_a)
|
2025-01-03 01:07:11 +08:00
|
|
|
|
{
|
2025-01-03 19:53:38 +08:00
|
|
|
|
var current = Essgeeinit.sw.Elapsed;
|
|
|
|
|
var delta = current - lastElapsed;
|
|
|
|
|
lastElapsed = current;
|
|
|
|
|
audioFPS = 1d / delta.TotalSeconds;
|
2025-01-03 01:07:11 +08:00
|
|
|
|
|
2025-02-18 17:44:30 +08:00
|
|
|
|
for (int i = 0; i < samples_a; i += 1)
|
2025-01-03 19:53:38 +08:00
|
|
|
|
{
|
2025-02-18 17:44:30 +08:00
|
|
|
|
_buffer.Write(buffer[i] / 32767.0f);
|
|
|
|
|
|
2025-02-18 13:21:54 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
public void BufferWirte(int Off, byte[] Data)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void GetCurrentPosition(out int play_position, out int write_position)
|
|
|
|
|
{
|
|
|
|
|
play_position = 0;
|
|
|
|
|
write_position = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetVolume(int Vol)
|
|
|
|
|
{
|
|
|
|
|
//TODO <20><><EFBFBD><EFBFBD>
|
2025-01-03 19:53:38 +08:00
|
|
|
|
if (m_as)
|
|
|
|
|
return;
|
|
|
|
|
m_as.volume = Vol;
|
2025-01-03 01:07:11 +08:00
|
|
|
|
}
|
2025-02-18 13:21:54 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
|
{
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F3))
|
|
|
|
|
{
|
|
|
|
|
BeginRecording();
|
|
|
|
|
Debug.Log("¼<><C2BC>");
|
|
|
|
|
}
|
|
|
|
|
if (Input.GetKeyDown(KeyCode.F4))
|
|
|
|
|
{
|
|
|
|
|
SaveRecording("D:/1.wav");
|
|
|
|
|
Debug.Log("<22><><EFBFBD><EFBFBD>");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
WaveHeader waveHeader;
|
|
|
|
|
FormatChunk formatChunk;
|
|
|
|
|
DataChunk dataChunk;
|
|
|
|
|
public void BeginRecording()
|
|
|
|
|
{
|
|
|
|
|
waveHeader = new WaveHeader();
|
|
|
|
|
formatChunk = new FormatChunk(44100, 2);
|
|
|
|
|
dataChunk = new DataChunk();
|
|
|
|
|
waveHeader.FileLength += formatChunk.Length();
|
|
|
|
|
|
|
|
|
|
IsRecording = true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void SaveRecording(string filename)
|
|
|
|
|
{
|
|
|
|
|
using (FileStream file = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
|
|
|
|
{
|
|
|
|
|
file.Write(waveHeader.GetBytes(), 0, (int)waveHeader.Length());
|
|
|
|
|
file.Write(formatChunk.GetBytes(), 0, (int)formatChunk.Length());
|
|
|
|
|
file.Write(dataChunk.GetBytes(), 0, (int)dataChunk.Length());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IsRecording = false;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class WaveHeader
|
|
|
|
|
{
|
|
|
|
|
const string fileTypeId = "RIFF";
|
|
|
|
|
const string mediaTypeId = "WAVE";
|
|
|
|
|
|
|
|
|
|
public string FileTypeId { get; private set; }
|
|
|
|
|
public uint FileLength { get; set; }
|
|
|
|
|
public string MediaTypeId { get; private set; }
|
|
|
|
|
|
|
|
|
|
public WaveHeader()
|
|
|
|
|
{
|
|
|
|
|
FileTypeId = fileTypeId;
|
|
|
|
|
MediaTypeId = mediaTypeId;
|
|
|
|
|
FileLength = 4; /* Minimum size is always 4 bytes */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] GetBytes()
|
|
|
|
|
{
|
|
|
|
|
List<byte> chunkData = new List<byte>();
|
|
|
|
|
|
|
|
|
|
chunkData.AddRange(Encoding.ASCII.GetBytes(FileTypeId));
|
|
|
|
|
chunkData.AddRange(BitConverter.GetBytes(FileLength));
|
|
|
|
|
chunkData.AddRange(Encoding.ASCII.GetBytes(MediaTypeId));
|
|
|
|
|
|
|
|
|
|
return chunkData.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint Length()
|
|
|
|
|
{
|
|
|
|
|
return (uint)GetBytes().Length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class FormatChunk
|
|
|
|
|
{
|
|
|
|
|
const string chunkId = "fmt ";
|
|
|
|
|
|
|
|
|
|
ushort bitsPerSample, channels;
|
|
|
|
|
uint frequency;
|
|
|
|
|
|
|
|
|
|
public string ChunkId { get; private set; }
|
|
|
|
|
public uint ChunkSize { get; private set; }
|
|
|
|
|
public ushort FormatTag { get; private set; }
|
|
|
|
|
|
|
|
|
|
public ushort Channels
|
|
|
|
|
{
|
|
|
|
|
get { return channels; }
|
|
|
|
|
set { channels = value; RecalcBlockSizes(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint Frequency
|
|
|
|
|
{
|
|
|
|
|
get { return frequency; }
|
|
|
|
|
set { frequency = value; RecalcBlockSizes(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint AverageBytesPerSec { get; private set; }
|
|
|
|
|
public ushort BlockAlign { get; private set; }
|
|
|
|
|
|
|
|
|
|
public ushort BitsPerSample
|
|
|
|
|
{
|
|
|
|
|
get { return bitsPerSample; }
|
|
|
|
|
set { bitsPerSample = value; RecalcBlockSizes(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FormatChunk()
|
|
|
|
|
{
|
|
|
|
|
ChunkId = chunkId;
|
|
|
|
|
ChunkSize = 16;
|
|
|
|
|
FormatTag = 1; /* MS PCM (Uncompressed wave file) */
|
|
|
|
|
Channels = 2; /* Default to stereo */
|
|
|
|
|
Frequency = 44100; /* Default to 44100hz */
|
|
|
|
|
BitsPerSample = 16; /* Default to 16bits */
|
|
|
|
|
RecalcBlockSizes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FormatChunk(int frequency, int channels) : this()
|
|
|
|
|
{
|
|
|
|
|
Channels = (ushort)channels;
|
|
|
|
|
Frequency = (ushort)frequency;
|
|
|
|
|
RecalcBlockSizes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RecalcBlockSizes()
|
|
|
|
|
{
|
|
|
|
|
BlockAlign = (ushort)(channels * (bitsPerSample / 8));
|
|
|
|
|
AverageBytesPerSec = frequency * BlockAlign;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] GetBytes()
|
|
|
|
|
{
|
|
|
|
|
List<byte> chunkBytes = new List<byte>();
|
|
|
|
|
|
|
|
|
|
chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(FormatTag));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(Channels));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(Frequency));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(AverageBytesPerSec));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(BlockAlign));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(BitsPerSample));
|
|
|
|
|
|
|
|
|
|
return chunkBytes.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint Length()
|
|
|
|
|
{
|
|
|
|
|
return (uint)GetBytes().Length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class DataChunk
|
|
|
|
|
{
|
|
|
|
|
const string chunkId = "data";
|
|
|
|
|
|
|
|
|
|
public string ChunkId { get; private set; }
|
|
|
|
|
public uint ChunkSize { get; set; }
|
|
|
|
|
public List<short> WaveData { get; private set; }
|
|
|
|
|
|
|
|
|
|
public DataChunk()
|
|
|
|
|
{
|
|
|
|
|
ChunkId = chunkId;
|
|
|
|
|
ChunkSize = 0;
|
|
|
|
|
WaveData = new List<short>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] GetBytes()
|
|
|
|
|
{
|
|
|
|
|
List<byte> chunkBytes = new List<byte>();
|
|
|
|
|
|
|
|
|
|
chunkBytes.AddRange(Encoding.ASCII.GetBytes(ChunkId));
|
|
|
|
|
chunkBytes.AddRange(BitConverter.GetBytes(ChunkSize));
|
|
|
|
|
byte[] bufferBytes = new byte[WaveData.Count * 2];
|
|
|
|
|
Buffer.BlockCopy(WaveData.ToArray(), 0, bufferBytes, 0, bufferBytes.Length);
|
|
|
|
|
chunkBytes.AddRange(bufferBytes.ToList());
|
|
|
|
|
|
|
|
|
|
return chunkBytes.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public uint Length()
|
|
|
|
|
{
|
|
|
|
|
return (uint)GetBytes().Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddSampleData(short[] stereoBuffer)
|
|
|
|
|
{
|
|
|
|
|
WaveData.AddRange(stereoBuffer);
|
|
|
|
|
|
|
|
|
|
ChunkSize += (uint)(stereoBuffer.Length * 2);
|
|
|
|
|
}
|
2025-02-18 17:44:30 +08:00
|
|
|
|
public unsafe void AddSampleData(short* stereoBuffer, int lenght)
|
2025-02-18 13:21:54 +08:00
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < lenght; i++)
|
|
|
|
|
{
|
|
|
|
|
WaveData.Add(stereoBuffer[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChunkSize += (uint)(lenght * 2);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-03 01:07:11 +08:00
|
|
|
|
}
|