Compare commits
98 Commits
Author | SHA1 | Date | |
---|---|---|---|
1f3b860f06 | |||
abe3c02ab4 | |||
45b417b2b4 | |||
d076339e3e | |||
837836431d | |||
9f555db5cd | |||
bf7fa60dfc | |||
752b93d3b7 | |||
f23b2878cc | |||
e211c3f00a | |||
d3709a753f | |||
ab676d58ea | |||
2372c194f1 | |||
40311310d1 | |||
dde9bb5c69 | |||
266338a7c9 | |||
90156eea4c | |||
071c01c235 | |||
de06ffb0f7 | |||
8a7de35e3f | |||
121296834a | |||
bbb24d8c7e | |||
4da44e09cb | |||
ae13f0ab4d | |||
a2a35f1be6 | |||
aedfadaaf7 | |||
5c0fb0cec3 | |||
17a1cab5d2 | |||
73aed239c3 | |||
9ac66336a2 | |||
4965681e06 | |||
3868a00206 | |||
933e5144a9 | |||
73a42c85c4 | |||
39ba11054b | |||
c250e3392c | |||
e56b069081 | |||
204c031fef | |||
d9053bbe37 | |||
c25e8427aa | |||
21a081b185 | |||
b540ea80d1 | |||
d692a9b83e | |||
9677ddaa5d | |||
ce92e8cd04 | |||
456fc04007 | |||
458452279c | |||
817b89767a | |||
3fb583c98c | |||
d2686e0a5b | |||
4905101df1 | |||
8750b90a7f | |||
af01100050 | |||
c0821fee1f | |||
a5c2aead67 | |||
d41c95dcff | |||
fbf2b09706 | |||
1fc0f569de | |||
dff138229c | |||
472119c8da | |||
1865ea87e5 | |||
18b61aff59 | |||
cb22629ac1 | |||
6f0f99ee2b | |||
70f2da8fdf | |||
5d3ef7761b | |||
476b4683cf | |||
5fb5079730 | |||
3fbacd0f49 | |||
7aa6abc120 | |||
548bfd60a2 | |||
65778a6b78 | |||
f4e879a1e6 | |||
a1ddaa2736 | |||
008286b79f | |||
a0c77f8d11 | |||
ece36b274d | |||
f3cc2e5703 | |||
5a39d3c4a1 | |||
cc51a03af9 | |||
567c64e149 | |||
36f00985d3 | |||
748d87adcc | |||
0fd47ff490 | |||
f088c3d344 | |||
905a191e28 | |||
ab0491817e | |||
5de6ae426e | |||
69ced3a6e8 | |||
2e43d01d36 | |||
7373ec5792 | |||
de162a648b | |||
131baebe2a | |||
187372cbde | |||
022d495335 | |||
c1372ed775 | |||
a16682cfd3 | |||
7c53b69c30 |
@ -89,6 +89,7 @@ csharp_style_conditional_delegate_call = true:suggestion
|
||||
# Modifier preferences
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
|
||||
# Code-block preferences
|
||||
csharp_prefer_braces = true:silent
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something doesn't work correctly in Ryujinx. Note that game-specific issues should be instead posted on the Game Compatibility List at https://github.com/Ryujinx/Ryujinx-Games-List, unless it is a provable regression.
|
||||
about: Something doesn't work correctly in Ryujinx. Game-specific issues should be posted at https://github.com/Ryujinx/Ryujinx-Games-List instead, unless it is a provable regression.
|
||||
#assignees:
|
||||
---
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct AllocationResult
|
||||
readonly struct AllocationResult
|
||||
{
|
||||
public int IntUsedRegisters { get; }
|
||||
public int VecUsedRegisters { get; }
|
||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
private class ParallelCopy
|
||||
{
|
||||
private struct Copy
|
||||
private readonly struct Copy
|
||||
{
|
||||
public Register Dest { get; }
|
||||
public Register Source { get; }
|
||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
class HybridAllocator : IRegisterAllocator
|
||||
{
|
||||
private struct BlockInfo
|
||||
private readonly struct BlockInfo
|
||||
{
|
||||
public bool HasCall { get; }
|
||||
|
||||
|
@ -3,7 +3,7 @@ using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct RegisterMasks
|
||||
readonly struct RegisterMasks
|
||||
{
|
||||
public int IntAvailableRegisters { get; }
|
||||
public int VecAvailableRegisters { get; }
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
struct IntrinsicInfo
|
||||
readonly struct IntrinsicInfo
|
||||
{
|
||||
public X86Instruction Inst { get; }
|
||||
public IntrinsicType Type { get; }
|
||||
|
@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
static class BitUtils
|
||||
{
|
||||
private static readonly sbyte[] HbsNibbleLut;
|
||||
|
||||
static BitUtils()
|
||||
{
|
||||
HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
}
|
||||
private static ReadOnlySpan<sbyte> HbsNibbleLut => new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
|
||||
public static long FillWithOnes(int bits)
|
||||
{
|
||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Instructions;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
struct InstDescriptor
|
||||
readonly struct InstDescriptor
|
||||
{
|
||||
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
private const int FastLookupSize = 0x1000;
|
||||
|
||||
private struct InstInfo
|
||||
private readonly struct InstInfo
|
||||
{
|
||||
public int Mask { get; }
|
||||
public int Value { get; }
|
||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Diagnostics
|
||||
{
|
||||
static class Symbols
|
||||
{
|
||||
private struct RangedSymbol
|
||||
private readonly struct RangedSymbol
|
||||
{
|
||||
public readonly ulong Start;
|
||||
public readonly ulong End;
|
||||
|
@ -3,7 +3,7 @@ using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
struct PhiOperation
|
||||
readonly struct PhiOperation
|
||||
{
|
||||
private readonly Operation _operation;
|
||||
|
||||
|
@ -2,7 +2,7 @@ using System;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
struct Register : IEquatable<Register>
|
||||
readonly struct Register : IEquatable<Register>
|
||||
{
|
||||
public int Index { get; }
|
||||
|
||||
|
@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
struct CacheEntry : IComparable<CacheEntry>
|
||||
readonly struct CacheEntry : IComparable<CacheEntry>
|
||||
{
|
||||
public int Offset { get; }
|
||||
public int Size { get; }
|
||||
|
@ -6,7 +6,7 @@ namespace ARMeilleure.Translation.Cache
|
||||
{
|
||||
class CacheMemoryAllocator
|
||||
{
|
||||
private struct MemoryBlock : IComparable<MemoryBlock>
|
||||
private readonly struct MemoryBlock : IComparable<MemoryBlock>
|
||||
{
|
||||
public int Offset { get; }
|
||||
public int Size { get; }
|
||||
|
@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
struct CompilerContext
|
||||
readonly struct CompilerContext
|
||||
{
|
||||
public ControlFlowGraph Cfg { get; }
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
||||
private const int RegsCount = 32;
|
||||
private const int RegsMask = RegsCount - 1;
|
||||
|
||||
private struct RegisterMask : IEquatable<RegisterMask>
|
||||
private readonly struct RegisterMask : IEquatable<RegisterMask>
|
||||
{
|
||||
public long IntMask => Mask.GetElement(0);
|
||||
public long VecMask => Mask.GetElement(1);
|
||||
|
@ -293,7 +293,7 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
private struct Range
|
||||
private readonly struct Range
|
||||
{
|
||||
public ulong Start { get; }
|
||||
public ulong End { get; }
|
||||
|
10
README.md
10
README.md
@ -21,6 +21,10 @@
|
||||
<img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://crwd.in/ryujinx">
|
||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
||||
alt="">
|
||||
</a>
|
||||
<a href="https://discord.com/invite/VkQYXAZ">
|
||||
<img src="https://img.shields.io/discord/410208534861447168?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
||||
alt="Discord">
|
||||
@ -36,7 +40,7 @@
|
||||
|
||||
## Compatibility
|
||||
|
||||
As of October 2022, Ryujinx has been tested on approximately 3,700 titles; over 3,500 boot past menus and into gameplay, with roughly 3,000 of those being considered playable.
|
||||
As of November 2022, Ryujinx has been tested on approximately 3,800 titles; over 3,600 boot past menus and into gameplay, with roughly 3,200 of those being considered playable.
|
||||
You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already!
|
||||
|
||||
## Usage
|
||||
@ -48,6 +52,8 @@ See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ry
|
||||
For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide
|
||||
](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
|
||||
|
||||
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
|
||||
|
||||
## Latest build
|
||||
|
||||
These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.**
|
||||
@ -90,7 +96,7 @@ Ryujinx system files are stored in the `Ryujinx` folder. This folder is located
|
||||
|
||||
- **GPU**
|
||||
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum) or Vulkan APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
The GPU emulator emulates the Switch's Maxwell GPU using either the OpenGL (version 4.5 minimum), Vulkan, or Metal (via MoltenVK) APIs through a custom build of OpenTK or Silk.NET respectively. There are currently four graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Aspect Ratio Adjustment, and Anisotropic Filtering. These enhancements can be adjusted or toggled as desired in the GUI.
|
||||
|
||||
- **Input**
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.2" />
|
||||
<PackageReference Include="OpenTK.OpenAL" Version="4.7.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Audio.Common;
|
||||
using Ryujinx.Audio.Integration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Memory;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using System;
|
||||
@ -112,6 +113,9 @@ namespace Ryujinx.Audio.Backends.SDL2
|
||||
|
||||
if (device == 0)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application,
|
||||
$"SDL2 open audio device initialization failed with error \"{SDL_GetError()}\"");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -119,6 +123,7 @@ namespace Ryujinx.Audio.Backends.SDL2
|
||||
|
||||
if (!isValid)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "SDL2 open audio device is not valid");
|
||||
SDL_CloseAudioDevice(device);
|
||||
|
||||
return 0;
|
||||
|
@ -4,7 +4,7 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOChannelLayout
|
||||
public readonly struct SoundIOChannelLayout
|
||||
{
|
||||
public static int BuiltInCount
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace SoundIOSharp
|
||||
{
|
||||
public struct SoundIOSampleRateRange
|
||||
public readonly struct SoundIOSampleRateRange
|
||||
{
|
||||
internal SoundIOSampleRateRange(int min, int max)
|
||||
{
|
||||
|
@ -48,6 +48,11 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
/// <summary>
|
||||
/// Effect to capture mixes (via auxiliary buffers).
|
||||
/// </summary>
|
||||
CaptureBuffer
|
||||
CaptureBuffer,
|
||||
|
||||
/// <summary>
|
||||
/// Effect applying a compressor filter (DRC).
|
||||
/// </summary>
|
||||
Compressor,
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ namespace Ryujinx.Audio.Renderer.Common
|
||||
Reverb3d,
|
||||
PcmFloat,
|
||||
Limiter,
|
||||
CaptureBuffer
|
||||
CaptureBuffer,
|
||||
Compressor
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@ -71,6 +72,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return (short)value;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||
{
|
||||
if ((uint)index > (uint)coefficients.Length)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return coefficients[index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
||||
{
|
||||
@ -84,8 +98,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
byte coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||
short history0 = loopContext.History0;
|
||||
short history1 = loopContext.History1;
|
||||
short coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
||||
short coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
||||
short coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 0);
|
||||
short coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||
|
||||
int decodedCount = Math.Min(count, endSampleOffset - startSampleOffset - offset);
|
||||
int nibbles = GetNibblesFromSampleCount(offset + startSampleOffset);
|
||||
@ -109,8 +123,8 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
coefficientIndex = (byte)((predScale >> 4) & 0xF);
|
||||
|
||||
coefficient0 = coefficients[coefficientIndex * 2 + 0];
|
||||
coefficient1 = coefficients[coefficientIndex * 2 + 1];
|
||||
coefficient0 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2);
|
||||
coefficient1 = GetCoefficientAtIndex(coefficients, coefficientIndex * 2 + 1);
|
||||
|
||||
nibbles += 2;
|
||||
|
||||
|
@ -116,6 +116,11 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
};
|
||||
}
|
||||
|
||||
public bool HasRemainingCommands(int sessionId)
|
||||
{
|
||||
return _sessionCommandList[sessionId] != null;
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
{
|
||||
_mailbox.SendMessage(MailboxMessage.RenderStart);
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.AdpcmDataSourceVersion1;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort OutputBufferIndex { get; }
|
||||
public uint SampleRate { get; }
|
||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.AuxiliaryBuffer;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint InputBufferIndex { get; }
|
||||
public uint OutputBufferIndex { get; }
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.BiquadFilter;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public Memory<BiquadFilterState> BiquadFilterState { get; }
|
||||
public int InputBufferIndex { get; }
|
||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.CaptureBuffer;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint InputBufferIndex { get; }
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.CircularBufferSink;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort[] Input { get; }
|
||||
public uint InputCount { get; }
|
||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.ClearMixBuffer;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ClearMixBufferCommand(int nodeId)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
LimiterVersion1,
|
||||
LimiterVersion2,
|
||||
GroupedBiquadFilter,
|
||||
CaptureBuffer
|
||||
CaptureBuffer,
|
||||
Compressor
|
||||
}
|
||||
}
|
173
Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
Normal file
173
Ryujinx.Audio/Renderer/Dsp/Command/CompressorCommand.cs
Normal file
@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
public class CompressorCommand : ICommand
|
||||
{
|
||||
private const int FixedPointPrecision = 15;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public int NodeId { get; }
|
||||
|
||||
public CommandType CommandType => CommandType.Compressor;
|
||||
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public CompressorParameter Parameter => _parameter;
|
||||
public Memory<CompressorState> State { get; }
|
||||
public ushort[] OutputBufferIndices { get; }
|
||||
public ushort[] InputBufferIndices { get; }
|
||||
public bool IsEffectEnabled { get; }
|
||||
|
||||
private CompressorParameter _parameter;
|
||||
|
||||
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
|
||||
{
|
||||
Enabled = true;
|
||||
NodeId = nodeId;
|
||||
_parameter = parameter;
|
||||
State = state;
|
||||
|
||||
IsEffectEnabled = isEnabled;
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
ref CompressorState state = ref State.Span[0];
|
||||
|
||||
if (IsEffectEnabled)
|
||||
{
|
||||
if (_parameter.Status == Server.Effect.UsageState.Invalid)
|
||||
{
|
||||
state = new CompressorState(ref _parameter);
|
||||
}
|
||||
else if (_parameter.Status == Server.Effect.UsageState.New)
|
||||
{
|
||||
state.UpdateParameter(ref _parameter);
|
||||
}
|
||||
}
|
||||
|
||||
ProcessCompressor(context, ref state);
|
||||
}
|
||||
|
||||
private unsafe void ProcessCompressor(CommandList context, ref CompressorState state)
|
||||
{
|
||||
Debug.Assert(_parameter.IsChannelCountValid());
|
||||
|
||||
if (IsEffectEnabled && _parameter.IsChannelCountValid())
|
||||
{
|
||||
Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
|
||||
Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
|
||||
Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
|
||||
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
|
||||
float unknown4 = state.Unknown4;
|
||||
ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
|
||||
float previousCompressionEmaAlpha = state.PreviousCompressionEmaAlpha;
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
|
||||
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
|
||||
}
|
||||
|
||||
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
|
||||
{
|
||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||
{
|
||||
channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
|
||||
}
|
||||
|
||||
float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
|
||||
float y = FloatingPointHelper.Log10(newMean) * 10.0f;
|
||||
float z = 0.0f;
|
||||
|
||||
bool unknown10OutOfRange = false;
|
||||
|
||||
if (newMean < 1.0e-10f)
|
||||
{
|
||||
z = 1.0f;
|
||||
|
||||
unknown10OutOfRange = state.Unknown10 < -100.0f;
|
||||
}
|
||||
|
||||
if (y >= state.Unknown10 || unknown10OutOfRange)
|
||||
{
|
||||
float tmpGain;
|
||||
|
||||
if (y >= state.Unknown14)
|
||||
{
|
||||
tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpGain = (y - state.Unknown10) * ((y - state.Unknown10) * -state.CompressorGainReduction);
|
||||
}
|
||||
|
||||
z = FloatingPointHelper.DecibelToLinearExtended(tmpGain);
|
||||
}
|
||||
|
||||
float unknown4New = z;
|
||||
float compressionEmaAlpha;
|
||||
|
||||
if ((unknown4 - z) <= 0.08f)
|
||||
{
|
||||
compressionEmaAlpha = Parameter.ReleaseCoefficient;
|
||||
|
||||
if ((unknown4 - z) >= -0.08f)
|
||||
{
|
||||
if (MathF.Abs(compressionGainAverage.Read() - z) >= 0.001f)
|
||||
{
|
||||
unknown4New = unknown4;
|
||||
}
|
||||
|
||||
compressionEmaAlpha = previousCompressionEmaAlpha;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compressionEmaAlpha = Parameter.AttackCoefficient;
|
||||
}
|
||||
|
||||
float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
|
||||
|
||||
for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
|
||||
{
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
|
||||
}
|
||||
|
||||
unknown4 = unknown4New;
|
||||
previousCompressionEmaAlpha = compressionEmaAlpha;
|
||||
}
|
||||
|
||||
state.InputMovingAverage = inputMovingAverage;
|
||||
state.Unknown4 = unknown4;
|
||||
state.CompressionGainAverage = compressionGainAverage;
|
||||
state.PreviousCompressionEmaAlpha = previousCompressionEmaAlpha;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
if (InputBufferIndices[i] != OutputBufferIndices[i])
|
||||
{
|
||||
context.CopyBuffer(OutputBufferIndices[i], InputBufferIndices[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.CopyMixBuffer;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType { get; }
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort OutputBufferIndex { get; }
|
||||
public uint SampleRate { get; }
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Delay;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public DelayParameter Parameter => _parameter;
|
||||
public Memory<DelayState> State { get; }
|
||||
@ -49,15 +49,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
}
|
||||
|
||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||
// TODO: Update delay processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
|
||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
|
||||
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
|
||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
|
||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private unsafe void ProcessDelayMono(ref DelayState state, float* outputBuffer, float* inputBuffer, uint sampleCount)
|
||||
{
|
||||
const ushort channelCount = 1;
|
||||
|
||||
float feedbackGain = FixedPointHelper.ToFloat(Parameter.FeedbackGain, FixedPointPrecision);
|
||||
float inGain = FixedPointHelper.ToFloat(Parameter.InGain, FixedPointPrecision);
|
||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||
@ -70,7 +70,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
float temp = input * inGain + delayLineValue * feedbackGain;
|
||||
|
||||
state.UpdateLowPassFilter(ref temp, 1);
|
||||
state.UpdateLowPassFilter(ref temp, channelCount);
|
||||
|
||||
outputBuffer[i] = (input * dryGain + delayLineValue * outGain) / 64;
|
||||
}
|
||||
@ -104,7 +104,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
Y = state.DelayLines[1].Read(),
|
||||
};
|
||||
|
||||
Vector2 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
||||
Vector2 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||
|
||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector2, float>(ref temp), channelCount);
|
||||
|
||||
@ -148,7 +148,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
W = state.DelayLines[3].Read()
|
||||
};
|
||||
|
||||
Vector4 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
||||
Vector4 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||
|
||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector4, float>(ref temp), channelCount);
|
||||
|
||||
@ -171,12 +171,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
float dryGain = FixedPointHelper.ToFloat(Parameter.DryGain, FixedPointPrecision);
|
||||
float outGain = FixedPointHelper.ToFloat(Parameter.OutGain, FixedPointPrecision);
|
||||
|
||||
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain,
|
||||
0.0f, delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f,
|
||||
delayFeedbackCrossGain, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f,
|
||||
0.0f, delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f,
|
||||
delayFeedbackCrossGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackBaseGain, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, feedbackGain);
|
||||
Matrix6x6 delayFeedback = new Matrix6x6(delayFeedbackBaseGain, 0.0f, delayFeedbackCrossGain, 0.0f, delayFeedbackCrossGain, 0.0f,
|
||||
0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain,
|
||||
delayFeedbackCrossGain, delayFeedbackCrossGain, delayFeedbackBaseGain, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, feedbackGain, 0.0f, 0.0f,
|
||||
delayFeedbackCrossGain, 0.0f, 0.0f, 0.0f, delayFeedbackBaseGain, delayFeedbackCrossGain,
|
||||
0.0f, delayFeedbackCrossGain, 0.0f, 0.0f, delayFeedbackCrossGain, delayFeedbackBaseGain);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@ -200,7 +200,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
U = state.DelayLines[5].Read()
|
||||
};
|
||||
|
||||
Vector6 temp = MatrixHelper.Transform(ref channelInput, ref delayFeedback) + channelInput * inGain;
|
||||
Vector6 temp = MatrixHelper.Transform(ref delayLineValues, ref delayFeedback) + channelInput * inGain;
|
||||
|
||||
state.UpdateLowPassFilter(ref Unsafe.As<Vector6, float>(ref temp), channelCount);
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.DepopForMixBuffers;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint MixBufferOffset { get; }
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.DepopPrepare;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint MixBufferCount { get; }
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.DeviceSink;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public string DeviceName { get; }
|
||||
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.DownMixSurroundToStereo;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort[] InputBufferIndices { get; }
|
||||
public ushort[] OutputBufferIndices { get; }
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.GroupedBiquadFilter;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
private BiquadFilterParameter[] _parameters;
|
||||
private Memory<BiquadFilterState> _biquadFilterStates;
|
||||
@ -47,9 +47,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Nintendo also implements a hot path for double biquad filters, but no generic path when the command definition suggests it could be done.
|
||||
// As such we currently only implement a generic path for simplicity.
|
||||
// TODO: Implement double biquad filters fast path.
|
||||
// NOTE: Nintendo only implement single and double biquad filters but no generic path when the command definition suggests it could be done.
|
||||
// As such we currently only implement a generic path for simplicity for double biquad.
|
||||
if (_parameters.Length == 1)
|
||||
{
|
||||
BiquadFilterHelper.ProcessBiquadFilter(ref _parameters[0], ref states[0], outputBuffer, inputBuffer, context.SampleCount);
|
||||
|
@ -8,7 +8,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType { get; }
|
||||
|
||||
public ulong EstimatedProcessingTime { get; }
|
||||
public uint EstimatedProcessingTime { get; }
|
||||
|
||||
public void Process(CommandList context);
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.LimiterVersion1;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public LimiterParameter Parameter => _parameter;
|
||||
public Memory<LimiterState> State { get; }
|
||||
@ -90,32 +90,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
if (sampleInputMax > state.DectectorAverage[channelIndex])
|
||||
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
|
||||
{
|
||||
inputCoefficient = Parameter.AttackCoefficient;
|
||||
}
|
||||
|
||||
state.DectectorAverage[channelIndex] += inputCoefficient * (sampleInputMax - state.DectectorAverage[channelIndex]);
|
||||
|
||||
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
|
||||
float attenuation = 1.0f;
|
||||
|
||||
if (state.DectectorAverage[channelIndex] > Parameter.Threshold)
|
||||
if (detectorValue > Parameter.Threshold)
|
||||
{
|
||||
attenuation = Parameter.Threshold / state.DectectorAverage[channelIndex];
|
||||
attenuation = Parameter.Threshold / detectorValue;
|
||||
}
|
||||
|
||||
float outputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
if (state.CompressionGain[channelIndex] > attenuation)
|
||||
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
|
||||
{
|
||||
outputCoefficient = Parameter.AttackCoefficient;
|
||||
}
|
||||
|
||||
state.CompressionGain[channelIndex] += outputCoefficient * (attenuation - state.CompressionGain[channelIndex]);
|
||||
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
|
||||
|
||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||
|
||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.LimiterVersion2;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public LimiterParameter Parameter => _parameter;
|
||||
public Memory<LimiterState> State { get; }
|
||||
@ -101,32 +101,31 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
float inputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
if (sampleInputMax > state.DectectorAverage[channelIndex])
|
||||
if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
|
||||
{
|
||||
inputCoefficient = Parameter.AttackCoefficient;
|
||||
}
|
||||
|
||||
state.DectectorAverage[channelIndex] += inputCoefficient * (sampleInputMax - state.DectectorAverage[channelIndex]);
|
||||
|
||||
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
|
||||
float attenuation = 1.0f;
|
||||
|
||||
if (state.DectectorAverage[channelIndex] > Parameter.Threshold)
|
||||
if (detectorValue > Parameter.Threshold)
|
||||
{
|
||||
attenuation = Parameter.Threshold / state.DectectorAverage[channelIndex];
|
||||
attenuation = Parameter.Threshold / detectorValue;
|
||||
}
|
||||
|
||||
float outputCoefficient = Parameter.ReleaseCoefficient;
|
||||
|
||||
if (state.CompressionGain[channelIndex] > attenuation)
|
||||
if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
|
||||
{
|
||||
outputCoefficient = Parameter.AttackCoefficient;
|
||||
}
|
||||
|
||||
state.CompressionGain[channelIndex] += outputCoefficient * (attenuation - state.CompressionGain[channelIndex]);
|
||||
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
|
||||
|
||||
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
|
||||
|
||||
float outputSample = delayedSample * state.CompressionGain[channelIndex] * Parameter.OutputGain;
|
||||
float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
|
||||
|
||||
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
|
||||
|
||||
@ -144,7 +143,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||
|
||||
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], state.CompressionGain[channelIndex]);
|
||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Mix;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.MixRamp;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.MixRampGrouped;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint MixBufferCount { get; }
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.PcmFloatDataSourceVersion1;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort OutputBufferIndex { get; }
|
||||
public uint SampleRate { get; }
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.PcmInt16DataSourceVersion1;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort OutputBufferIndex { get; }
|
||||
public uint SampleRate { get; }
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Performance;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public PerformanceEntryAddresses PerformanceEntryAddresses { get; }
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Reverb3d;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Reverb;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ReverbParameter Parameter => _parameter;
|
||||
public Memory<ReverbState> State { get; }
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Upsample;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public uint BufferCount { get; }
|
||||
public uint InputBufferIndex { get; }
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.Volume;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -11,7 +11,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public CommandType CommandType => CommandType.VolumeRamp;
|
||||
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
public ushort InputBufferIndex { get; }
|
||||
public ushort OutputBufferIndex { get; }
|
||||
|
@ -0,0 +1,26 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Effect
|
||||
{
|
||||
public struct ExponentialMovingAverage
|
||||
{
|
||||
private float _mean;
|
||||
|
||||
public ExponentialMovingAverage(float mean)
|
||||
{
|
||||
_mean = mean;
|
||||
}
|
||||
|
||||
public float Read()
|
||||
{
|
||||
return _mean;
|
||||
}
|
||||
|
||||
public float Update(float value, float alpha)
|
||||
{
|
||||
_mean += alpha * (value - _mean);
|
||||
|
||||
return _mean;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return (float)value / (1 << qBits);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float ConvertFloat(float value, int qBits)
|
||||
{
|
||||
return value / (1 << qBits);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int ToFixed(float value, int qBits)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp
|
||||
@ -46,6 +47,53 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
return MathF.Pow(10, x);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float Log10(float x)
|
||||
{
|
||||
// NOTE: Nintendo uses an approximation of log10, we don't.
|
||||
// As such, we support the same ranges as Nintendo to avoid unexpected behaviours.
|
||||
return MathF.Pow(10, MathF.Max(x, 1.0e-10f));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float MeanSquare(ReadOnlySpan<float> inputs)
|
||||
{
|
||||
float res = 0.0f;
|
||||
|
||||
foreach (float input in inputs)
|
||||
{
|
||||
res += (input * input);
|
||||
}
|
||||
|
||||
res /= inputs.Length;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map decibel to linear.
|
||||
/// </summary>
|
||||
/// <param name="db">The decibel value to convert</param>
|
||||
/// <returns>Converted linear value/returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DecibelToLinear(float db)
|
||||
{
|
||||
return MathF.Pow(10.0f, db / 20.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Map decibel to linear in [0, 2] range.
|
||||
/// </summary>
|
||||
/// <param name="db">The decibel value to convert</param>
|
||||
/// <returns>Converted linear value in [0, 2] range</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DecibelToLinearExtended(float db)
|
||||
{
|
||||
float tmp = MathF.Log2(DecibelToLinear(db));
|
||||
|
||||
return MathF.Truncate(tmp) + MathF.Pow(2.0f, tmp - MathF.Truncate(tmp));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DegreesToRadians(float degrees)
|
||||
{
|
||||
|
51
Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs
Normal file
51
Ryujinx.Audio/Renderer/Dsp/State/CompressorState.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||
{
|
||||
public class CompressorState
|
||||
{
|
||||
public ExponentialMovingAverage InputMovingAverage;
|
||||
public float Unknown4;
|
||||
public ExponentialMovingAverage CompressionGainAverage;
|
||||
public float CompressorGainReduction;
|
||||
public float Unknown10;
|
||||
public float Unknown14;
|
||||
public float PreviousCompressionEmaAlpha;
|
||||
public float MakeupGain;
|
||||
public float OutputGain;
|
||||
|
||||
public CompressorState(ref CompressorParameter parameter)
|
||||
{
|
||||
InputMovingAverage = new ExponentialMovingAverage(0.0f);
|
||||
Unknown4 = 1.0f;
|
||||
CompressionGainAverage = new ExponentialMovingAverage(1.0f);
|
||||
|
||||
UpdateParameter(ref parameter);
|
||||
}
|
||||
|
||||
public void UpdateParameter(ref CompressorParameter parameter)
|
||||
{
|
||||
float threshold = parameter.Threshold;
|
||||
float ratio = 1.0f / parameter.Ratio;
|
||||
float attackCoefficient = parameter.AttackCoefficient;
|
||||
float makeupGain;
|
||||
|
||||
if (parameter.MakeupGainEnabled)
|
||||
{
|
||||
makeupGain = (threshold * 0.5f * (ratio - 1.0f)) - 3.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
makeupGain = 0.0f;
|
||||
}
|
||||
|
||||
PreviousCompressionEmaAlpha = attackCoefficient;
|
||||
MakeupGain = makeupGain;
|
||||
CompressorGainReduction = (1.0f - ratio) / Constants.ChannelCountMax;
|
||||
Unknown10 = threshold - 1.5f;
|
||||
Unknown14 = threshold + 1.5f;
|
||||
OutputGain = FloatingPointHelper.DecibelToLinearExtended(parameter.OutputGain + makeupGain);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using Ryujinx.Audio.Renderer.Dsp.Effect;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using System;
|
||||
|
||||
@ -5,20 +6,20 @@ namespace Ryujinx.Audio.Renderer.Dsp.State
|
||||
{
|
||||
public class LimiterState
|
||||
{
|
||||
public float[] DectectorAverage;
|
||||
public float[] CompressionGain;
|
||||
public ExponentialMovingAverage[] DetectorAverage;
|
||||
public ExponentialMovingAverage[] CompressionGainAverage;
|
||||
public float[] DelayedSampleBuffer;
|
||||
public int[] DelayedSampleBufferPosition;
|
||||
|
||||
public LimiterState(ref LimiterParameter parameter, ulong workBuffer)
|
||||
{
|
||||
DectectorAverage = new float[parameter.ChannelCount];
|
||||
CompressionGain = new float[parameter.ChannelCount];
|
||||
DetectorAverage = new ExponentialMovingAverage[parameter.ChannelCount];
|
||||
CompressionGainAverage = new ExponentialMovingAverage[parameter.ChannelCount];
|
||||
DelayedSampleBuffer = new float[parameter.ChannelCount * parameter.DelayBufferSampleCountMax];
|
||||
DelayedSampleBufferPosition = new int[parameter.ChannelCount];
|
||||
|
||||
DectectorAverage.AsSpan().Fill(0.0f);
|
||||
CompressionGain.AsSpan().Fill(1.0f);
|
||||
DetectorAverage.AsSpan().Fill(new ExponentialMovingAverage(0.0f));
|
||||
CompressionGainAverage.AsSpan().Fill(new ExponentialMovingAverage(1.0f));
|
||||
DelayedSampleBufferPosition.AsSpan().Fill(0);
|
||||
DelayedSampleBuffer.AsSpan().Fill(0.0f);
|
||||
|
||||
|
115
Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
Normal file
115
Ryujinx.Audio/Renderer/Parameter/Effect/CompressorParameter.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using Ryujinx.Audio.Renderer.Server.Effect;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Parameter.Effect
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="IEffectInParameter.SpecificData"/> for <see cref="Common.EffectType.Compressor"/>.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct CompressorParameter
|
||||
{
|
||||
/// <summary>
|
||||
/// The input channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||
/// </summary>
|
||||
public Array6<byte> Input;
|
||||
|
||||
/// <summary>
|
||||
/// The output channel indices that will be used by the <see cref="Dsp.AudioProcessor"/>.
|
||||
/// </summary>
|
||||
public Array6<byte> Output;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of channels supported.
|
||||
/// </summary>
|
||||
public ushort ChannelCountMax;
|
||||
|
||||
/// <summary>
|
||||
/// The total channel count used.
|
||||
/// </summary>
|
||||
public ushort ChannelCount;
|
||||
|
||||
/// <summary>
|
||||
/// The target sample rate.
|
||||
/// </summary>
|
||||
/// <remarks>This is in kHz.</remarks>
|
||||
public int SampleRate;
|
||||
|
||||
/// <summary>
|
||||
/// The threshold.
|
||||
/// </summary>
|
||||
public float Threshold;
|
||||
|
||||
/// <summary>
|
||||
/// The compressor ratio.
|
||||
/// </summary>
|
||||
public float Ratio;
|
||||
|
||||
/// <summary>
|
||||
/// The attack time.
|
||||
/// <remarks>This is in microseconds.</remarks>
|
||||
/// </summary>
|
||||
public int AttackTime;
|
||||
|
||||
/// <summary>
|
||||
/// The release time.
|
||||
/// <remarks>This is in microseconds.</remarks>
|
||||
/// </summary>
|
||||
public int ReleaseTime;
|
||||
|
||||
/// <summary>
|
||||
/// The input gain.
|
||||
/// </summary>
|
||||
public float InputGain;
|
||||
|
||||
/// <summary>
|
||||
/// The attack coefficient.
|
||||
/// </summary>
|
||||
public float AttackCoefficient;
|
||||
|
||||
/// <summary>
|
||||
/// The release coefficient.
|
||||
/// </summary>
|
||||
public float ReleaseCoefficient;
|
||||
|
||||
/// <summary>
|
||||
/// The output gain.
|
||||
/// </summary>
|
||||
public float OutputGain;
|
||||
|
||||
/// <summary>
|
||||
/// The current usage status of the effect on the client side.
|
||||
/// </summary>
|
||||
public UsageState Status;
|
||||
|
||||
/// <summary>
|
||||
/// Indicate if the makeup gain should be used.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool MakeupGainEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Reserved/padding.
|
||||
/// </summary>
|
||||
private Array2<byte> _reserved;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the <see cref="ChannelCount"/> is valid.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the <see cref="ChannelCount"/> is valid.</returns>
|
||||
public bool IsChannelCountValid()
|
||||
{
|
||||
return EffectInParameterVersion1.IsChannelCountValid(ChannelCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the <see cref="ChannelCountMax"/> is valid.
|
||||
/// </summary>
|
||||
/// <returns>Returns true if the <see cref="ChannelCountMax"/> is valid.</returns>
|
||||
public bool IsChannelCountMaxValid()
|
||||
{
|
||||
return EffectInParameterVersion1.IsChannelCountValid(ChannelCountMax);
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
private object _lock = new object();
|
||||
|
||||
private AudioRendererRenderingDevice _renderingDevice;
|
||||
private AudioRendererExecutionMode _executionMode;
|
||||
private IWritableEvent _systemEvent;
|
||||
private ManualResetEvent _terminationEvent;
|
||||
@ -63,6 +64,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private uint _renderingTimeLimitPercent;
|
||||
private bool _voiceDropEnabled;
|
||||
private uint _voiceDropCount;
|
||||
private float _voiceDropParameter;
|
||||
private bool _isDspRunningBehind;
|
||||
|
||||
private ICommandProcessingTimeEstimator _commandProcessingTimeEstimator;
|
||||
@ -95,6 +97,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_totalElapsedTicksUpdating = 0;
|
||||
_sessionId = 0;
|
||||
_voiceDropParameter = 1.0f;
|
||||
}
|
||||
|
||||
public ResultCode Initialize(
|
||||
@ -130,6 +133,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_upsamplerCount = parameter.SinkCount + parameter.SubMixBufferCount;
|
||||
_appletResourceId = appletResourceId;
|
||||
_memoryPoolCount = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
|
||||
_renderingDevice = parameter.RenderingDevice;
|
||||
_executionMode = parameter.ExecutionMode;
|
||||
_sessionId = sessionId;
|
||||
MemoryManager = memoryManager;
|
||||
@ -337,6 +341,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_processHandle = processHandle;
|
||||
_elapsedFrameCount = 0;
|
||||
_voiceDropParameter = 1.0f;
|
||||
|
||||
switch (_behaviourContext.GetCommandProcessingTimeEstimatorVersion())
|
||||
{
|
||||
@ -515,7 +520,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
return (ulong)(_manager.TickSource.ElapsedSeconds * Constants.TargetTimerFrequency);
|
||||
}
|
||||
|
||||
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, long voicesEstimatedTime, long deltaTimeDsp)
|
||||
private uint ComputeVoiceDrop(CommandBuffer commandBuffer, uint voicesEstimatedTime, long deltaTimeDsp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -584,7 +589,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
command.Enabled = false;
|
||||
|
||||
voicesEstimatedTime -= (long)command.EstimatedProcessingTime;
|
||||
voicesEstimatedTime -= (uint)(_voiceDropParameter * command.EstimatedProcessingTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,13 +623,13 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
_voiceContext.Sort();
|
||||
commandGenerator.GenerateVoices();
|
||||
|
||||
long voicesEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
||||
uint voicesEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||
|
||||
commandGenerator.GenerateSubMixes();
|
||||
commandGenerator.GenerateFinalMixes();
|
||||
commandGenerator.GenerateSinks();
|
||||
|
||||
long totalEstimatedTime = (long)commandBuffer.EstimatedProcessingTime;
|
||||
uint totalEstimatedTime = (uint)(_voiceDropParameter * commandBuffer.EstimatedProcessingTime);
|
||||
|
||||
if (_voiceDropEnabled)
|
||||
{
|
||||
@ -665,14 +670,21 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
_terminationEvent.Reset();
|
||||
|
||||
GenerateCommandList(out CommandList commands);
|
||||
if (!_manager.Processor.HasRemainingCommands(_sessionId))
|
||||
{
|
||||
GenerateCommandList(out CommandList commands);
|
||||
|
||||
_manager.Processor.Send(_sessionId,
|
||||
commands,
|
||||
GetMaxAllocatedTimeForDsp(),
|
||||
_appletResourceId);
|
||||
_manager.Processor.Send(_sessionId,
|
||||
commands,
|
||||
GetMaxAllocatedTimeForDsp(),
|
||||
_appletResourceId);
|
||||
|
||||
_systemEvent.Signal();
|
||||
_systemEvent.Signal();
|
||||
}
|
||||
else
|
||||
{
|
||||
_isDspRunningBehind = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -856,5 +868,26 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVoiceDropParameter(float voiceDropParameter)
|
||||
{
|
||||
_voiceDropParameter = Math.Clamp(voiceDropParameter, 0.0f, 2.0f);
|
||||
}
|
||||
|
||||
public float GetVoiceDropParameter()
|
||||
{
|
||||
return _voiceDropParameter;
|
||||
}
|
||||
|
||||
public ResultCode ExecuteAudioRendererRendering()
|
||||
{
|
||||
if (_executionMode == AudioRendererExecutionMode.Manual && _renderingDevice == AudioRendererRenderingDevice.Cpu)
|
||||
{
|
||||
// NOTE: Here Nintendo aborts with this error code, we don't want that.
|
||||
return ResultCode.InvalidExecutionContextOperation;
|
||||
}
|
||||
|
||||
return ResultCode.UnsupportedOperation;
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <see cref="Parameter.RendererInfoOutStatus"/> was added to supply the count of update done sent to the DSP.
|
||||
/// A new version of the command estimator was added to address timing changes caused by the voice changes.
|
||||
/// Additionally, the rendering limit percent was incremented to 80%.
|
||||
///
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>This was added in system update 6.0.0</remarks>
|
||||
public const int Revision5 = 5 << 24;
|
||||
@ -93,9 +93,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// REV11:
|
||||
/// The "legacy" effects (Delay, Reverb and Reverb 3D) were updated to match the standard channel mapping used by the audio renderer.
|
||||
/// A new effect was added: Compressor. This effect is effectively implemented with a DRC.
|
||||
/// A new version of the command estimator was added to address timing changes caused by the legacy effects changes.
|
||||
/// A voice drop parameter was added in 15.0.0: This allows an application to amplify or attenuate the estimated time of DSP commands.
|
||||
/// </summary>
|
||||
/// <remarks>This was added in system update 14.0.0</remarks>
|
||||
/// <remarks>This was added in system update 14.0.0 but some changes were made in 15.0.0</remarks>
|
||||
public const int Revision11 = 11 << 24;
|
||||
|
||||
/// <summary>
|
||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
/// <summary>
|
||||
/// The estimated total processing time.
|
||||
/// </summary>
|
||||
public ulong EstimatedProcessingTime { get; set; }
|
||||
public uint EstimatedProcessingTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The command list that is populated by the <see cref="CommandBuffer"/>.
|
||||
@ -469,6 +469,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
|
||||
{
|
||||
if (parameter.IsChannelCountValid())
|
||||
{
|
||||
CompressorCommand command = new CompressorCommand(bufferOffset, parameter, state, isEnabled, nodeId);
|
||||
|
||||
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);
|
||||
|
||||
AddCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate a new <see cref="VolumeCommand"/>.
|
||||
/// </summary>
|
||||
|
@ -606,6 +606,17 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
|
||||
{
|
||||
Debug.Assert(effect.Type == EffectType.Compressor);
|
||||
|
||||
_commandBuffer.GenerateCompressorEffect(bufferOffset,
|
||||
effect.Parameter,
|
||||
effect.State,
|
||||
effect.IsEnabled,
|
||||
nodeId);
|
||||
}
|
||||
|
||||
private void GenerateEffect(ref MixState mix, int effectId, BaseEffect effect)
|
||||
{
|
||||
int nodeId = mix.NodeId;
|
||||
@ -650,6 +661,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
case EffectType.CaptureBuffer:
|
||||
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
|
||||
break;
|
||||
case EffectType.Compressor:
|
||||
GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Unsupported effect type {effect.Type}");
|
||||
}
|
||||
|
@ -179,5 +179,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint Estimate(CompressorCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -543,5 +543,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint Estimate(CompressorCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -747,5 +747,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public virtual uint Estimate(CompressorCommand command)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -232,5 +232,79 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override uint Estimate(CompressorCommand command)
|
||||
{
|
||||
Debug.Assert(_sampleCount == 160 || _sampleCount == 240);
|
||||
|
||||
if (_sampleCount == 160)
|
||||
{
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 34431;
|
||||
case 2:
|
||||
return 44253;
|
||||
case 4:
|
||||
return 63827;
|
||||
case 6:
|
||||
return 83361;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)630.12f;
|
||||
case 2:
|
||||
return (uint)638.27f;
|
||||
case 4:
|
||||
return (uint)705.86f;
|
||||
case 6:
|
||||
return (uint)782.02f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Enabled)
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return 51095;
|
||||
case 2:
|
||||
return 65693;
|
||||
case 4:
|
||||
return 95383;
|
||||
case 6:
|
||||
return 124510;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (command.Parameter.ChannelCount)
|
||||
{
|
||||
case 1:
|
||||
return (uint)840.14f;
|
||||
case 2:
|
||||
return (uint)826.1f;
|
||||
case 4:
|
||||
return (uint)901.88f;
|
||||
case 6:
|
||||
return (uint)965.29f;
|
||||
default:
|
||||
throw new NotImplementedException($"{command.Parameter.ChannelCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -262,6 +262,8 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
return PerformanceDetailType.Limiter;
|
||||
case EffectType.CaptureBuffer:
|
||||
return PerformanceDetailType.CaptureBuffer;
|
||||
case EffectType.Compressor:
|
||||
return PerformanceDetailType.Compressor;
|
||||
default:
|
||||
throw new NotImplementedException($"{Type}");
|
||||
}
|
||||
|
67
Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
Normal file
67
Ryujinx.Audio/Renderer/Server/Effect/CompressorEffect.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using Ryujinx.Audio.Renderer.Common;
|
||||
using Ryujinx.Audio.Renderer.Dsp.State;
|
||||
using Ryujinx.Audio.Renderer.Parameter.Effect;
|
||||
using Ryujinx.Audio.Renderer.Parameter;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Server.Effect
|
||||
{
|
||||
/// <summary>
|
||||
/// Server state for a compressor effect.
|
||||
/// </summary>
|
||||
public class CompressorEffect : BaseEffect
|
||||
{
|
||||
/// <summary>
|
||||
/// The compressor parameter.
|
||||
/// </summary>
|
||||
public CompressorParameter Parameter;
|
||||
|
||||
/// <summary>
|
||||
/// The compressor state.
|
||||
/// </summary>
|
||||
public Memory<CompressorState> State { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="CompressorEffect"/>.
|
||||
/// </summary>
|
||||
public CompressorEffect()
|
||||
{
|
||||
State = new CompressorState[1];
|
||||
}
|
||||
|
||||
public override EffectType TargetEffectType => EffectType.Compressor;
|
||||
|
||||
public override ulong GetWorkBuffer(int index)
|
||||
{
|
||||
return GetSingleBuffer();
|
||||
}
|
||||
|
||||
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion1 parameter, PoolMapper mapper)
|
||||
{
|
||||
// Nintendo doesn't do anything here but we still require updateErrorInfo to be initialised.
|
||||
updateErrorInfo = new BehaviourParameter.ErrorInfo();
|
||||
}
|
||||
|
||||
public override void Update(out BehaviourParameter.ErrorInfo updateErrorInfo, ref EffectInParameterVersion2 parameter, PoolMapper mapper)
|
||||
{
|
||||
Debug.Assert(IsTypeValid(ref parameter));
|
||||
|
||||
UpdateParameterBase(ref parameter);
|
||||
|
||||
Parameter = MemoryMarshal.Cast<byte, CompressorParameter>(parameter.SpecificData)[0];
|
||||
IsEnabled = parameter.IsEnabled;
|
||||
|
||||
updateErrorInfo = new BehaviourParameter.ErrorInfo();
|
||||
}
|
||||
|
||||
public override void UpdateForCommandGeneration()
|
||||
{
|
||||
UpdateUsageStateForCommandGeneration();
|
||||
|
||||
Parameter.Status = UsageState.Enabled;
|
||||
}
|
||||
}
|
||||
}
|
@ -35,5 +35,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
uint Estimate(LimiterCommandVersion2 command);
|
||||
uint Estimate(GroupedBiquadFilterCommand command);
|
||||
uint Estimate(CaptureBufferCommand command);
|
||||
uint Estimate(CompressorCommand command);
|
||||
}
|
||||
}
|
@ -263,12 +263,12 @@ namespace Ryujinx.Audio.Renderer.Server.MemoryPool
|
||||
return UpdateResult.Success;
|
||||
}
|
||||
|
||||
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress & (pageSize - 1)) != 0)
|
||||
if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0)
|
||||
{
|
||||
return UpdateResult.InvalidParameter;
|
||||
}
|
||||
|
||||
if (inParameter.Size == 0 || (inParameter.Size & (pageSize - 1)) != 0)
|
||||
if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0)
|
||||
{
|
||||
return UpdateResult.InvalidParameter;
|
||||
}
|
||||
|
@ -240,6 +240,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
case EffectType.CaptureBuffer:
|
||||
effect = new CaptureBufferEffect();
|
||||
break;
|
||||
case EffectType.Compressor:
|
||||
effect = new CompressorEffect();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotImplementedException($"EffectType {parameter.Type} not implemented!");
|
||||
}
|
||||
|
@ -17,5 +17,6 @@ namespace Ryujinx.Audio
|
||||
InvalidAddressInfo = (42 << ErrorCodeShift) | ModuleId,
|
||||
InvalidMixSorting = (43 << ErrorCodeShift) | ModuleId,
|
||||
UnsupportedOperation = (513 << ErrorCodeShift) | ModuleId,
|
||||
InvalidExecutionContextOperation = (514 << ErrorCodeShift) | ModuleId,
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
Name = $"Ryujinx {Program.Version}";
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
private const float VolumeDelta = 0.05f;
|
||||
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
|
||||
private readonly long _ticksPerFrame;
|
||||
private readonly Stopwatch _chrono;
|
||||
@ -125,7 +125,7 @@ namespace Ryujinx.Ava
|
||||
_inputManager = inputManager;
|
||||
_accountManager = accountManager;
|
||||
_userChannelPersistence = userChannelPersistence;
|
||||
_renderingThread = new Thread(RenderLoop) { Name = "GUI.RenderThread" };
|
||||
_renderingThread = new Thread(RenderLoop, 1 * 1024 * 1024) { Name = "GUI.RenderThread" };
|
||||
_hideCursorOnIdle = ConfigurationState.Instance.HideCursorOnIdle;
|
||||
_lastCursorMoveTime = Stopwatch.GetTimestamp();
|
||||
_glLogLevel = ConfigurationState.Instance.Logger.GraphicsDebugLevel;
|
||||
@ -349,7 +349,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
_isActive = false;
|
||||
|
||||
_renderingThread.Join();
|
||||
if (_renderingThread.IsAlive)
|
||||
{
|
||||
_renderingThread.Join();
|
||||
}
|
||||
|
||||
DisplaySleep.Restore();
|
||||
|
||||
@ -378,7 +381,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
_gpuCancellationTokenSource.Dispose();
|
||||
|
||||
|
||||
_chrono.Stop();
|
||||
}
|
||||
|
||||
@ -393,7 +396,7 @@ namespace Ryujinx.Ava
|
||||
Renderer?.MakeCurrent();
|
||||
|
||||
Device.DisposeGpu();
|
||||
|
||||
|
||||
Renderer?.MakeCurrent(null);
|
||||
}
|
||||
|
||||
@ -417,7 +420,6 @@ namespace Ryujinx.Ava
|
||||
public async Task<bool> LoadGuestApplication()
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@ -428,17 +430,16 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
if (userError == UserError.NoFirmware)
|
||||
{
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
|
||||
firmwareVersion.VersionString);
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
"");
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@ -447,8 +448,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@ -461,11 +461,9 @@ namespace Ryujinx.Ava
|
||||
|
||||
_parent.RefreshFirmwareStatus();
|
||||
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||
message,
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
@ -473,9 +471,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@ -514,7 +510,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
{
|
||||
@ -602,7 +598,7 @@ namespace Ryujinx.Ava
|
||||
if (Renderer.IsVulkan)
|
||||
{
|
||||
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||
|
||||
|
||||
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||
}
|
||||
else
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Aktiviere Fs Zugriff-Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Globaler Zugriff-Log-Modus:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Entwickleroptionen (WARNUNG: Beeinträchtigt die Leistung)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Logstufe:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Keine",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Fehler",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Verlangsamungen",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Alle",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Keine",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Fehler",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Verlangsamungen",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Alle",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Aktiviere Debug-Log",
|
||||
"SettingsTabInput": "Eingabe",
|
||||
"SettingsTabInputEnableDockedMode": "Docked Modus",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Direkter Tastaturzugriff",
|
||||
"SettingsButtonSave": "Speichern",
|
||||
"SettingsButtonClose": "Schließen",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Abbrechen",
|
||||
"SettingsButtonApply": "Übernehmen",
|
||||
"ControllerSettingsPlayer": "Spieler",
|
||||
"ControllerSettingsPlayer1": "Spieler 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Ενεργοποίηση Καταγραφής Πρόσβασης FS",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Λειτουργία Καταγραφής Καθολικής Πρόσβασης FS:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Επιλογές Προγραμματιστή (ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Η απόδοση Θα μειωθεί)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Επίπεδο Καταγραφής OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Κανένα",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Σφάλμα",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Επιβραδύνσεις",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Όλα",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Κανένα",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Σφάλμα",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Επιβραδύνσεις",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Όλα",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Ενεργοποίηση Αρχείων Καταγραφής Εντοπισμού Σφαλμάτων",
|
||||
"SettingsTabInput": "Χειρισμός",
|
||||
"SettingsTabInputEnableDockedMode": "Ενεργοποίηση Docked Mode",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Άμεση Πρόσβαση στο Πληκτρολόγιο",
|
||||
"SettingsButtonSave": "Αποθήκευση",
|
||||
"SettingsButtonClose": "Κλείσιμο",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Ακύρωση",
|
||||
"SettingsButtonApply": "Εφαρμογή",
|
||||
"ControllerSettingsPlayer": "Παίχτης",
|
||||
"ControllerSettingsPlayer1": "Παίχτης 1",
|
||||
|
@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (may cause instability)",
|
||||
"SettingsTabSystemExpandDramSize": "Expand DRAM Size to 6GiB",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
"SettingsTabGraphicsAPI": "Graphics API",
|
||||
@ -157,17 +157,19 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Enable Fs Access Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Global Access Log Mode:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Developer Options (WARNING: Will reduce performance)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Log Level:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "None",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Error",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Slowdowns",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "All",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevel": "Graphics Backend Log Level:",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "None",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Error",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Slowdowns",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "All",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Enable Debug Logs",
|
||||
"SettingsTabInput": "Input",
|
||||
"SettingsTabInputEnableDockedMode": "Docked Mode",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Direct Keyboard Access",
|
||||
"SettingsButtonSave": "Save",
|
||||
"SettingsButtonClose": "Close",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Cancel",
|
||||
"SettingsButtonApply": "Apply",
|
||||
"ControllerSettingsPlayer": "Player",
|
||||
"ControllerSettingsPlayer1": "Player 1",
|
||||
@ -410,6 +412,8 @@
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
||||
"DlcManagerRemoveAllButton": "Remove All",
|
||||
"DlcManagerEnableAllButton": "Enable All",
|
||||
"DlcManagerDisableAllButton": "Disable All",
|
||||
"MenuBarOptionsChangeLanguage": "Change Language",
|
||||
"CommonSort": "Sort",
|
||||
"CommonShowNames": "Show Names",
|
||||
@ -440,7 +444,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"DRamTooltip": "Increases the amount of memory on the emulated system from 4GiB to 6GiB.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@ -562,12 +566,12 @@
|
||||
"Writable": "Writable",
|
||||
"SelectDlcDialogTitle": "Select DLC files",
|
||||
"SelectUpdateDialogTitle": "Select update files",
|
||||
"UserProfileWindowTitle": "Manage User Profiles",
|
||||
"CheatWindowTitle": "Manage Game Cheats",
|
||||
"DlcWindowTitle": "Manage Game DLC",
|
||||
"UpdateWindowTitle": "Manage Game Updates",
|
||||
"UserProfileWindowTitle": "User Profiles Manager",
|
||||
"CheatWindowTitle": "Cheats Manager",
|
||||
"DlcWindowTitle": "Downloadable Content Manager",
|
||||
"UpdateWindowTitle": "Title Update Manager",
|
||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||
"DlcWindowHeading": "DLC Available for {0} [{1}]",
|
||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||
"UserProfilesEditProfile": "Edit Selected",
|
||||
"Cancel": "Cancel",
|
||||
"Save": "Save",
|
||||
@ -575,7 +579,7 @@
|
||||
"UserProfilesSetProfileImage": "Set Profile Image",
|
||||
"UserProfileEmptyNameError": "Name is required",
|
||||
"UserProfileNoImageError": "Profile image must be set",
|
||||
"GameUpdateWindowHeading": "Updates Available for {0} [{1}]",
|
||||
"GameUpdateWindowHeading": "{0} Update(s) available for {1} ({2})",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Increase resolution:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Decrease resolution:",
|
||||
"UserProfilesName": "Name:",
|
||||
@ -592,7 +596,18 @@
|
||||
"RyujinxUpdaterMessage": "Do you want to update Ryujinx to the latest version?",
|
||||
"SettingsTabHotkeysVolumeUpHotkey": "Increase Volume:",
|
||||
"SettingsTabHotkeysVolumeDownHotkey": "Decrease Volume:",
|
||||
"VolumeShort": "Vol",
|
||||
"SettingsEnableMacroHLE": "Enable Macro HLE",
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure."
|
||||
"SettingsEnableMacroHLETooltip": "High-level emulation of GPU Macro code.\n\nImproves performance, but may cause graphical glitches in some games.\n\nLeave ON if unsure.",
|
||||
"VolumeShort": "Vol",
|
||||
"UserProfilesManageSaves": "Manage Saves",
|
||||
"DeleteUserSave": "Do you want to delete user save for this game?",
|
||||
"IrreversibleActionNote": "This action is not reversible.",
|
||||
"SaveManagerHeading": "Manage Saves for {0}",
|
||||
"SaveManagerTitle": "Save Manager",
|
||||
"Name": "Name",
|
||||
"Size": "Size",
|
||||
"Search": "Search",
|
||||
"UserProfilesRecoverLostAccounts": "Recover Lost Accounts",
|
||||
"Recover": "Recover",
|
||||
"UserProfilesRecoverHeading" : "Saves were found for the following accounts"
|
||||
}
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar registros de Fs Access",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo de registros Fs Global Access:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opciones de desarrollador (ADVERTENCIA: empeorarán el rendimiento)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Nivel de registro de OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Nada",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Errores",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Ralentizaciones",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Todo",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nada",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errores",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentizaciones",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Todo",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Habilitar registros de debug",
|
||||
"SettingsTabInput": "Entrada",
|
||||
"SettingsTabInputEnableDockedMode": "Modo dock/TV",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Acceso directo al teclado",
|
||||
"SettingsButtonSave": "Guardar",
|
||||
"SettingsButtonClose": "Cerrar",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Cancelar",
|
||||
"SettingsButtonApply": "Aplicar",
|
||||
"ControllerSettingsPlayer": "Jugador",
|
||||
"ControllerSettingsPlayer1": "Jugador 1",
|
||||
|
@ -150,17 +150,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Activer les journaux des accès au système de fichiers",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Niveau des journaux des accès au système de fichiers:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Options développeur (ATTENTION: Cela peut réduire les performances)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Niveau des journaux OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Aucun",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Erreur",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Ralentissements",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Tout",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Aucun",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erreur",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Ralentissements",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tout",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Activer les journaux de debug",
|
||||
"SettingsTabInput": "Contrôles",
|
||||
"SettingsTabInputEnableDockedMode": "Active le mode station d'accueil",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accès direct au clavier",
|
||||
"SettingsButtonSave": "Enregistrer",
|
||||
"SettingsButtonClose": "Fermer",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Annuler",
|
||||
"SettingsButtonApply": "Appliquer",
|
||||
"ControllerSettingsPlayer": "Joueur",
|
||||
"ControllerSettingsPlayer1": "Joueur 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Attiva Fs Access Logs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modalità log accesso globale Fs:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opzioni da sviluppatore (AVVISO: Ridurrà le prestazioni)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Livello di log OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Nessuno",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Errore",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Rallentamenti",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Tutto",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nessuno",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Errore",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Rallentamenti",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Tutto",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Attiva logs di debug",
|
||||
"SettingsTabInput": "Input",
|
||||
"SettingsTabInputEnableDockedMode": "Attiva modalità TV",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Accesso diretto alla tastiera",
|
||||
"SettingsButtonSave": "Salva",
|
||||
"SettingsButtonClose": "Chiudi",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Cancella",
|
||||
"SettingsButtonApply": "Applica",
|
||||
"ControllerSettingsPlayer": "Giocatore",
|
||||
"ControllerSettingsPlayer1": "Giocatore 1",
|
||||
@ -556,8 +557,8 @@
|
||||
"SettingsSelectThemeFileDialogTitle" : "Seleziona file del tema",
|
||||
"SettingsXamlThemeFile" : "File del tema xaml",
|
||||
"SettingsTabHotkeysResScaleUpHotkey": "Aumentare la risoluzione:",
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:"
|
||||
"AvatarWindowTitle": "Gestisci account - Avatar"
|
||||
"SettingsTabHotkeysResScaleDownHotkey": "Diminuire la risoluzione:",
|
||||
"AvatarWindowTitle": "Gestisci account - Avatar",
|
||||
"Amiibo": "Amiibo",
|
||||
"Unknown": "Sconosciuto",
|
||||
"Usage": "Utilizzo",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs アクセスログを有効",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs グローバルアクセスログモード:",
|
||||
"SettingsTabLoggingDeveloperOptions": "開発者オプション (警告: パフォーマンスが低下します)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL ログレベル:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "なし",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "エラー",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "パフォーマンス低下",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "すべて",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "なし",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "エラー",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "パフォーマンス低下",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "すべて",
|
||||
"SettingsTabLoggingEnableDebugLogs": "デバッグログを有効",
|
||||
"SettingsTabInput": "入力",
|
||||
"SettingsTabInputEnableDockedMode": "ドッキングモード",
|
||||
"SettingsTabInputDirectKeyboardAccess": "キーボード直接アクセス",
|
||||
"SettingsButtonSave": "セーブ",
|
||||
"SettingsButtonClose": "閉じる",
|
||||
"SettingsButtonOk": "オーケー",
|
||||
"SettingsButtonCancel": "キャンセル",
|
||||
"SettingsButtonApply": "適用",
|
||||
"ControllerSettingsPlayer": "プレイヤー",
|
||||
"ControllerSettingsPlayer1": "プレイヤー 1",
|
||||
|
@ -156,17 +156,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs 액세스 로그 켜기",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs 전역 액세스 로그 모드 :",
|
||||
"SettingsTabLoggingDeveloperOptions": "개발자 옵션 (경고 : 성능이 저하됩니다.)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL 로그 수준 :",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "없음",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "오류",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "감속",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "모두",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "없음",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "오류",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "감속",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "모두",
|
||||
"SettingsTabLoggingEnableDebugLogs": "디버그 로그 사용",
|
||||
"SettingsTabInput": "입력",
|
||||
"SettingsTabInputEnableDockedMode": "도킹 모드 활성화",
|
||||
"SettingsTabInputDirectKeyboardAccess": "직접 키보드 액세스",
|
||||
"SettingsButtonSave": "구하다",
|
||||
"SettingsButtonClose": "출구",
|
||||
"SettingsButtonOk": "좋아",
|
||||
"SettingsButtonCancel": "취소",
|
||||
"SettingsButtonApply": "적용하다",
|
||||
"ControllerSettingsPlayer": "플레이어",
|
||||
"ControllerSettingsPlayer1": "플레이어 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Włącz Logi Dostępu do Systemu Plików",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Tryb Globalnych Logów Systemu Plików:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opcje programistyczne (OSTRZEŻENIE: Zmniejszą wydajność)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Poziom Logów OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Żadne",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Błędy",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Spowolnienia",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Wszystkie",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Żadne",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Błędy",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Spowolnienia",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Wszystkie",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Włącz Logi Debugowania",
|
||||
"SettingsTabInput": "Sterowanie",
|
||||
"SettingsTabInputEnableDockedMode": "Tryb Zadokowany",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Bezpośredni Dostęp do Klawiatury",
|
||||
"SettingsButtonSave": "Zapisz",
|
||||
"SettingsButtonClose": "Zamknij",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Anuluj",
|
||||
"SettingsButtonApply": "Zastosuj",
|
||||
"ControllerSettingsPlayer": "Gracz",
|
||||
"ControllerSettingsPlayer1": "Gracz 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Habilitar logs de acesso ao sistema de arquivos",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Modo global de logs do sistema de arquivos:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Opções do desenvolvedor (AVISO: Vai reduzir a performance)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Nível de log do OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Nenhum",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Erro",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Lentidão",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Todos",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Nenhum",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Erro",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Lentidão",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Todos",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Habilitar logs de depuração",
|
||||
"SettingsTabInput": "Controle",
|
||||
"SettingsTabInputEnableDockedMode": "Habilitar modo TV",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Acesso direto ao teclado",
|
||||
"SettingsButtonSave": "Salvar",
|
||||
"SettingsButtonClose": "Fechar",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Cancelar",
|
||||
"SettingsButtonApply": "Aplicar",
|
||||
"ControllerSettingsPlayer": "Jogador",
|
||||
"ControllerSettingsPlayer1": "Jogador 1",
|
||||
|
@ -156,17 +156,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Включить журналы доступа Fs",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Режим журнала глобального доступа Fs:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Параметры разработчика (ВНИМАНИЕ: снизит производительность)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "Уровень журнала OpenGL:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Ничего",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Ошибка",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Замедления",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Всё",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Ничего",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Ошибка",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Замедления",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Всё",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Включить журналы отладки",
|
||||
"SettingsTabInput": "Управление",
|
||||
"SettingsTabInputEnableDockedMode": "Включить режим закрепления",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Прямой доступ с клавиатуры",
|
||||
"SettingsButtonSave": "Сохранить",
|
||||
"SettingsButtonClose": "Закрыть",
|
||||
"SettingsButtonOk": "OK",
|
||||
"SettingsButtonCancel": "Отмена",
|
||||
"SettingsButtonApply": "Применить",
|
||||
"ControllerSettingsPlayer": "Игрок",
|
||||
"ControllerSettingsPlayer1": "Игрок 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "Fs Erişim Loglarını Etkinleştir",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "Fs Evrensel Erişim Log Modu:",
|
||||
"SettingsTabLoggingDeveloperOptions": "Geliştirici Seçenekleri (UYARI: Performansı düşürecektir)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL Log Seviyesi:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "Hiç",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "Hata",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "Yavaşlamalar",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "Her Şey",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "Hiç",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "Hata",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "Yavaşlamalar",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "Her Şey",
|
||||
"SettingsTabLoggingEnableDebugLogs": "Hata Ayıklama Loglarını Etkinleştir",
|
||||
"SettingsTabInput": "Giriş Yöntemi",
|
||||
"SettingsTabInputEnableDockedMode": "Docked Modunu Etkinleştir",
|
||||
"SettingsTabInputDirectKeyboardAccess": "Doğrudan Klavye Erişimi",
|
||||
"SettingsButtonSave": "Kaydet",
|
||||
"SettingsButtonClose": "Kapat",
|
||||
"SettingsButtonOk": "Tamam",
|
||||
"SettingsButtonCancel": "İptal",
|
||||
"SettingsButtonApply": "Uygula",
|
||||
"ControllerSettingsPlayer": "Oyuncu",
|
||||
"ControllerSettingsPlayer1": "Oyuncu 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "记录文件访问",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "记录全局文件访问模式:",
|
||||
"SettingsTabLoggingDeveloperOptions": "开发者选项 (警告: 会降低性能)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL日志级别:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "无",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "错误",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "减速",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "全部",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "无",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "错误",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "减速",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "全部",
|
||||
"SettingsTabLoggingEnableDebugLogs": "启用调试日志",
|
||||
"SettingsTabInput": "输入",
|
||||
"SettingsTabInputEnableDockedMode": "主机模式",
|
||||
"SettingsTabInputDirectKeyboardAccess": "直通键盘控制",
|
||||
"SettingsButtonSave": "保存",
|
||||
"SettingsButtonClose": "关闭",
|
||||
"SettingsButtonOk": "批准",
|
||||
"SettingsButtonCancel": "取消",
|
||||
"SettingsButtonApply": "应用",
|
||||
"ControllerSettingsPlayer": "玩家",
|
||||
"ControllerSettingsPlayer1": "玩家 1",
|
||||
|
@ -157,17 +157,18 @@
|
||||
"SettingsTabLoggingEnableFsAccessLogs": "記錄檔案存取",
|
||||
"SettingsTabLoggingFsGlobalAccessLogMode": "記錄全域檔案存取模式:",
|
||||
"SettingsTabLoggingDeveloperOptions": "開發者選項 (警告: 會降低效能)",
|
||||
"SettingsTabLoggingOpenglLogLevel": "OpenGL 日誌級別:",
|
||||
"SettingsTabLoggingOpenglLogLevelNone": "無",
|
||||
"SettingsTabLoggingOpenglLogLevelError": "錯誤",
|
||||
"SettingsTabLoggingOpenglLogLevelPerformance": "減速",
|
||||
"SettingsTabLoggingOpenglLogLevelAll": "全部",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelNone": "無",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelError": "錯誤",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelPerformance": "減速",
|
||||
"SettingsTabLoggingGraphicsBackendLogLevelAll": "全部",
|
||||
"SettingsTabLoggingEnableDebugLogs": "啟用除錯日誌",
|
||||
"SettingsTabInput": "輸入",
|
||||
"SettingsTabInputEnableDockedMode": "Docked 模式",
|
||||
"SettingsTabInputDirectKeyboardAccess": "直通鍵盤控制",
|
||||
"SettingsButtonSave": "儲存",
|
||||
"SettingsButtonClose": "關閉",
|
||||
"SettingsButtonOk": "嘛好",
|
||||
"SettingsButtonCancel": "取消",
|
||||
"SettingsButtonApply": "套用",
|
||||
"ControllerSettingsPlayer": "玩家",
|
||||
"ControllerSettingsPlayer1": "玩家 1",
|
||||
|
@ -41,6 +41,9 @@
|
||||
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" Color="{DynamicResource DataGridSelectionColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentColorBrush" Color="{DynamicResource SystemAccentColor}" />
|
||||
<SolidColorBrush x:Key="ThemeAccentBrush4" Color="{DynamicResource ThemeAccentColor4}" />
|
||||
<Color x:Key="ControlFillColorSecondary">#008AA8</Color>
|
||||
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="{StaticResource ControlFillColorSecondary}" />
|
||||
<StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
|
||||
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
|
||||
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
|
||||
@ -55,5 +58,7 @@
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="ThemeForegroundColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#3D3D3D</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#0FFFFFFF</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#1EFFFFFF</Color>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -50,5 +50,7 @@
|
||||
<Color x:Key="SystemChromeWhiteColor">#FFFFFFFF</Color>
|
||||
<Color x:Key="ThemeForegroundColor">#FF000000</Color>
|
||||
<Color x:Key="MenuFlyoutPresenterBorderColor">#C1C1C1</Color>
|
||||
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
|
||||
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -1,7 +1,6 @@
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:sys="clr-namespace:System;assembly=netstandard"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia">
|
||||
<Design.PreviewWith>
|
||||
<Border Height="2000" Padding="20">
|
||||
@ -269,13 +268,15 @@
|
||||
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
|
||||
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
|
||||
<Color x:Key="ThemeControlBorderColor">#FF505050</Color>
|
||||
<sys:Double x:Key="ScrollBarThickness">15</sys:Double>
|
||||
<sys:Double x:Key="FontSizeSmall">8</sys:Double>
|
||||
<sys:Double x:Key="FontSizeNormal">10</sys:Double>
|
||||
<sys:Double x:Key="FontSize">12</sys:Double>
|
||||
<sys:Double x:Key="FontSizeLarge">15</sys:Double>
|
||||
<sys:Double x:Key="ControlContentThemeFontSize">13</sys:Double>
|
||||
<x:Double x:Key="ScrollBarThickness">15</x:Double>
|
||||
<x:Double x:Key="FontSizeSmall">8</x:Double>
|
||||
<x:Double x:Key="FontSizeNormal">10</x:Double>
|
||||
<x:Double x:Key="FontSize">12</x:Double>
|
||||
<x:Double x:Key="FontSizeLarge">15</x:Double>
|
||||
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">600</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
@ -113,6 +113,11 @@ namespace Ryujinx.Ava.Common
|
||||
return;
|
||||
}
|
||||
|
||||
OpenSaveDir(saveDataId);
|
||||
}
|
||||
|
||||
public static void OpenSaveDir(ulong saveDataId)
|
||||
{
|
||||
string saveRootPath = Path.Combine(_virtualFileSystem.GetNandPath(), $"user/save/{saveDataId:x16}");
|
||||
|
||||
if (!Directory.Exists(saveRootPath))
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@ -93,7 +94,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
return;
|
||||
}
|
||||
|
||||
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
|
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
127
Ryujinx.Ava/Helper/MetalHelper.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Helper
|
||||
{
|
||||
public delegate void UpdateBoundsCallbackDelegate(Rect rect);
|
||||
|
||||
[SupportedOSPlatform("macos")]
|
||||
static class MetalHelper
|
||||
{
|
||||
private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";
|
||||
|
||||
private struct Selector
|
||||
{
|
||||
public readonly IntPtr NativePtr;
|
||||
|
||||
public unsafe Selector(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
NativePtr = sel_registerName(data);
|
||||
}
|
||||
|
||||
public static implicit operator Selector(string value) => new Selector(value);
|
||||
}
|
||||
|
||||
private static unsafe IntPtr GetClass(string value)
|
||||
{
|
||||
int size = System.Text.Encoding.UTF8.GetMaxByteCount(value.Length);
|
||||
byte* data = stackalloc byte[size];
|
||||
|
||||
fixed (char* pValue = value)
|
||||
{
|
||||
System.Text.Encoding.UTF8.GetBytes(pValue, value.Length, data, size);
|
||||
}
|
||||
|
||||
return objc_getClass(data);
|
||||
}
|
||||
|
||||
private struct NSPoint
|
||||
{
|
||||
public double X;
|
||||
public double Y;
|
||||
|
||||
public NSPoint(double x, double y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
}
|
||||
|
||||
private struct NSRect
|
||||
{
|
||||
public NSPoint Pos;
|
||||
public NSPoint Size;
|
||||
|
||||
public NSRect(double x, double y, double width, double height)
|
||||
{
|
||||
Pos = new NSPoint(x, y);
|
||||
Size = new NSPoint(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
public static IntPtr GetMetalLayer(out IntPtr nsView, out UpdateBoundsCallbackDelegate updateBounds)
|
||||
{
|
||||
// Create a new CAMetalLayer.
|
||||
IntPtr layerClass = GetClass("CAMetalLayer");
|
||||
IntPtr metalLayer = IntPtr_objc_msgSend(layerClass, "alloc");
|
||||
objc_msgSend(metalLayer, "init");
|
||||
|
||||
// Create a child NSView to render into.
|
||||
IntPtr nsViewClass = GetClass("NSView");
|
||||
IntPtr child = IntPtr_objc_msgSend(nsViewClass, "alloc");
|
||||
objc_msgSend(child, "init", new NSRect(0, 0, 0, 0));
|
||||
|
||||
// Make its renderer our metal layer.
|
||||
objc_msgSend(child, "setWantsLayer:", (byte)1);
|
||||
objc_msgSend(child, "setLayer:", metalLayer);
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
|
||||
// Ensure the scale factor is up to date.
|
||||
updateBounds = (Rect rect) => {
|
||||
objc_msgSend(metalLayer, "setContentsScale:", Program.DesktopScaleFactor);
|
||||
};
|
||||
|
||||
nsView = child;
|
||||
return metalLayer;
|
||||
}
|
||||
|
||||
public static void DestroyMetalLayer(IntPtr nsView, IntPtr metalLayer)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static unsafe extern IntPtr sel_registerName(byte* data);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static unsafe extern IntPtr objc_getClass(byte* data);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, byte value);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, IntPtr value);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, NSRect point);
|
||||
|
||||
[DllImport(LibObjCImport)]
|
||||
private static extern void objc_msgSend(IntPtr receiver, Selector selector, double value);
|
||||
|
||||
[DllImport(LibObjCImport, EntryPoint = "objc_msgSend")]
|
||||
private static extern IntPtr IntPtr_objc_msgSend(IntPtr receiver, Selector selector);
|
||||
}
|
||||
}
|
@ -4,7 +4,6 @@ using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
using ConfigKey = Ryujinx.Common.Configuration.Hid.Key;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
|
||||
@ -13,30 +12,37 @@ namespace Ryujinx.Ava.Input
|
||||
internal class AvaloniaKeyboard : IKeyboard
|
||||
{
|
||||
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
|
||||
private readonly AvaloniaKeyboardDriver _driver;
|
||||
private readonly AvaloniaKeyboardDriver _driver;
|
||||
private StandardKeyboardInputConfig _configuration;
|
||||
|
||||
private readonly object _userMappingLock = new();
|
||||
|
||||
private StandardKeyboardInputConfig _configuration;
|
||||
|
||||
private bool HasConfiguration => _configuration != null;
|
||||
|
||||
public string Id { get; }
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsConnected => true;
|
||||
public bool IsConnected => true;
|
||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||
|
||||
public GamepadFeaturesFlag Features => GamepadFeaturesFlag.None;
|
||||
private class ButtonMappingEntry
|
||||
{
|
||||
public readonly Key From;
|
||||
public readonly GamepadButtonInputId To;
|
||||
|
||||
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
|
||||
{
|
||||
To = to;
|
||||
From = from;
|
||||
}
|
||||
}
|
||||
|
||||
public AvaloniaKeyboard(AvaloniaKeyboardDriver driver, string id, string name)
|
||||
{
|
||||
_driver = driver;
|
||||
Id = id;
|
||||
Name = name;
|
||||
_buttonsUserMapping = new List<ButtonMappingEntry>();
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
_driver = driver;
|
||||
Id = id;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public KeyboardStateSnapshot GetKeyboardStateSnapshot()
|
||||
{
|
||||
@ -46,11 +52,11 @@ namespace Ryujinx.Ava.Input
|
||||
public GamepadStateSnapshot GetMappedStateSnapshot()
|
||||
{
|
||||
KeyboardStateSnapshot rawState = GetKeyboardStateSnapshot();
|
||||
GamepadStateSnapshot result = default;
|
||||
GamepadStateSnapshot result = default;
|
||||
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
if (!HasConfiguration)
|
||||
if (_configuration == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@ -62,17 +68,17 @@ namespace Ryujinx.Ava.Input
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not touch state of the button already pressed
|
||||
// NOTE: Do not touch state of the button already pressed.
|
||||
if (!result.IsPressed(entry.To))
|
||||
{
|
||||
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
|
||||
}
|
||||
}
|
||||
|
||||
(short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick);
|
||||
(short leftStickX, short leftStickY) = GetStickValues(ref rawState, _configuration.LeftJoyconStick);
|
||||
(short rightStickX, short rightStickY) = GetStickValues(ref rawState, _configuration.RightJoyconStick);
|
||||
|
||||
result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY));
|
||||
result.SetStick(StickInputId.Left, ConvertRawStickValue(leftStickX), ConvertRawStickValue(leftStickY));
|
||||
result.SetStick(StickInputId.Right, ConvertRawStickValue(rightStickX), ConvertRawStickValue(rightStickY));
|
||||
}
|
||||
|
||||
@ -114,29 +120,29 @@ namespace Ryujinx.Ava.Input
|
||||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// Left joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
|
||||
// Left JoyCon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (Key)_configuration.LeftJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (Key)_configuration.LeftJoycon.DpadUp));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (Key)_configuration.LeftJoycon.DpadDown));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (Key)_configuration.LeftJoycon.DpadLeft));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (Key)_configuration.LeftJoycon.DpadRight));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (Key)_configuration.LeftJoycon.ButtonMinus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (Key)_configuration.LeftJoycon.ButtonL));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (Key)_configuration.LeftJoycon.ButtonZl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (Key)_configuration.LeftJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (Key)_configuration.LeftJoycon.ButtonSl));
|
||||
|
||||
// Finally right joycon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||
// Right JoyCon
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (Key)_configuration.RightJoyconStick.StickButton));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (Key)_configuration.RightJoycon.ButtonA));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (Key)_configuration.RightJoycon.ButtonB));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (Key)_configuration.RightJoycon.ButtonX));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (Key)_configuration.RightJoycon.ButtonY));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (Key)_configuration.RightJoycon.ButtonPlus));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (Key)_configuration.RightJoycon.ButtonR));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (Key)_configuration.RightJoycon.ButtonZr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (Key)_configuration.RightJoycon.ButtonSr));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (Key)_configuration.RightJoycon.ButtonSl));
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,16 +196,6 @@ namespace Ryujinx.Ava.Input
|
||||
_driver?.ResetKeys();
|
||||
}
|
||||
|
||||
private class ButtonMappingEntry
|
||||
{
|
||||
public readonly Key From;
|
||||
public readonly GamepadButtonInputId To;
|
||||
|
||||
public ButtonMappingEntry(GamepadButtonInputId to, Key from)
|
||||
{
|
||||
To = to;
|
||||
From = from;
|
||||
}
|
||||
}
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user