Skip to content

Commit

Permalink
Merge pull request #35 from stevehjohn/bass
Browse files Browse the repository at this point in the history
Use BASS Audio Library
  • Loading branch information
stevehjohn authored Aug 14, 2024
2 parents 44b0517 + 8e49fdc commit 8648a37
Show file tree
Hide file tree
Showing 20 changed files with 179 additions and 36 deletions.
20 changes: 19 additions & 1 deletion src/Zen.Desktop.Host/Infrastructure/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Zen.System;
using Zen.System.FileHandling;
using Zen.System.FileHandling.Interfaces;
using Zen.System.Modules.Audio.Engines;
using Keys = Microsoft.Xna.Framework.Input.Keys;
using Model = Zen.System.Infrastructure.Model;

Expand Down Expand Up @@ -112,6 +113,12 @@ private void SetMotherboard(Model model)

_motherboard.Sound = AppSettings.Instance.Sound;

_motherboard.AudioEngine = AppSettings.Instance.AudioEngine switch
{
AudioEngine.Bass => new BassAudioEngine(),
_ => new PortAudioEngine()
};

_motherboard.Fast = AppSettings.Instance.Speed == Speed.Fast;
_motherboard.Slow = AppSettings.Instance.Speed == Speed.Slow;

Expand Down Expand Up @@ -318,8 +325,19 @@ private void MenuFinished(MenuResult result, object arguments)

break;

case MenuResult.SoundOn:
case MenuResult.SoundPortAudio:
_motherboard.Sound = true;
_motherboard.AudioEngine = new PortAudioEngine();
AppSettings.Instance.AudioEngine = AudioEngine.PortAudio;
AppSettings.Instance.Sound = true;
AppSettings.Instance.Save();

break;

case MenuResult.SoundBass:
_motherboard.Sound = true;
_motherboard.AudioEngine = new BassAudioEngine();
AppSettings.Instance.AudioEngine = AudioEngine.Bass;
AppSettings.Instance.Sound = true;
AppSettings.Instance.Save();

Expand Down
3 changes: 2 additions & 1 deletion src/Zen.Desktop.Host/Infrastructure/Menu/MenuResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public enum MenuResult
SaveState,
LoadState,
ChangeScale,
SoundOn,
SoundPortAudio,
SoundBass,
SoundOff,
VisualisationOff,
VisualisationWaveform,
Expand Down
16 changes: 12 additions & 4 deletions src/Zen.Desktop.Host/Infrastructure/Menu/SoundMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ public override List<Label> GetMenu()
var items = new List<Label>
{
new(0, true, "Zen - Sound", Color.White, 0, 0, null),
new(1, false, $"[1] {(AppSettings.Instance.Sound ? ">" : " ")} On {(AppSettings.Instance.Sound ? "<" : " ")}", Color.Yellow, 1, 3, Keys.D1, Color.LightGreen),
new(2, false, $"[2] {(AppSettings.Instance.Sound ? " " : ">")} Off {(AppSettings.Instance.Sound ? " " : "<")}", Color.Yellow, 1, 5, Keys.D2, Color.LightGreen),
new(1, false, $"[1] {(AppSettings.Instance.Sound ? " " : ">")} Off {(AppSettings.Instance.Sound ? " " : "<")}", Color.Yellow, 1, 3, Keys.D1, Color.LightGreen),
new(2, false, $"[2] {(AppSettings.Instance.Sound && AppSettings.Instance.AudioEngine == AudioEngine.PortAudio ? ">" : " ")} On - PortAudio {(AppSettings.Instance.AudioEngine == AudioEngine.PortAudio ? "<" : " ")}", Color.Yellow, 1, 5, Keys.D2, Color.LightGreen),
new(3, false, $"[3] {(AppSettings.Instance.Sound && AppSettings.Instance.AudioEngine == AudioEngine.Bass ? ">" : " ")} On - Bass {(AppSettings.Instance.AudioEngine == AudioEngine.Bass ? "<" : " ")}", Color.Yellow, 1, 7, Keys.D3, Color.LightGreen),
new(96, true, "It will Depend on your", Color.Wheat, 0, 11, null),
new(97, true, "hardware and OS", Color.Wheat, 0, 13, null),
new(98, true, "whether Port Audio or Bass", Color.Wheat, 0, 15, null),
new(98, true, "produce better audio", Color.Wheat, 0, 17, null),
new(99, true, "[ESC] Close Menu", Color.FromNonPremultiplied(255, 64, 64, 255), 0, 21, Keys.Escape, Color.LightGreen)
};

