From d30a4e1d9c5372e682d584929f2edfbeab16a036 Mon Sep 17 00:00:00 2001 From: sin365 <353374337@qq.com> Date: Tue, 18 Feb 2025 13:21:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9F=B3=E9=A2=91=E8=A7=A3=E5=86=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Scripts/UEssgee.cs | 4 +- .../UEssgeeInterface/UEGSoundPlayer.cs | 300 +++++++++++++++--- 2 files changed, 265 insertions(+), 39 deletions(-) diff --git a/Assets/Scripts/UEssgee.cs b/Assets/Scripts/UEssgee.cs index d7ee5ac..778931d 100644 --- a/Assets/Scripts/UEssgee.cs +++ b/Assets/Scripts/UEssgee.cs @@ -44,9 +44,9 @@ public class Essgeeinit : MonoBehaviour uegResources = new UEGResources(); uegLog = new UEGLog(); InitAll(uegResources, Application.persistentDataPath); - LoadAndRunCartridge("G:/psjapa.sms"); + //LoadAndRunCartridge("G:/psjapa.sms"); //LoadAndRunCartridge("G:/Ninja_Gaiden_(UE)_type_A_[!].sms"); - //LoadAndRunCartridge("G:/SML2.gb"); + LoadAndRunCartridge("G:/SML2.gb"); } void OnDisable() diff --git a/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs b/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs index 434b3c2..9909c28 100644 --- a/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs +++ b/Assets/Scripts/UEssgeeInterface/UEGSoundPlayer.cs @@ -1,26 +1,60 @@ using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; using UnityEngine; public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer { [SerializeField] private AudioSource m_as; - private RingBuffer _buffer = new RingBuffer(4096); + private RingBuffer _buffer = new RingBuffer(44100*2); private TimeSpan lastElapsed; public double audioFPS { get; private set; } + public bool IsRecording { get; private set; } + float lastData = 0; + private AudioClip audioClip; + private int writePos = 0; + private float[] buffer; - void Awake() + void Start() { - AudioClip dummy = AudioClip.Create("dummy", 1, 2, AudioSettings.outputSampleRate, false); - //AudioClip dummy = AudioClip.Create("dummy", 1, 2, 44100, false); - dummy.SetData(new float[] { 1, 1 }, 0); - m_as.clip = dummy; - m_as.loop = true; - m_as.spatialBlend = 1; + GetComponent().PlayOneShot(audioClip); } + private Queue sampleQueue = new Queue(); + + // 外部填充数据 + public void AddData(float[] data) + { + lock (sampleQueue) + { + foreach (var sample in data) + { + sampleQueue.Enqueue(sample); + } + } + } + + // Unity 音频线程回调 + void OnAudioFilterRead(float[] data, int channels) + { + lock (sampleQueue) + { + for (int i = 0; i < data.Length; i++) + { + if (sampleQueue.Count > 0) + data[i] = sampleQueue.Dequeue(); + else + data[i] = 0; // 无数据时静音 + } + } + } + + public void Initialize() { if (!m_as.isPlaying) @@ -37,25 +71,6 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer } } - void OnAudioFilterRead(float[] data, int channels) - { - if (!Essgeeinit.bInGame) return; - int step = channels; - for (int i = 0; i < data.Length; i += step) - { - float rawFloat = lastData; - if (_buffer.TryRead(out float rawData)) - { - rawFloat = rawData; - } - - data[i] = rawFloat; - for (int fill = 1; fill < step; fill++) - data[i + fill] = rawFloat; - lastData = rawFloat; - } - } - public unsafe void SubmitSamples(short* buffer, short*[] ChannelSamples, int samples_a) { var current = Essgeeinit.sw.Elapsed; @@ -63,22 +78,30 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer lastElapsed = current; audioFPS = 1d / delta.TotalSeconds; - - //for (int i = 0; i < samples_a; i++) + //for (int i = 0; i < samples_a; i += 1) //{ - // short left = BitConverter.ToInt16(buffer, i * 2 * 2); - // //short right = BitConverter.ToInt16(buffer, i * 2 * 2 + 2); - // _buffer.Write(left / 32767.0f); - // //_buffer.Write(right / 32767.0f); + // //_buffer.Write(((i % 2 == 0)?-1:1) * buffer[i] / 32767.0f); + // _buffer.Write(buffer[i] / 32767.0f); + //} - for (int i = 0; i < samples_a; i += 2) + AddData(ConvertShortToFloat(buffer, samples_a)); + + if (IsRecording) { - _buffer.Write(buffer[i] / 32767.0f); - //_buffer.Write(buffer[i] / 32767.0f); + dataChunk.AddSampleData(buffer, samples_a); + waveHeader.FileLength += (uint)samples_a; } } - + unsafe float[] ConvertShortToFloat(short* input,int length) + { + float[] output = new float[length]; + for (int i = 0; i < length; i++) + { + output[i] = input[i] / 32768.0f; + } + return output; + } public void BufferWirte(int Off, byte[] Data) { } @@ -96,4 +119,207 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer return; m_as.volume = Vol; } + + + void Update() + { + if (Input.GetKeyDown(KeyCode.F3)) + { + BeginRecording(); + Debug.Log("录制"); + } + if (Input.GetKeyDown(KeyCode.F4)) + { + SaveRecording("D:/1.wav"); + Debug.Log("保存"); + } + } + 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 chunkData = new List(); + + 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 chunkBytes = new List(); + + 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 WaveData { get; private set; } + + public DataChunk() + { + ChunkId = chunkId; + ChunkSize = 0; + WaveData = new List(); + } + + public byte[] GetBytes() + { + List chunkBytes = new List(); + + 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); + } + public unsafe void AddSampleData(short* stereoBuffer,int lenght) + { + for (int i = 0; i < lenght; i++) + { + WaveData.Add(stereoBuffer[i]); + } + + ChunkSize += (uint)(lenght * 2); + } + } }