Move solution and projects to src
This commit is contained in:
26
src/Ryujinx.Audio/Backends/Common/BackendHelper.cs
Normal file
26
src/Ryujinx.Audio/Backends/Common/BackendHelper.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.Common
|
||||
{
|
||||
public static class BackendHelper
|
||||
{
|
||||
public static int GetSampleSize(SampleFormat format)
|
||||
{
|
||||
return format switch
|
||||
{
|
||||
SampleFormat.PcmInt8 => sizeof(byte),
|
||||
SampleFormat.PcmInt16 => sizeof(ushort),
|
||||
SampleFormat.PcmInt24 => 3,
|
||||
SampleFormat.PcmInt32 => sizeof(int),
|
||||
SampleFormat.PcmFloat => sizeof(float),
|
||||
_ => throw new ArgumentException($"{format}"),
|
||||
};
|
||||
}
|
||||
|
||||
public static int GetSampleCount(SampleFormat format, int channelCount, int bufferSize)
|
||||
{
|
||||
return bufferSize / GetSampleSize(format) / channelCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
166
src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs
Normal file
166
src/Ryujinx.Audio/Backends/Common/DynamicRingBuffer.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using Ryujinx.Common;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.Common
|
||||
{
|
||||
/// <summary>
|
||||
/// A ring buffer that grow if data written to it is too big to fit.
|
||||
/// </summary>
|
||||
public class DynamicRingBuffer
|
||||
{
|
||||
private const int RingBufferAlignment = 2048;
|
||||
|
||||
private object _lock = new object();
|
||||
|
||||
private byte[] _buffer;
|
||||
private int _size;
|
||||
private int _headOffset;
|
||||
private int _tailOffset;
|
||||
|
||||
public int Length => _size;
|
||||
|
||||
public DynamicRingBuffer(int initialCapacity = RingBufferAlignment)
|
||||
{
|
||||
_buffer = new byte[initialCapacity];
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_size = 0;
|
||||
_headOffset = 0;
|
||||
_tailOffset = 0;
|
||||
}
|
||||
|
||||
public void Clear(int size)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (size > _size)
|
||||
{
|
||||
size = _size;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_headOffset = (_headOffset + size) % _buffer.Length;
|
||||
_size -= size;
|
||||
|
||||
if (_size == 0)
|
||||
{
|
||||
_headOffset = 0;
|
||||
_tailOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCapacityLocked(int capacity)
|
||||
{
|
||||
byte[] buffer = new byte[capacity];
|
||||
|
||||
if (_size > 0)
|
||||
{
|
||||
if (_headOffset < _tailOffset)
|
||||
{
|
||||
Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(_buffer, _headOffset, buffer, 0, _buffer.Length - _headOffset);
|
||||
Buffer.BlockCopy(_buffer, 0, buffer, _buffer.Length - _headOffset, _tailOffset);
|
||||
}
|
||||
}
|
||||
|
||||
_buffer = buffer;
|
||||
_headOffset = 0;
|
||||
_tailOffset = _size;
|
||||
}
|
||||
|
||||
|
||||
public void Write<T>(T[] buffer, int index, int count)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if ((_size + count) > _buffer.Length)
|
||||
{
|
||||
SetCapacityLocked(BitUtils.AlignUp(_size + count, RingBufferAlignment));
|
||||
}
|
||||
|
||||
if (_headOffset < _tailOffset)
|
||||
{
|
||||
int tailLength = _buffer.Length - _tailOffset;
|
||||
|
||||
if (tailLength >= count)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, tailLength);
|
||||
Buffer.BlockCopy(buffer, index + tailLength, _buffer, 0, count - tailLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(buffer, index, _buffer, _tailOffset, count);
|
||||
}
|
||||
|
||||
_size += count;
|
||||
_tailOffset = (_tailOffset + count) % _buffer.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public int Read<T>(T[] buffer, int index, int count)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (count > _size)
|
||||
{
|
||||
count = _size;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_headOffset < _tailOffset)
|
||||
{
|
||||
Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
int tailLength = _buffer.Length - _headOffset;
|
||||
|
||||
if (tailLength >= count)
|
||||
{
|
||||
Buffer.BlockCopy(_buffer, _headOffset, buffer, index, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(_buffer, _headOffset, buffer, index, tailLength);
|
||||
Buffer.BlockCopy(_buffer, 0, buffer, index + tailLength, count - tailLength);
|
||||
}
|
||||
}
|
||||
|
||||
_size -= count;
|
||||
_headOffset = (_headOffset + count) % _buffer.Length;
|
||||
|
||||
if (_size == 0)
|
||||
{
|
||||
_headOffset = 0;
|
||||
_tailOffset = 0;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Memory;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Backends.Common
|
||||
{
|
||||
public abstract class HardwareDeviceSessionOutputBase : IHardwareDeviceSession
|
||||
{
|
||||
public IVirtualMemoryManager MemoryManager { get; }
|
||||
public SampleFormat RequestedSampleFormat { get; }
|
||||
public uint RequestedSampleRate { get; }
|
||||
public uint RequestedChannelCount { get; }
|
||||
|
||||
public HardwareDeviceSessionOutputBase(IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount)
|
||||
{
|
||||
MemoryManager = memoryManager;
|
||||
RequestedSampleFormat = requestedSampleFormat;
|
||||
RequestedSampleRate = requestedSampleRate;
|
||||
RequestedChannelCount = requestedChannelCount;
|
||||
}
|
||||
|
||||
private byte[] GetBufferSamples(AudioBuffer buffer)
|
||||
{
|
||||
if (buffer.DataPointer == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] data = new byte[buffer.DataSize];
|
||||
|
||||
MemoryManager.Read(buffer.DataPointer, data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected ulong GetSampleCount(AudioBuffer buffer)
|
||||
{
|
||||
return GetSampleCount((int)buffer.DataSize);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected ulong GetSampleCount(int dataSize)
|
||||
{
|
||||
return (ulong)BackendHelper.GetSampleCount(RequestedSampleFormat, (int)RequestedChannelCount, dataSize);
|
||||
}
|
||||
|
||||
public abstract void Dispose();
|
||||
public abstract void PrepareToClose();
|
||||
public abstract void QueueBuffer(AudioBuffer buffer);
|
||||
public abstract void SetVolume(float volume);
|
||||
public abstract float GetVolume();
|
||||
public abstract void Start();
|
||||
public abstract void Stop();
|
||||
public abstract ulong GetPlayedSampleCount();
|
||||
public abstract bool WasBufferFullyConsumed(AudioBuffer buffer);
|
||||
public virtual bool RegisterBuffer(AudioBuffer buffer)
|
||||
{
|
||||
return RegisterBuffer(buffer, GetBufferSamples(buffer));
|
||||
}
|
||||
|
||||
public virtual bool RegisterBuffer(AudioBuffer buffer, byte[] samples)
|
||||
{
|
||||
if (samples == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer.Data == null)
|
||||
{
|
||||
buffer.Data = samples;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void UnregisterBuffer(AudioBuffer buffer) { }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user