音频处理指针化

This commit is contained in:
sin365 2025-02-08 10:12:58 +08:00
parent bf0acee294
commit 2303b0c5f6
7 changed files with 229 additions and 55 deletions

View File

@ -6,10 +6,13 @@ namespace Essgee.Emulation.Audio
{ {
public CGBAudio() public CGBAudio()
{ {
channelSampleBuffer = new List<short>[numChannels]; //channelSampleBuffer = new List<short>[numChannels];
for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>(); //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
mixedSampleBuffer = new List<short>(); //改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
channel1 = new Square(true); channel1 = new Square(true);
channel2 = new Square(false); channel2 = new Square(false);

View File

@ -4,10 +4,11 @@ using Essgee.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
namespace Essgee.Emulation.Audio namespace Essgee.Emulation.Audio
{ {
public partial class DMGAudio : IAudio public unsafe partial class DMGAudio : IAudio
{ {
// https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware
// http://emudev.de/gameboy-emulator/bleeding-ears-time-to-add-audio/ // http://emudev.de/gameboy-emulator/bleeding-ears-time-to-add-audio/
@ -34,8 +35,55 @@ namespace Essgee.Emulation.Audio
protected int frameSequencerReload, frameSequencerCounter, frameSequencer; protected int frameSequencerReload, frameSequencerCounter, frameSequencer;
protected List<short>[] channelSampleBuffer; //protected List<short>[] channelSampleBuffer;
protected List<short> mixedSampleBuffer; #region //指针化 channelSampleBuffer
static short[][] channelSampleBuffer_src;
static GCHandle[] channelSampleBuffer_handle;
public static short*[] channelSampleBuffer;
public static int[] channelSampleBufferLength;
public static int channelSampleBuffer_writePos;
public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null;
public static void channelSampleBuffer_Init(int length1, int Lenght2)
{
if (channelSampleBuffer_src != null)
{
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
channelSampleBuffer_handle[i].ReleaseGCHandle();
}
channelSampleBuffer_src = new short[length1][];
channelSampleBuffer_handle = new GCHandle[length1];
channelSampleBuffer = new short*[length1];
channelSampleBuffer_writePos = 0;
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
{
channelSampleBuffer_src[i] = new short[Lenght2];
channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]);
}
}
#endregion
//protected List<short> mixedSampleBuffer;
#region //指针化 mixedSampleBuffer
short[] mixedSampleBuffer_src;
GCHandle mixedSampleBuffer_handle;
public short* mixedSampleBuffer;
public int mixedSampleBufferLength;
public int mixedSampleBuffer_writePos;
public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null;
public short[] mixedSampleBuffer_set
{
set
{
mixedSampleBuffer_handle.ReleaseGCHandle();
mixedSampleBuffer_src = value;
mixedSampleBufferLength = value.Length;
mixedSampleBuffer_writePos = 0;
mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer);
}
}
#endregion
public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples; public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); } public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); }
@ -60,10 +108,14 @@ namespace Essgee.Emulation.Audio
public DMGAudio() public DMGAudio()
{ {
channelSampleBuffer = new List<short>[numChannels]; //channelSampleBuffer = new List<short>[numChannels];
for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>(); //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
//改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
mixedSampleBuffer = new List<short>();
channel1 = new Square(true); channel1 = new Square(true);
channel2 = new Square(false); channel2 = new Square(false);
@ -263,13 +315,22 @@ namespace Essgee.Emulation.Audio
sampleCycleCount -= cyclesPerSample; sampleCycleCount -= cyclesPerSample;
} }
if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) //if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels))
if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels))
{ {
//EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
// numChannels,
// channelSampleBuffer.Select(x => x.ToArray()).ToArray(),
// new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
// mixedSampleBuffer.ToArray());
EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
numChannels, numChannels,
channelSampleBuffer.Select(x => x.ToArray()).ToArray(), channelSampleBuffer,
new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
mixedSampleBuffer.ToArray()); mixedSampleBuffer,
mixedSampleBuffer_writePos);
OnEnqueueSamples(eventArgs); OnEnqueueSamples(eventArgs);
FlushSamples(); FlushSamples();
@ -295,10 +356,18 @@ namespace Essgee.Emulation.Audio
var ch3 = (short)(((channel3Enable[i] ? channel3.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8); var ch3 = (short)(((channel3Enable[i] ? channel3.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
var ch4 = (short)(((channel4Enable[i] ? channel4.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8); var ch4 = (short)(((channel4Enable[i] ? channel4.OutputVolume : 0) * (volumeRightLeft[i] + 1)) << 8);
channelSampleBuffer[0].Add(ch1); //废弃旧的数组方式
channelSampleBuffer[1].Add(ch2); //channelSampleBuffer[0].Add(ch1);
channelSampleBuffer[2].Add(ch3); //channelSampleBuffer[1].Add(ch2);
channelSampleBuffer[3].Add(ch4); //channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */ /* Mix samples */
var mixed = 0; var mixed = 0;
@ -308,16 +377,22 @@ namespace Essgee.Emulation.Audio
if (channel4ForceEnable) mixed += ch4; if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels; mixed /= numChannels;
mixedSampleBuffer.Add((short)mixed); //废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
} }
} }
public void FlushSamples() public void FlushSamples()
{ {
for (int i = 0; i < numChannels; i++) //for (int i = 0; i < numChannels; i++)
channelSampleBuffer[i].Clear(); // channelSampleBuffer[i].Clear();
channelSampleBuffer_writePos = 0;
mixedSampleBuffer.Clear(); //mixedSampleBuffer.Clear();
mixedSampleBuffer_writePos = 0;
} }
public virtual byte ReadPort(byte port) public virtual byte ReadPort(byte port)

View File

@ -4,11 +4,12 @@ using Essgee.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using static Essgee.Emulation.Utilities; using static Essgee.Emulation.Utilities;
namespace Essgee.Emulation.Audio namespace Essgee.Emulation.Audio
{ {
public class SN76489 : IAudio public unsafe class SN76489 : IAudio
{ {
/* http://www.smspower.org/Development/SN76489 */ /* http://www.smspower.org/Development/SN76489 */
/* Differences in various system's PSGs: http://forums.nesdev.com/viewtopic.php?p=190216#p190216 */ /* Differences in various system's PSGs: http://forums.nesdev.com/viewtopic.php?p=190216#p190216 */
@ -26,8 +27,60 @@ namespace Essgee.Emulation.Audio
protected virtual int noiseBitShift => 14; protected virtual int noiseBitShift => 14;
/* Sample generation & event handling */ /* Sample generation & event handling */
protected List<short>[] channelSampleBuffer; //protected List<short>[] channelSampleBuffer;
protected List<short> mixedSampleBuffer;
#region //指针化 channelSampleBuffer
static short[][] channelSampleBuffer_src;
static GCHandle[] channelSampleBuffer_handle;
public static short*[] channelSampleBuffer;
public static int[] channelSampleBufferLength;
public static int channelSampleBuffer_writePos;
public static bool channelSampleBuffer_IsNull => channelSampleBuffer == null;
public static void channelSampleBuffer_Init(int length1, int Lenght2)
{
if (channelSampleBuffer_src != null)
{
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
channelSampleBuffer_handle[i].ReleaseGCHandle();
}
channelSampleBuffer_src = new short[length1][];
channelSampleBuffer_handle = new GCHandle[length1];
channelSampleBuffer = new short*[length1];
channelSampleBuffer_writePos = 0;
for (int i = 0; i < channelSampleBuffer_src.Length; i++)
{
channelSampleBuffer_src[i] = new short[Lenght2];
channelSampleBuffer_src[i].GetObjectPtr(ref channelSampleBuffer_handle[i], ref channelSampleBuffer[i]);
}
}
#endregion
//protected List<short> mixedSampleBuffer;
#region //指针化 mixedSampleBuffer
short[] mixedSampleBuffer_src;
GCHandle mixedSampleBuffer_handle;
public short* mixedSampleBuffer;
public int mixedSampleBufferLength;
public int mixedSampleBuffer_writePos;
public bool mixedSampleBuffer_IsNull => mixedSampleBuffer == null;
public short[] mixedSampleBuffer_set
{
set
{
mixedSampleBuffer_handle.ReleaseGCHandle();
mixedSampleBuffer_src = value;
mixedSampleBufferLength = value.Length;
mixedSampleBuffer_writePos = 0;
mixedSampleBuffer_src.GetObjectPtr(ref mixedSampleBuffer_handle, ref mixedSampleBuffer);
}
}
#endregion
public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples; public virtual event EventHandler<EnqueueSamplesEventArgs> EnqueueSamples;
public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); } public virtual void OnEnqueueSamples(EnqueueSamplesEventArgs e) { EnqueueSamples?.Invoke(this, e); }
@ -76,10 +129,14 @@ namespace Essgee.Emulation.Audio
public SN76489() public SN76489()
{ {
channelSampleBuffer = new List<short>[numChannels]; //channelSampleBuffer = new List<short>[numChannels];
for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>(); //for (int i = 0; i < numChannels; i++) channelSampleBuffer[i] = new List<short>();
//mixedSampleBuffer = new List<short>();
//改为二维数组
channelSampleBuffer_Init(numChannels, 1470);
mixedSampleBuffer_set = new short[1470];
mixedSampleBuffer = new List<short>();
volumeRegisters = new ushort[numChannels]; volumeRegisters = new ushort[numChannels];
toneRegisters = new ushort[numChannels]; toneRegisters = new ushort[numChannels];
@ -211,13 +268,21 @@ namespace Essgee.Emulation.Audio
sampleCycleCount -= cyclesPerSample; sampleCycleCount -= cyclesPerSample;
} }
if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) //if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels))
if (mixedSampleBuffer_writePos >= (samplesPerFrame * numOutputChannels))
{ {
//EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
// numChannels,
// channelSampleBuffer.Select(x => x.ToArray()).ToArray(),
// new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
// mixedSampleBuffer.ToArray());
EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create( EnqueueSamplesEventArgs eventArgs = EnqueueSamplesEventArgs.Create(
numChannels, numChannels,
channelSampleBuffer.Select(x => x.ToArray()).ToArray(), channelSampleBuffer,
new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable }, new bool[] { !channel1ForceEnable, !channel2ForceEnable, !channel3ForceEnable, !channel4ForceEnable },
mixedSampleBuffer.ToArray()); mixedSampleBuffer,
mixedSampleBufferLength);
OnEnqueueSamples(eventArgs); OnEnqueueSamples(eventArgs);
@ -291,10 +356,19 @@ namespace Essgee.Emulation.Audio
var ch3 = (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)); var ch3 = (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0));
var ch4 = (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)); var ch4 = (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1));
channelSampleBuffer[0].Add(ch1); //废弃旧的数组方式
channelSampleBuffer[1].Add(ch2); //channelSampleBuffer[0].Add(ch1);
channelSampleBuffer[2].Add(ch3); //channelSampleBuffer[1].Add(ch2);
channelSampleBuffer[3].Add(ch4); //channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */ /* Mix samples */
var mixed = 0; var mixed = 0;
@ -304,16 +378,22 @@ namespace Essgee.Emulation.Audio
if (channel4ForceEnable) mixed += ch4; if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels; mixed /= numChannels;
mixedSampleBuffer.Add((short)mixed); //废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
} }
} }
public void FlushSamples() public void FlushSamples()
{ {
for (int i = 0; i < numChannels; i++) //for (int i = 0; i < numChannels; i++)
channelSampleBuffer[i].Clear(); // channelSampleBuffer[i].Clear();
channelSampleBuffer_writePos = 0;
mixedSampleBuffer.Clear(); //mixedSampleBuffer.Clear();
mixedSampleBuffer_writePos = 0;
} }
private ushort CheckParity(ushort val) private ushort CheckParity(ushort val)

