音频解决
This commit is contained in:
parent
a096ca21c8
commit
d30a4e1d9c
@ -44,9 +44,9 @@ public class Essgeeinit : MonoBehaviour
|
|||||||
uegResources = new UEGResources();
|
uegResources = new UEGResources();
|
||||||
uegLog = new UEGLog();
|
uegLog = new UEGLog();
|
||||||
InitAll(uegResources, Application.persistentDataPath);
|
InitAll(uegResources, Application.persistentDataPath);
|
||||||
LoadAndRunCartridge("G:/psjapa.sms");
|
//LoadAndRunCartridge("G:/psjapa.sms");
|
||||||
//LoadAndRunCartridge("G:/Ninja_Gaiden_(UE)_type_A_[!].sms");
|
//LoadAndRunCartridge("G:/Ninja_Gaiden_(UE)_type_A_[!].sms");
|
||||||
//LoadAndRunCartridge("G:/SML2.gb");
|
LoadAndRunCartridge("G:/SML2.gb");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDisable()
|
void OnDisable()
|
||||||
|
@ -1,26 +1,60 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
|
public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private AudioSource m_as;
|
private AudioSource m_as;
|
||||||
private RingBuffer<float> _buffer = new RingBuffer<float>(4096);
|
private RingBuffer<float> _buffer = new RingBuffer<float>(44100*2);
|
||||||
private TimeSpan lastElapsed;
|
private TimeSpan lastElapsed;
|
||||||
public double audioFPS { get; private set; }
|
public double audioFPS { get; private set; }
|
||||||
|
public bool IsRecording { get; private set; }
|
||||||
|
|
||||||
float lastData = 0;
|
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);
|
GetComponent<AudioSource>().PlayOneShot(audioClip);
|
||||||
//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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Queue<float> sampleQueue = new Queue<float>();
|
||||||
|
|
||||||
|
// 外部填充数据
|
||||||
|
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()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
if (!m_as.isPlaying)
|
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)
|
public unsafe void SubmitSamples(short* buffer, short*[] ChannelSamples, int samples_a)
|
||||||
{
|
{
|
||||||
var current = Essgeeinit.sw.Elapsed;
|
var current = Essgeeinit.sw.Elapsed;
|
||||||
@ -63,22 +78,30 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
|
|||||||
lastElapsed = current;
|
lastElapsed = current;
|
||||||
audioFPS = 1d / delta.TotalSeconds;
|
audioFPS = 1d / delta.TotalSeconds;
|
||||||
|
|
||||||
|
//for (int i = 0; i < samples_a; i += 1)
|
||||||
//for (int i = 0; i < samples_a; i++)
|
|
||||||
//{
|
//{
|
||||||
// short left = BitConverter.ToInt16(buffer, i * 2 * 2);
|
// //_buffer.Write(((i % 2 == 0)?-1:1) * buffer[i] / 32767.0f);
|
||||||
// //short right = BitConverter.ToInt16(buffer, i * 2 * 2 + 2);
|
// _buffer.Write(buffer[i] / 32767.0f);
|
||||||
// _buffer.Write(left / 32767.0f);
|
|
||||||
// //_buffer.Write(right / 32767.0f);
|
|
||||||
//}
|
//}
|
||||||
|
|
||||||
for (int i = 0; i < samples_a; i += 2)
|
AddData(ConvertShortToFloat(buffer, samples_a));
|
||||||
{
|
|
||||||
_buffer.Write(buffer[i] / 32767.0f);
|
|
||||||
//_buffer.Write(buffer[i] / 32767.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (IsRecording)
|
||||||
|
{
|
||||||
|
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)
|
public void BufferWirte(int Off, byte[] Data)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -96,4 +119,207 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
|
|||||||
return;
|
return;
|
||||||
m_as.volume = Vol;
|
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<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);
|
||||||
|
}
|
||||||
|
public unsafe void AddSampleData(short* stereoBuffer,int lenght)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < lenght; i++)
|
||||||
|
{
|
||||||
|
WaveData.Add(stereoBuffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkSize += (uint)(lenght * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user