Expand All @@ -25,10 +30,13 @@ public override (MenuResult Result, MenuBase NewMenu, object Arguments) ItemSele
switch (id)
{
case 1:
return (MenuResult.SoundOn, null, null);
return (MenuResult.SoundOff, null, null);

case 2:
return (MenuResult.SoundOff, null, null);
return (MenuResult.SoundPortAudio, null, null);

case 3:
return (MenuResult.SoundBass, null, null);

default:
return (MenuResult.NewMenu, new MainMenu(), null);
Expand Down
6 changes: 3 additions & 3 deletions src/Zen.Desktop.Host/Infrastructure/Menu/SpeedMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ public override List<Label> GetMenu()
new(3, false, $"[3] {(AppSettings.Instance.Speed == Speed.Half ? ">" : " ")} Half {(AppSettings.Instance.Speed == Speed.Half ? "<" : " ")}", Color.Yellow, 1, 7, Keys.D3, Color.LightGreen),
new(4, false, $"[4] {(AppSettings.Instance.Speed == Speed.Normal ? ">" : " ")} Normal {(AppSettings.Instance.Speed == Speed.Normal ? "<" : " ")}", Color.Yellow, 1, 9, Keys.D4, Color.LightGreen),
new(5, false, $"[5] {(AppSettings.Instance.Speed == Speed.Fast ? ">" : " ")} As Fast As Possible {(AppSettings.Instance.Speed == Speed.Fast ? "<" : " ")}", Color.Yellow, 1, 11, Keys.D5, Color.LightGreen),
new(96, true, "This setting is not saved", Color.Orange, 0, 15, null),
new(97, true, "Zen always starts", Color.Orange, 0, 17, null),
new(98, true, "at Normal speed", Color.Orange, 0, 18, null),
new(96, true, "This setting is not saved", Color.Wheat, 0, 15, null),
new(97, true, "Zen always starts", Color.Wheat, 0, 17, null),
new(98, true, "at Normal speed", Color.Wheat, 0, 18, null),
new(99, true, "[ESC] Close Menu", Color.FromNonPremultiplied(255, 64, 64, 255), 0, 21, Keys.Escape, Color.LightGreen)
};

Expand Down
2 changes: 2 additions & 0 deletions src/Zen.Desktop.Host/Infrastructure/Settings/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public class AppSettings
public int ScaleFactor { get; set; }

public bool Sound { get; set; }

public AudioEngine AudioEngine { get; set; }

public Speed Speed { get; set; }

Expand Down
7 changes: 7 additions & 0 deletions src/Zen.Desktop.Host/Infrastructure/Settings/AudioEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Zen.Desktop.Host.Infrastructure.Settings;

public enum AudioEngine
{
PortAudio,
Bass
}
76 changes: 76 additions & 0 deletions src/Zen.System/Modules/Audio/Engines/BassAudioEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System.Runtime.InteropServices;
using Un4seen.Bass;
using Zen.Common.Infrastructure;

namespace Zen.System.Modules.Audio.Engines;

public class BassAudioEngine : IZenAudioEngine
{
private static readonly AutoResetEvent ResetEvent = new(true);

private readonly int _sampleHandle;

private int _channel = -1;

private bool _first = true;

public BassAudioEngine()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && ! File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libbass.so")))
{
switch (RuntimeInformation.ProcessArchitecture)
{
case Architecture.X64:
File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libbass.so.x64"), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libbass.so"));

break;

default:
File.Copy(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libbass.so.arm64"), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libbass.so"));

break;
}
}

try
{
Bass.BASS_Init(-1, Constants.SampleRate, BASSInit.BASS_DEVICE_MONO, 0);

_sampleHandle = Bass.BASS_SampleCreate(Constants.DefaultBufferSize * 4, Constants.SampleRate, 1, 1, BASSFlag.BASS_SAMPLE_FLOAT);
}
catch (Exception exception)
{
Logger.LogException(nameof(BassAudioEngine), exception);
}
}

public void Send(float[] data)
{
if (! _first)
{
ResetEvent.WaitOne();
}
else
{
_first = false;
}

Bass.BASS_SampleSetData(_sampleHandle, data);

_channel = Bass.BASS_SampleGetChannel(_sampleHandle, BASSFlag.BASS_SAMCHAN_STREAM);

Bass.BASS_ChannelSetSync(_channel, BASSSync.BASS_SYNC_END | BASSSync.BASS_SYNC_ONETIME, Constants.DefaultBufferSize * 4, PlayComplete, IntPtr.Zero);

Bass.BASS_ChannelPlay(_channel, false);
}

private static void PlayComplete(int handle, int channel, int data, IntPtr user)
{
ResetEvent.Set();
}

public void Dispose()
{
Bass.BASS_Free();
}
}
6 changes: 6 additions & 0 deletions src/Zen.System/Modules/Audio/Engines/IZenAudioEngine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Zen.System.Modules.Audio.Engines;