View File

@ -2,7 +2,7 @@
namespace Essgee.Emulation.Audio namespace Essgee.Emulation.Audio
{ {
public class SegaGGPSG : SegaSMSPSG public unsafe class SegaGGPSG : SegaSMSPSG
{ {
public const int PortStereoControl = 0x06; public const int PortStereoControl = 0x06;
@ -34,10 +34,19 @@ namespace Essgee.Emulation.Audio
var ch3 = (channel2Enable[i] ? (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)) : (short)0); var ch3 = (channel2Enable[i] ? (short)(volumeTable[volumeRegisters[2]] * ((toneRegisters[2] < 2 ? true : channelOutput[2]) ? 1.0 : 0.0)) : (short)0);
var ch4 = (channel3Enable[i] ? (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)) : (short)0); var ch4 = (channel3Enable[i] ? (short)(volumeTable[volumeRegisters[3]] * (noiseLfsr & 0x1)) : (short)0);
channelSampleBuffer[0].Add(ch1);
channelSampleBuffer[1].Add(ch2); //废弃旧的数组方式
channelSampleBuffer[2].Add(ch3); //channelSampleBuffer[0].Add(ch1);
channelSampleBuffer[3].Add(ch4); //channelSampleBuffer[1].Add(ch2);
//channelSampleBuffer[2].Add(ch3);
//channelSampleBuffer[3].Add(ch4);
//二维指针下标
channelSampleBuffer_writePos++;
channelSampleBuffer[0][channelSampleBuffer_writePos] = ch1;
channelSampleBuffer[1][channelSampleBuffer_writePos] = ch2;
channelSampleBuffer[2][channelSampleBuffer_writePos] = ch3;
channelSampleBuffer[3][channelSampleBuffer_writePos] = ch4;
/* Mix samples */ /* Mix samples */
var mixed = 0; var mixed = 0;
@ -47,7 +56,11 @@ namespace Essgee.Emulation.Audio
if (channel4ForceEnable) mixed += ch4; if (channel4ForceEnable) mixed += ch4;
mixed /= numChannels; mixed /= numChannels;
mixedSampleBuffer.Add((short)mixed); //废弃旧的方式
//mixedSampleBuffer.Add((short)mixed);
//指针下标
mixedSampleBuffer_writePos++;
mixedSampleBuffer[mixedSampleBuffer_writePos] = (short)mixed;
} }
} }

