Skip to content

Commit

Permalink
Haydn: Part 1 (#2007)
Browse files Browse the repository at this point in the history
* Haydn: Part 1

Based on my reverse of audio 11.0.0.

As always, core implementation under LGPLv3 for the same reasons as for Amadeus.

This place the bases of a more flexible audio system while making audout & audin accurate.

This have the following improvements:
- Complete reimplementation of audout and audin.
- Audin currently only have a dummy backend.
- Dramatically reduce CPU usage by up to 50% in common cases (SoundIO and OpenAL).
- Audio Renderer now can output to 5.1 devices when supported.
- Audio Renderer init its backend on demand instead of keeping two up all the time.
- All backends implementation are now in their own project.
- Ryujinx.Audio.Renderer was renamed Ryujinx.Audio and was refactored because of this.

As a note, games having issues with OpenAL haven't improved and will not
because of OpenAL design (stopping when buffers finish playing causing
possible audio "pops" when buffers are very small).

* Update for latest hexkyz's edits on Switchbrew

* audren: Rollback channel configuration changes

* Address gdkchan's comments

* Fix typo in OpenAL backend driver

* Address last comments

* Fix a nit

* Address gdkchan's comments
  • Loading branch information
Mary authored Feb 26, 2021
1 parent 1c49089 commit f556c80
Show file tree
Hide file tree
Showing 249 changed files with 5,602 additions and 2,700 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ If you'd like to donate, please take a look at our [Patreon](https://www.patreon
## License

This software is licensed under the terms of the MIT license.
The Ryujinx.Audio.Renderer project is licensed under the terms of the LGPLv3 license.
The Ryujinx.Audio project is licensed under the terms of the LGPLv3 license.
This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3.
See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](Ryujinx/THIRDPARTY.md) for more details.

9 changes: 9 additions & 0 deletions Ryujinx.Audio.Backends.OpenAL/OpenALAudioBuffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Ryujinx.Audio.Backends.OpenAL
{
class OpenALAudioBuffer
{
public int BufferId;
public ulong DriverIdentifier;
public ulong SampleCount;
}
}
170 changes: 170 additions & 0 deletions Ryujinx.Audio.Backends.OpenAL/OpenALHardwareDeviceDriver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
using OpenTK.Audio;
using Ryujinx.Audio.Common;
using Ryujinx.Audio.Integration;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Threading;
using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;

namespace Ryujinx.Audio.Backends.OpenAL
{
public class OpenALHardwareDeviceDriver : IHardwareDeviceDriver
{
private object _lock = new object();

private AudioContext _context;
private ManualResetEvent _updateRequiredEvent;
private List<OpenALHardwareDeviceSession> _sessions;
private bool _stillRunning;
private Thread _updaterThread;

public OpenALHardwareDeviceDriver()
{
_context = new AudioContext();
_updateRequiredEvent = new ManualResetEvent(false);
_sessions = new List<OpenALHardwareDeviceSession>();

_stillRunning = true;
_updaterThread = new Thread(Update)
{
Name = "HardwareDeviceDriver.OpenAL"
};

_updaterThread.Start();
}

public static bool IsSupported
{
get
{
try
{
return AudioContext.AvailableDevices.Count > 0;
}
catch
{
return false;
}
}
}

public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount)
{
if (channelCount == 0)
{
channelCount = 2;
}

if (sampleRate == 0)
{
sampleRate = Constants.TargetSampleRate;
}

if (direction != Direction.Output)
{
throw new ArgumentException($"{direction}");
}
else if (!SupportsChannelCount(channelCount))
{
throw new ArgumentException($"{channelCount}");
}

lock (_lock)
{
OpenALHardwareDeviceSession session = new OpenALHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount);

_sessions.Add(session);

return session;
}
}

internal void Unregister(OpenALHardwareDeviceSession session)
{
lock (_lock)
{
_sessions.Remove(session);
}
}

public ManualResetEvent GetUpdateRequiredEvent()
{
return _updateRequiredEvent;
}

private void Update()
{
while (_stillRunning)
{
bool updateRequired = false;

lock (_lock)
{
foreach (OpenALHardwareDeviceSession session in _sessions)
{
if (session.Update())
{
updateRequired = true;
}
}
}

if (updateRequired)
{
_updateRequiredEvent.Set();
}

// If it's not slept it will waste cycles.
Thread.Sleep(10);
}
}

public void Dispose()
{
Dispose(true);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (_lock)
{
_stillRunning = false;
_updaterThread.Join();

// Loop against all sessions to dispose them (they will unregister themself)
while (_sessions.Count > 0)
{
OpenALHardwareDeviceSession session = _sessions[0];

session.Dispose();
}
}

_context.Dispose();
}
}

public bool SupportsSampleRate(uint sampleRate)
{
return true;
}

public bool SupportsSampleFormat(SampleFormat sampleFormat)
{
return true;
}

public bool SupportsChannelCount(uint channelCount)
{
return channelCount == 1 || channelCount == 2 || channelCount == 6;
}

public bool SupportsDirection(Direction direction)
{
return direction == Direction.Output;
}
}
}
Loading

0 comments on commit f556c80

Please sign in to comment.