Skip to content

Commit

Permalink
* Improved BiQuadFilter performance
Browse files Browse the repository at this point in the history
* Improved implementation for `Vector8`
  • Loading branch information
MineCake147E committed Nov 22, 2020
1 parent ceed5a8 commit 30c3bf7
Show file tree
Hide file tree
Showing 10 changed files with 527 additions and 228 deletions.
48 changes: 48 additions & 0 deletions MonoAudio.Benchmarks/BiQuadBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;

using MonoAudio.Conversion.Resampling.Sample;
using MonoAudio.Filters;
using MonoAudio.Synthesis;

namespace MonoAudio.Benchmarks
{
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
public class BiQuadBenchmarks
{
private IReadableAudioSource<float, SampleFormat> source;
private BiQuadFilter filter;
private float[] buffer;
private const int SampleRate = 192000;

[Params(1, 2, 3, 4, 8)]
public int Channels { get; set; }

[GlobalSetup]
public void Setup()
{
source = new DummySource<float, SampleFormat>(new SampleFormat(Channels, SampleRate));
filter = new BiQuadFilter(source, BiQuadParameter.CreateLPFParameter(SampleRate, 48000, 1));
buffer = new float[2560];
}

[Benchmark]
public void BiQuadFilter()
{
var span = buffer.AsSpan();
_ = filter.Read(span);
}

[GlobalCleanup]
public void Cleanup()
{
filter?.Dispose();
source?.Dispose();
buffer = null;
}
}
}
10 changes: 7 additions & 3 deletions MonoAudio.Benchmarks/MonoAudio.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net472</TargetFrameworks>
<TargetFrameworks>net5.0;netstandard2.0;net472</TargetFrameworks>
</PropertyGroup>
<PropertyGroup>
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\MonoAudio\MonoAudio.csproj" />
</ItemGroup>
</Project>
</Project>
3 changes: 2 additions & 1 deletion MonoAudio.Benchmarks/ResamplerBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

namespace MonoAudio.Benchmarks
{
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[DisassemblyDiagnoser(maxDepth: 16)]
//[SimpleJob(RuntimeMoniker.Mono, baseline: true)]
public class ResamplerBenchmarks
{
Expand Down
17 changes: 12 additions & 5 deletions MonoAudio/Filters/BiQuadFilter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;

namespace MonoAudio.Filters
Expand Down Expand Up @@ -81,24 +82,30 @@ public BiQuadFilter(IReadableAudioSource<float, SampleFormat> source, BiQuadPara
/// <returns></returns>
public ReadResult Read(Span<float> buffer)
{
int channels = Format.Channels;
buffer = buffer.SliceAlign(channels);
ReadResult rr = Source.Read(buffer);
if (rr.HasNoData) return rr;
var len = rr.Length;
buffer = buffer.Slice(0, len);
unsafe
{
for (int i = 0; i < buffer.Length; i += Format.Channels)
//Factor localization greatly improved performance
Vector3 factorB = Parameter.B;
Vector2 factorA = Parameter.A;
for (int i = 0; i < buffer.Length; i += channels)
{
var span = buffer.Slice(i, internalStates.Length);
ref var pos = ref buffer[i];
//var span = buffer.Slice(i, internalStates.Length);
for (int ch = 0; ch < internalStates.Length; ch++)
{
//Reference: https://en.wikipedia.org/wiki/Digital_biquad_filter#Transposed_Direct_form_2
//Transformed for SIMD awareness.
ref var a = ref internalStates[ch]; //Persist reference in order to decrease number of times of range check.
ref float v = ref span[ch];
var feedForward = v * Parameter.B; //Multiply in one go
ref float v = ref Unsafe.Add(ref pos, ch);
var feedForward = v * factorB; //Multiply in one go
var sum1 = v = feedForward.X + a.X;
var feedBack = sum1 * Parameter.A; //Multiply in one go
var feedBack = sum1 * factorA; //Multiply in one go
var aY = a.Y; //Needed backup
a = new Vector2(feedForward.Y + feedBack.X + aY, feedForward.Z + feedBack.Y);
}
Expand Down
Loading

0 comments on commit 30c3bf7

Please sign in to comment.