View File

@ -2,12 +2,14 @@
namespace Essgee.EventArguments namespace Essgee.EventArguments
{ {
public class EnqueueSamplesEventArgs : EventArgs public unsafe class EnqueueSamplesEventArgs : EventArgs
{ {
public int NumChannels { get; set; } public int NumChannels { get; set; }
public short[][] ChannelSamples { get; set; } //public short[][] ChannelSamples { get; set; }
public short*[] ChannelSamples { get; set; }
public bool[] IsChannelMuted { get; set; } public bool[] IsChannelMuted { get; set; }
public short[] MixedSamples { get; set; } public short* MixedSamples { get; set; }
public int MixedSamplesLength { get; set; }
//public EnqueueSamplesEventArgs(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples) //public EnqueueSamplesEventArgs(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples)
//{ //{
@ -17,17 +19,19 @@ namespace Essgee.EventArguments
// MixedSamples = mixedSamples; // MixedSamples = mixedSamples;
//} //}
public static EnqueueSamplesEventArgs Create(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples) //public static EnqueueSamplesEventArgs Create(int numChannels, short[][] channelSamples, bool[] isMuted, short[] mixedSamples)
public static EnqueueSamplesEventArgs Create(int numChannels, short*[] channelSamples, bool[] isMuted, short* mixedSamples,int mixedSamplesLength)
{ {
var eventArgs = ObjectPoolAuto.Acquire<EnqueueSamplesEventArgs>(); var eventArgs = ObjectPoolAuto.Acquire<EnqueueSamplesEventArgs>();
eventArgs.NumChannels = numChannels; eventArgs.NumChannels = numChannels;
eventArgs.ChannelSamples = channelSamples; eventArgs.ChannelSamples = channelSamples;
eventArgs.IsChannelMuted = isMuted; eventArgs.IsChannelMuted = isMuted;
eventArgs.MixedSamples = mixedSamples; eventArgs.MixedSamples = mixedSamples;
eventArgs.MixedSamplesLength = mixedSamplesLength;
return eventArgs; return eventArgs;
} }
} }
public static class EnqueueSamplesEventArgsEx public unsafe static class EnqueueSamplesEventArgsEx
{ {
public static void Release(this EnqueueSamplesEventArgs eventArgs) public static void Release(this EnqueueSamplesEventArgs eventArgs)
{ {

View File

@ -346,7 +346,7 @@ public class Essgeeinit : MonoBehaviour
private void LoadAndRunCartridge(string fileName) private void LoadAndRunCartridge(string fileName)
{ {
//Application.targetFrameRate = 60; Application.targetFrameRate = 60;
try try
{ {
var (machineType, romData) = CartridgeLoader.Load(fileName, "ROM image"); var (machineType, romData) = CartridgeLoader.Load(fileName, "ROM image");
@ -698,7 +698,7 @@ public class Essgeeinit : MonoBehaviour
} }
} }
public void EnqueueSoundSamples(object sender, EnqueueSamplesEventArgs e) public unsafe void EnqueueSoundSamples(object sender, EnqueueSamplesEventArgs e)
{ {
//if (sampleQueue.Count > MaxQueueLength) //if (sampleQueue.Count > MaxQueueLength)
//{ //{
@ -718,7 +718,8 @@ public class Essgeeinit : MonoBehaviour
//} //}
//TODO 音频处理 //TODO 音频处理
soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamples.Length); //soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamples.Length);
soundHandler.SubmitSamples(e.MixedSamples, e.ChannelSamples, e.MixedSamplesLength);
} }
#endregion #endregion
} }

View File

@ -56,7 +56,7 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
} }
} }
public 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;
var delta = current - lastElapsed; var delta = current - lastElapsed;
@ -74,9 +74,7 @@ public class UEGSoundPlayer : MonoBehaviour//, ISoundPlayer
for (int i = 0; i < samples_a; i += 2) for (int i = 0; i < samples_a; i += 2)
{ {
//_buffer.Write(buffer[i] / 32767.0f); _buffer.Write(buffer[i] / 32767.0f);
float data = (uint)(buffer[i] + 32767);
_buffer.Write(data / ushort.MaxValue);
//_buffer.Write(buffer[i] / 32767.0f); //_buffer.Write(buffer[i] / 32767.0f);
} }
} }