public interface IZenAudioEngine : IDisposable
{
void Send(float[] data);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using Bufdio;
using Bufdio.Engines;
using Zen.Common.Infrastructure;

namespace Zen.System.Modules.Audio;
namespace Zen.System.Modules.Audio.Engines;

public class AudioEngine : IDisposable
public class PortAudioEngine : IZenAudioEngine
{
private readonly IAudioEngine? _engine;

public AudioEngine()
public PortAudioEngine()
{
try
{
Expand All @@ -21,19 +21,19 @@ public AudioEngine()
}
else
{
BufdioLib.InitializePortAudio(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Libraries", "libportaudio.dylib"));
BufdioLib.InitializePortAudio(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libportaudio.dylib"));
}
}
else
{
BufdioLib.InitializePortAudio(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Libraries", "libportaudio"));
BufdioLib.InitializePortAudio(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libportaudio"));
}

_engine = new PortAudioEngine(new AudioEngineOptions(1, Constants.SampleRate));
_engine = new Bufdio.Engines.PortAudioEngine(new AudioEngineOptions(1, Constants.SampleRate));
}
catch (Exception exception)
{
Logger.LogException(nameof(AudioEngine), exception);
Logger.LogException(nameof(PortAudioEngine), exception);
}
}

Expand Down
20 changes: 13 additions & 7 deletions src/Zen.System/Modules/AyAudio.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Zen.Common.Infrastructure;
using Zen.System.Modules.Audio;
using Zen.System.Modules.Audio.Engines;

namespace Zen.System.Modules;

Expand All @@ -15,13 +16,7 @@ public class AyAudio : IDisposable

private readonly MixerDac _mixerDac = new();

private Task? _audioThread;

private byte _registerNumber;

private float[] _buffer;

private readonly AudioEngine _engine = new();
private IZenAudioEngine _engine = new PortAudioEngine();

private readonly CancellationTokenSource _cancellationTokenSource;

Expand All @@ -33,6 +28,12 @@ public class AyAudio : IDisposable

private readonly Queue<(int Frame, Command Command, byte Value)>[] _commandQueues;

private Task? _audioThread;

private byte _registerNumber;

private float[] _buffer;

private int _readQueue;

private float _bitValue;
Expand All @@ -53,6 +54,11 @@ public int BufferSize
}
}

public IZenAudioEngine AudioEngine
{
set => _engine = value;
}

public bool Silent { get; set; }

public Action<float[]>? AySignalHook { get; set; }
Expand Down
8 changes: 4 additions & 4 deletions src/Zen.System/Modules/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,12 @@ private void TimerWorker()
_resetEvent.WaitOne();
}

_ayAudio.FrameReady(_resetEvent);

_resetEvent.Reset();

Counters.Instance.IncrementCounter(Counter.SpectrumFrames);
}

_ayAudio.FrameReady(_resetEvent);

_resetEvent.Reset();
}
catch (Exception exception)
{
Expand Down
6 changes: 6 additions & 0 deletions src/Zen.System/Motherboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Zen.System.Infrastructure;
using Zen.System.Interfaces;
using Zen.System.Modules;
using Zen.System.Modules.Audio.Engines;
using Zen.System.ProcessorHooks;
using Zen.Z80.Interfaces;
using Zen.Z80.Processor;
Expand Down Expand Up @@ -79,6 +80,11 @@ public bool Sound
}
}

public IZenAudioEngine AudioEngine
{
set => _ayAudio.AudioEngine = value;
}

public Motherboard(Model model)
{
_model = model;
Expand Down
29 changes: 21 additions & 8 deletions src/Zen.System/Zen.System.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,35 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Bufdio" Version="0.1.0" />
<ProjectReference Include="..\Zen.Z80\Zen.Z80.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Zen.Z80\Zen.Z80.csproj" />
<PackageReference Include="Bufdio" Version="0.1.0" />
<PackageReference Include="radio42.Bass.Net.core" Version="2.4.17.5" />
</ItemGroup>

<ItemGroup>
<None Update="Libraries\libportaudio.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<None Update="libbass.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="libbass.so.arm64">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="bass.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="libbass.so.x64">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="libportaudio.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Libraries\libportaudio.dylib">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<None Update="libportaudio.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Libraries\libportaudio.so">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<None Update="libportaudio.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

Expand Down
Binary file added src/Zen.System/bass.dll
Binary file not shown.
Binary file added src/Zen.System/libbass.dylib
Binary file not shown.
Binary file added src/Zen.System/libbass.so.arm64
Binary file not shown.
Binary file added src/Zen.System/libbass.so.x64
Binary file not shown.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 8648a37

Please sign in to comment.