音频解决
This commit is contained in:
parent
a096ca21c8
commit
d30a4e1d9c
@ -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()
|
||||
|
@ -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<float> _buffer = new RingBuffer<float>(4096);
|
||||
private RingBuffer<float> _buffer = new RingBuffer<float>(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<AudioSource>().PlayOneShot(audioClip);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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<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