Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix .net related problems with alphaSkia, fix player related problems #1329

Merged
merged 3 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions src.csharp/AlphaTab.Windows/NAudioSynthOutput.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class NAudioSynthOutput : WaveProvider32, ISynthOutput, IDisposable
{
private const int BufferSize = 4096;
private const int PreferredSampleRate = 44100;

private DirectSoundOut _context;
private CircularSampleBuffer _circularBuffer;
private int _bufferCount = 0;
Expand All @@ -27,7 +27,7 @@ public class NAudioSynthOutput : WaveProvider32, ISynthOutput, IDisposable
/// Initializes a new instance of the <see cref="NAudioSynthOutput"/> class.
/// </summary>
public NAudioSynthOutput()
: base(PreferredSampleRate, 2)
: base(PreferredSampleRate, (int)SynthConstants.AudioChannels)
{
_context = null!;
_circularBuffer = null!;
Expand All @@ -42,16 +42,21 @@ public void Activate()
/// <inheritdoc />
public void Open(double bufferTimeInMilliseconds)
{
var latency = 40;
_context = new DirectSoundOut(latency);
_context.Init(this);

// NAudio introduces another level of buffering and latency
// we've seen that this can cause our buffers to deplete
// as a mitigation we buffer a lot more
_bufferCount = (int)(
(bufferTimeInMilliseconds * PreferredSampleRate) /
1000 /
BufferSize
);
) * 4;
_circularBuffer = new CircularSampleBuffer(BufferSize * _bufferCount);
_context = new DirectSoundOut(100);
_context.Init(this);

((EventEmitter) Ready).Trigger();
((EventEmitter)Ready).Trigger();
}

/// <inheritdoc />
Expand Down Expand Up @@ -112,12 +117,12 @@ private void RequestBuffers()
// before we already get samples via addSamples, therefore we need to
// remember how many buffers have been requested, and consider them as available.
var bufferedSamples = _circularBuffer.Count + _requestedBufferCount * BufferSize;

if (bufferedSamples < halfSamples)
{
for (var i = 0; i < halfBufferCount; i++)
{
((EventEmitter) SampleRequest).Trigger();
((EventEmitter)SampleRequest).Trigger();
_requestedBufferCount++;
}
}
Expand All @@ -127,17 +132,19 @@ private void RequestBuffers()
public override int Read(float[] buffer, int offset, int count)
{
var read = new Float32Array(count);

var samplesFromBuffer = _circularBuffer.Read(read, 0, System.Math.Min(read.Length, _circularBuffer.Count));

var samplesFromBuffer = (int)_circularBuffer.Read(read, 0,
System.Math.Min(read.Length, _circularBuffer.Count));

Buffer.BlockCopy(read.Data, 0, buffer, offset * sizeof(float),
count * sizeof(float));
samplesFromBuffer * sizeof(float));

var samples = count / 2;
((EventEmitterOfT<double>) SamplesPlayed).Trigger(samples / SynthConstants.AudioChannels);
((EventEmitterOfT<double>)SamplesPlayed).Trigger(samplesFromBuffer /
SynthConstants.AudioChannels);

RequestBuffers();


return count;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System.Drawing;
using System.Drawing.Imaging;
using AlphaSkia;
using AlphaTab.Platform.Skia.AlphaSkiaBridge;

namespace AlphaTab.WinForms
{
internal static class SkiaUtil
internal static class AlphaSkiaUtil
{
public static Bitmap ToBitmap(AlphaSkiaImage image)
public static Bitmap ToBitmap(AlphaSkiaImage imageBridge)
{
var image = imageBridge.Image;
var bitmap = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppPArgb);
var bitmapData =
bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly,
Expand Down
4 changes: 2 additions & 2 deletions src.csharp/AlphaTab.Windows/WinForms/WinFormsUiFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using AlphaSkia;
using AlphaTab.Synth;
using AlphaTab.Platform;
using AlphaTab.Platform.CSharp;
using AlphaTab.Platform.Skia.AlphaSkiaBridge;
using AlphaTab.Rendering;
using AlphaTab.Rendering.Utils;

Expand Down Expand Up @@ -146,7 +146,7 @@ public override void BeginUpdateRenderResults(RenderFinishedEventArgs? r)
case AlphaSkiaImage skiaImage:
using (skiaImage)
{
source = SkiaUtil.ToBitmap(skiaImage);
source = AlphaSkiaUtil.ToBitmap(skiaImage);
}

break;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using AlphaSkia;
using AlphaTab.Platform.Skia.AlphaSkiaBridge;

namespace AlphaTab.Wpf
{
internal static class SkImageSource
internal static class AlphaSkiaImageSource
{
public static BitmapSource Create(AlphaSkiaImage image)
public static BitmapSource Create(AlphaSkiaImage imageBridge)
{
var image = imageBridge.Image;
var bitmap = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Pbgra32, null);
bitmap.Lock();
// copy
Expand Down
4 changes: 2 additions & 2 deletions src.csharp/AlphaTab.Windows/Wpf/WpfUiFacade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using AlphaSkia;
using AlphaTab.Synth;
using AlphaTab.Platform;
using AlphaTab.Platform.CSharp;
using AlphaTab.Platform.Skia.AlphaSkiaBridge;
using AlphaTab.Rendering;
using AlphaTab.Rendering.Utils;
using Point = System.Windows.Point;
Expand Down Expand Up @@ -158,7 +158,7 @@ public override void BeginUpdateRenderResults(RenderFinishedEventArgs? r)
{
using (skiaImage)
{
source = SkImageSource.Create(skiaImage);
source = AlphaSkiaImageSource.Create(skiaImage);
}
}
else if (body is System.Drawing.Bitmap image)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ internal enum AlphaSkiaTextBaseline
Bottom = AlphaSkia.AlphaSkiaTextBaseline.Bottom
}

internal class AlphaSkiaImage : IDisposable
/// <summary>
/// Bridge between alphaTab and <see cref="AlphaSkia.AlphaSkiaImage"/>
/// </summary>
public class AlphaSkiaImage : IDisposable
{
internal AlphaSkia.AlphaSkiaImage Image { get; }
public double Width => Image.Width;
public double Height => Image.Height;
/// <summary>
/// Gets the target <see cref="AlphaSkia.AlphaSkiaImage"/>.
/// </summary>
public AlphaSkia.AlphaSkiaImage Image { get; }
internal double Width => Image.Width;
internal double Height => Image.Height;

internal AlphaSkiaImage(AlphaSkia.AlphaSkiaImage image)
{
Expand All @@ -34,7 +40,7 @@ public void Dispose()
Image.Dispose();
}

public ArrayBuffer? ReadPixels()
internal ArrayBuffer? ReadPixels()
{
var data = Image.ReadPixels();
if (data == null)
Expand All @@ -45,7 +51,7 @@ public void Dispose()
return new ArrayBuffer(new ArraySegment<byte>(data, 0, data.Length));
}

public ArrayBuffer? ToPng()
internal ArrayBuffer? ToPng()
{
var data = Image.ToPng();
if (data == null)
Expand All @@ -56,20 +62,23 @@ public void Dispose()
return new ArrayBuffer(new ArraySegment<byte>(data, 0, data.Length));
}

public static AlphaSkiaImage? Decode(ArrayBuffer buffer)
internal static AlphaSkiaImage? Decode(ArrayBuffer buffer)
{
var underlying = AlphaSkia.AlphaSkiaImage.Decode(buffer.Raw.Array!);
return underlying == null ? null : new AlphaSkiaImage(underlying);
}

public static AlphaSkiaImage? FromPixels(double width, double height, ArrayBuffer pixels)
internal static AlphaSkiaImage? FromPixels(double width, double height, ArrayBuffer pixels)
{
var underlying =
AlphaSkia.AlphaSkiaImage.FromPixels((int)width, (int)height, pixels.Raw.Array!);
return underlying == null ? null : new AlphaSkiaImage(underlying);
}
}

/// <summary>
/// Bridge between alphaTab and <see cref="AlphaSkia.AlphaSkiaCanvas"/>
/// </summary>
internal class AlphaSkiaCanvas : IDisposable
{
private readonly AlphaSkia.AlphaSkiaCanvas _canvas = new();
Expand Down Expand Up @@ -177,10 +186,10 @@ public void Stroke()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FillText(string text, AlphaSkiaTypeface typeface, double fontSize, double x,
double y,
AlphaSkiaTextAlign textAlign, AlphaSkiaTextBaseline baseline)
AlphaSkiaTextAlign textAlign, AlphaSkiaTextBaseline baselineBridge)
{
_canvas.FillText(text, typeface.Typeface, (float)fontSize, (float)x, (float)y,
(AlphaSkia.AlphaSkiaTextAlign)textAlign, (AlphaSkia.AlphaSkiaTextBaseline)baseline);
(AlphaSkia.AlphaSkiaTextAlign)textAlign, (AlphaSkia.AlphaSkiaTextBaseline)baselineBridge);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down