sdl3 audio
This commit is contained in:
parent
0bd62888a0
commit
fbc5ccfa2c
@ -1,16 +0,0 @@
|
||||
namespace Ryujinx.Audio.Backends.SDL3
|
||||
{
|
||||
class SDL3AudioBuffer
|
||||
{
|
||||
public readonly ulong DriverIdentifier;
|
||||
public readonly ulong SampleCount;
|
||||
public ulong SamplePlayed;
|
||||
|
||||
public SDL3AudioBuffer(ulong driverIdentifier, ulong sampleCount)
|
||||
{
|
||||
DriverIdentifier = driverIdentifier;
|
||||
SampleCount = sampleCount;
|
||||
SamplePlayed = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
|
||||
SDL3Driver.Instance.Initialize();
|
||||
|
||||
if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, out var spec, out int sample_frames))
|
||||
if (!SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, out var spec, out int _))
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application,
|
||||
$"SDL_GetDefaultAudioInfo failed with error \"{SDL_GetError()}\"");
|
||||
@ -48,8 +48,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
|
||||
private static bool IsSupportedInternal()
|
||||
{
|
||||
var device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax,
|
||||
Constants.TargetSampleCount, null);
|
||||
var device = OpenStream(SampleFormat.PcmInt16, Constants.TargetSampleRate, Constants.ChannelCountMax);
|
||||
|
||||
if (device != 0)
|
||||
{
|
||||
@ -100,7 +99,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
}
|
||||
|
||||
private static SDL_AudioSpec GetSDL3Spec(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||
uint requestedChannelCount, uint sampleCount)
|
||||
uint requestedChannelCount)
|
||||
{
|
||||
return new SDL_AudioSpec
|
||||
{
|
||||
@ -123,10 +122,9 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
}
|
||||
|
||||
internal static nint OpenStream(SampleFormat requestedSampleFormat, uint requestedSampleRate,
|
||||
uint requestedChannelCount, uint sampleCount, SDL_AudioStreamCallback callback)
|
||||
uint requestedChannelCount)
|
||||
{
|
||||
SDL_AudioSpec spec = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount,
|
||||
sampleCount);
|
||||
SDL_AudioSpec spec = GetSDL3Spec(requestedSampleFormat, requestedSampleRate, requestedChannelCount);
|
||||
|
||||
var stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, ref spec,null,IntPtr.Zero);
|
||||
|
||||
|
@ -1,12 +1,8 @@
|
||||
using Ryujinx.Audio.Backends.Common;
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static SDL3.SDL;
|
||||
|
||||
@ -15,14 +11,10 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
class SDL3HardwareDeviceSession : HardwareDeviceSessionOutputBase
|
||||
{
|
||||
private readonly SDL3HardwareDeviceDriver _driver;
|
||||
private readonly ConcurrentQueue<SDL3AudioBuffer> _queuedBuffers;
|
||||
private readonly DynamicRingBuffer _ringBuffer;
|
||||
private ulong _playedSampleCount;
|
||||
private readonly ManualResetEvent _updateRequiredEvent;
|
||||
private nint _outputStream;
|
||||
private bool _hasSetupError;
|
||||
private readonly SDL_AudioStreamCallback _callbackDelegate;
|
||||
private readonly int _bytesPerFrame;
|
||||
private uint _sampleCount;
|
||||
private bool _started;
|
||||
private float _volume;
|
||||
@ -34,10 +26,6 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
{
|
||||
_driver = driver;
|
||||
_updateRequiredEvent = _driver.GetUpdateRequiredEvent();
|
||||
_queuedBuffers = new ConcurrentQueue<SDL3AudioBuffer>();
|
||||
_ringBuffer = new DynamicRingBuffer();
|
||||
_callbackDelegate = Update;
|
||||
_bytesPerFrame = BackendHelper.GetSampleSize(RequestedSampleFormat) * (int)RequestedChannelCount;
|
||||
_nativeSampleFormat = SDL3HardwareDeviceDriver.GetSDL3Format(RequestedSampleFormat);
|
||||
_sampleCount = uint.MaxValue;
|
||||
_started = false;
|
||||
@ -56,7 +44,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
_sampleCount = Math.Max(Constants.TargetSampleCount, bufferSampleCount);
|
||||
|
||||
var newOutputStream = SDL3HardwareDeviceDriver.OpenStream(RequestedSampleFormat, RequestedSampleRate,
|
||||
RequestedChannelCount, _sampleCount, _callbackDelegate);
|
||||
RequestedChannelCount);
|
||||
|
||||
_hasSetupError = newOutputStream == 0;
|
||||
|
||||
@ -75,78 +63,6 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void Update(nint userdata, IntPtr stream, int streamLength, int total_amount)
|
||||
{
|
||||
Console.WriteLine("call");
|
||||
Console.WriteLine(SDL_GetAudioDeviceName(SDL_GetAudioStreamDevice(stream)));
|
||||
Span<byte> streamSpan = new((void*)stream, streamLength);
|
||||
|
||||
int maxFrameCount = (int)GetSampleCount(streamLength);
|
||||
int bufferedFrames = _ringBuffer.Length / _bytesPerFrame;
|
||||
|
||||
int frameCount = Math.Min(bufferedFrames, maxFrameCount);
|
||||
|
||||
if (frameCount == 0)
|
||||
{
|
||||
// SDL3 left the responsibility to the user to clear the buffer.
|
||||
streamSpan.Clear();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame);
|
||||
|
||||
Span<byte> samples = samplesOwner.Span;
|
||||
|
||||
_ringBuffer.Read(samples, 0, samples.Length);
|
||||
|
||||
// fixed (byte* p = samples)
|
||||
// {
|
||||
// nint pStreamSrc = (nint)p;
|
||||
//
|
||||
// // Zero the dest buffer
|
||||
// streamSpan.Clear();
|
||||
//
|
||||
// // Apply volume to written data
|
||||
// // SDL_MixAudio(stream, pStreamSrc, _nativeSampleFormat, (uint)samples.Length, _driver.Volume * _volume);
|
||||
// IntPtr unmanagedBuffer = Marshal.AllocHGlobal(samples.Length);
|
||||
// Marshal.Copy(p, 0, unmanagedBuffer, samples.Length);
|
||||
// SDL_PutAudioStreamData(_outputStream, unmanagedBuffer,samples.Length);
|
||||
// }
|
||||
|
||||
|
||||
ulong sampleCount = GetSampleCount(samples.Length);
|
||||
|
||||
ulong availaibleSampleCount = sampleCount;
|
||||
|
||||
bool needUpdate = false;
|
||||
|
||||
while (availaibleSampleCount > 0 && _queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
|
||||
{
|
||||
ulong sampleStillNeeded = driverBuffer.SampleCount - Interlocked.Read(ref driverBuffer.SamplePlayed);
|
||||
ulong playedAudioBufferSampleCount = Math.Min(sampleStillNeeded, availaibleSampleCount);
|
||||
|
||||
ulong currentSamplePlayed =
|
||||
Interlocked.Add(ref driverBuffer.SamplePlayed, playedAudioBufferSampleCount);
|
||||
availaibleSampleCount -= playedAudioBufferSampleCount;
|
||||
|
||||
if (currentSamplePlayed == driverBuffer.SampleCount)
|
||||
{
|
||||
_queuedBuffers.TryDequeue(out _);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
Interlocked.Add(ref _playedSampleCount, playedAudioBufferSampleCount);
|
||||
}
|
||||
|
||||
// Notify the output if needed.
|
||||
if (needUpdate)
|
||||
{
|
||||
_updateRequiredEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public override ulong GetPlayedSampleCount()
|
||||
{
|
||||
return Interlocked.Read(ref _playedSampleCount);
|
||||
@ -164,27 +80,21 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
EnsureAudioStreamSetup(buffer);
|
||||
if (_outputStream != 0)
|
||||
{
|
||||
SDL3AudioBuffer driverBuffer = new(buffer.DataPointer, GetSampleCount(buffer));
|
||||
|
||||
_ringBuffer.Write(buffer.Data, 0, buffer.Data.Length);
|
||||
int MinimumAudio = int.MaxValue; // 8000 float samples per second, half a second.
|
||||
// SDL_ResumeAudioStreamDevice(_outputStream);
|
||||
Console.WriteLine(SDL_GetAudioStreamAvailable(_outputStream));
|
||||
if (SDL_GetAudioStreamAvailable(_outputStream) < MinimumAudio)
|
||||
if (SDL_GetAudioStreamAvailable(_outputStream) < int.MaxValue)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* samplesPtr = buffer.Data)
|
||||
{
|
||||
IntPtr buffer2 = (IntPtr)samplesPtr;
|
||||
|
||||
SDL_PutAudioStreamData(_outputStream, buffer2, buffer.Data.Length);
|
||||
|
||||
var len = buffer.Data.Length;
|
||||
IntPtr src = (IntPtr)samplesPtr;
|
||||
byte* dst = stackalloc byte[len];
|
||||
IntPtr dstPtr = (IntPtr)dst;
|
||||
SDL_MixAudio(dstPtr, src, _nativeSampleFormat, (uint)len, _driver.Volume);
|
||||
SDL_PutAudioStreamData(_outputStream, dstPtr, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_queuedBuffers.Enqueue(driverBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -229,12 +139,7 @@ namespace Ryujinx.Audio.Backends.SDL3
|
||||
|
||||
public override bool WasBufferFullyConsumed(AudioBuffer buffer)
|
||||
{
|
||||
if (!_queuedBuffers.TryPeek(out SDL3AudioBuffer driverBuffer))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return driverBuffer.DriverIdentifier != buffer.DataPointer;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
|
@ -8,7 +8,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
Invalid,
|
||||
WindowKeyboard,
|
||||
GamepadSDL2,
|
||||
GamepadSDL3
|
||||
}
|
||||
}
|
||||
|
@ -4222,6 +4222,31 @@
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "SettingsTabSystemAudioBackendSDL3",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "SDL3",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "SettingsTabSystemHacks",
|
||||
"Translations": {
|
||||
|
@ -157,7 +157,7 @@ namespace Ryujinx.Headless
|
||||
config = new StandardControllerInputConfig
|
||||
{
|
||||
Version = InputConfig.CurrentVersion,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
Backend = InputBackendType.GamepadSDL3,
|
||||
Id = null,
|
||||
ControllerType = ControllerType.JoyconPair,
|
||||
DeadzoneLeft = 0.1f,
|
||||
|
@ -491,7 +491,7 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
var config = new StandardControllerInputConfig
|
||||
{
|
||||
Id = Id,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
Backend = InputBackendType.GamepadSDL3,
|
||||
PlayerIndex = PlayerIndex,
|
||||
ControllerType = ControllerType,
|
||||
LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId>
|
||||
|
@ -579,7 +579,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
config = new StandardControllerInputConfig
|
||||
{
|
||||
Version = InputConfig.CurrentVersion,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
Backend = InputBackendType.GamepadSDL3,
|
||||
Id = id,
|
||||
ControllerType = ControllerType.ProController,
|
||||
DeadzoneLeft = 0.1f,
|
||||
|
@ -48,8 +48,7 @@
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem IsEnabled="{Binding IsSDL3Enabled}">
|
||||
<TextBlock>
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemAudioBackendSDL2}" />
|
||||
<TextBlock Text="+1" />
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemAudioBackendSDL3}" />
|
||||
</TextBlock>
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
Loading…
x
Reference in New Issue
Block a user