Skip to content

Commit

Permalink
Use IsActive, update filters to handle different types, use audio upd…
Browse files Browse the repository at this point in the history
…ate callback
  • Loading branch information
Nytra committed Dec 31, 2024
1 parent 01dfee7 commit a851a5f
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 29 deletions.
21 changes: 13 additions & 8 deletions ProjectObsidian/Components/Audio/BandPassFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Elements.Assets;
using System.Net;
using ProtoFlux.Runtimes.Execution;
using System.Collections.Generic;

namespace Obsidian.Components.Audio
{
Expand All @@ -22,8 +23,8 @@ public class BandPassFilter : Component, IAudioSource, IWorldElement

private double lastTime;

private object lowFilter = null;
private object highFilter = null;
private Dictionary<Type, object> lowFilters = new();
private Dictionary<Type, object> highFilters = new();

public bool IsActive
{
Expand All @@ -37,6 +38,8 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
if (!IsActive)
{
buffer.Fill(default(S));
lowFilters.Clear();
highFilters.Clear();
return;
}

Expand All @@ -45,17 +48,19 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>

Source.Target.Read(tempBuffer);

if (lowFilter == null)
if (!lowFilters.TryGetValue(typeof(S), out object lowFilter))
{
lowFilter = new ButterworthFilter.FilterButterworth<S>();
lowFilters.Add(typeof(S), lowFilter);
}
if (highFilter == null)
if (!highFilters.TryGetValue(typeof(S), out object highFilter))
{
highFilter = new ButterworthFilter.FilterButterworth<S>();
highFilters.Add(typeof(S), highFilter);
}

((ButterworthFilter.FilterButterworth<S>)lowFilter).UpdateCoefficients(HighFrequency, (int)(tempBuffer.Length / (Engine.Current.AudioSystem.DSPTime - lastTime)), ButterworthFilter.FilterButterworth<S>.PassType.Lowpass, Resonance);
((ButterworthFilter.FilterButterworth<S>)highFilter).UpdateCoefficients(LowFrequency, (int)(tempBuffer.Length / (Engine.Current.AudioSystem.DSPTime - lastTime)), ButterworthFilter.FilterButterworth<S>.PassType.Highpass, Resonance);
((ButterworthFilter.FilterButterworth<S>)lowFilter).UpdateCoefficients(HighFrequency, Engine.AudioSystem.SampleRate, ButterworthFilter.FilterButterworth<S>.PassType.Lowpass, Resonance);
((ButterworthFilter.FilterButterworth<S>)highFilter).UpdateCoefficients(LowFrequency, Engine.AudioSystem.SampleRate, ButterworthFilter.FilterButterworth<S>.PassType.Highpass, Resonance);

for (int i = 0; i < tempBuffer.Length; i++)
{
Expand All @@ -80,8 +85,8 @@ protected override void OnChanges()
base.OnChanges();
if (Source.GetWasChangedAndClear())
{
lowFilter = null;
highFilter = null;
lowFilters.Clear();
highFilters.Clear();
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions ProjectObsidian/Components/Audio/ButterworthFilter.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using FrooxEngine;
using Elements.Assets;
using System.Collections.Generic;

namespace Obsidian.Components.Audio;

Expand All @@ -19,7 +20,7 @@ public class ButterworthFilter : Component, IAudioSource, IWorldElement

private double lastTime;

private object filter = null;
private Dictionary<Type, object> filters = new();

public bool IsActive
{
Expand All @@ -42,7 +43,7 @@ protected override void OnChanges()
base.OnChanges();
if (Source.GetWasChangedAndClear())
{
filter = null;
filters.Clear();
}
}

Expand All @@ -53,6 +54,7 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
if (!IsActive)
{
buffer.Fill(default(S));
filters.Clear();
return;
}

Expand All @@ -62,19 +64,17 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>

Source.Target.Read(span);

if (filter == null)
{
if (!filters.TryGetValue(typeof(S), out object filter)) {
filter = new FilterButterworth<S>();
filters.Add(typeof(S), filter);
}

((FilterButterworth<S>)filter).UpdateCoefficients(Frequency, (int)(span.Length / (Engine.Current.AudioSystem.DSPTime - lastTime)), LowPass ? FilterButterworth<S>.PassType.Lowpass : FilterButterworth<S>.PassType.Highpass, Resonance);
((FilterButterworth<S>)filter).UpdateCoefficients(Frequency, Engine.AudioSystem.SampleRate, LowPass ? FilterButterworth<S>.PassType.Lowpass : FilterButterworth<S>.PassType.Highpass, Resonance);

for (int i = 0; i < span.Length; i++)
{
((FilterButterworth<S>)filter).Update(ref span[i]);
}

lastTime = Engine.Current.AudioSystem.DSPTime;
}

public class FilterButterworth<S> where S: unmanaged, IAudioSample<S>
Expand Down Expand Up @@ -140,8 +140,8 @@ public void Update(ref S newInput)

for (int i = 0; i < final.ChannelCount; i++)
{
if (final[i] > 1) final = final.SetChannel(i, 1f);
if (final[i] < -1) final = final.SetChannel(i, -1f);
if (final[i] > 1f) final = final.SetChannel(i, 1f);
else if (final[i] < -1f) final = final.SetChannel(i, -1f);
}

this.inputHistory[1] = this.inputHistory[0];
Expand Down
8 changes: 7 additions & 1 deletion ProjectObsidian/ProtoFlux/Audio/AudioAdder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public class AudioAdderProxy : ProtoFluxEngineProxy, IAudioSource

public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
{
if (!IsActive)
{
buffer.Fill(default(S));
return;
}

Span<S> newBuffer = stackalloc S[buffer.Length];
newBuffer = buffer;
Span<S> newBuffer2 = stackalloc S[buffer.Length];
Expand All @@ -47,7 +53,7 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
for (int j = 0; j < newBuffer[i].ChannelCount; j++)
{
if (newBuffer[i][j] > 1f) newBuffer[i] = newBuffer[i].SetChannel(j, 1f);
if (newBuffer[i][j] < -1f) newBuffer[i] = newBuffer[i].SetChannel(j, -1f);
else if (newBuffer[i][j] < -1f) newBuffer[i] = newBuffer[i].SetChannel(j, -1f);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions ProjectObsidian/ProtoFlux/Audio/AudioMultiply.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ public class AudioMultiplyProxy : ProtoFluxEngineProxy, IAudioSource

public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
{
if (!IsActive)
{
buffer.Fill(default(S));
return;
}

Span<S> newBuffer = stackalloc S[buffer.Length];
newBuffer = buffer;
if (AudioInput != null)
Expand Down
8 changes: 7 additions & 1 deletion ProjectObsidian/ProtoFlux/Audio/AudioSubtractor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ public class AudioSubtractorProxy : ProtoFluxEngineProxy, IAudioSource

public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
{
if (!IsActive)
{
buffer.Fill(default(S));
return;
}

Span<S> newBuffer = stackalloc S[buffer.Length];
newBuffer = buffer;
Span<S> newBuffer2 = stackalloc S[buffer.Length];
Expand All @@ -47,7 +53,7 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
for (int j = 0; j < newBuffer[i].ChannelCount; j++)
{
if (newBuffer[i][j] > 1f) newBuffer[i] = newBuffer[i].SetChannel(j, 1f);
if (newBuffer[i][j] < -1f) newBuffer[i] = newBuffer[i].SetChannel(j, -1f);
else if (newBuffer[i][j] < -1f) newBuffer[i] = newBuffer[i].SetChannel(j, -1f);
}
}
}
Expand Down
39 changes: 29 additions & 10 deletions ProjectObsidian/ProtoFlux/Audio/SineGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using Elements.Assets;
using Elements.Core;
using System.Runtime.InteropServices;
using System.Linq.Expressions;
using FrooxEngine.FrooxEngine.ProtoFlux.CoreNodes;

namespace ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Audio
{
Expand All @@ -19,7 +17,7 @@ public class SineGeneratorProxy : ProtoFluxEngineProxy, IAudioSource

public float Phase;

public float time;
public double time;

private float[] tempBuffer;

Expand All @@ -29,22 +27,43 @@ public class SineGeneratorProxy : ProtoFluxEngineProxy, IAudioSource

public int ChannelCount => 1;

// TODO: Make this not advance time on each read
// If two things are reading this generator, it advances twice as fast
private bool updateTime;

public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
{
if (!IsActive)
{
buffer.Fill(default(S));
return;
}

tempBuffer = tempBuffer.EnsureSize(buffer.Length);
time %= MathX.PI * 2f;
float advance = 1f / (float)base.Engine.AudioSystem.SampleRate * (MathX.PI * 2f) * (float)Frequency;
var temptime = time;
temptime %= MathX.PI * 2f;
var clampedAmplitude = MathX.Clamp01(Amplitude);
float advance = (1f / (float)base.Engine.AudioSystem.SampleRate) * (MathX.PI * 2f) * (float)Frequency;
for (int i = 0; i < buffer.Length; i++)
{
tempBuffer[i] = MathX.Sin(time + Phase) * MathX.Clamp01(Amplitude);
time += advance;
tempBuffer[i] = (float)MathX.Sin(temptime + Phase) * clampedAmplitude;
temptime += advance;
}
if (updateTime)
{
time = temptime;
updateTime = false;
}
double position = 0.0;
MonoSample lastSample = default(MonoSample);
MemoryMarshal.Cast<float, MonoSample>(MemoryExtensions.AsSpan(tempBuffer)).CopySamples(buffer, ref position, ref lastSample);
}

protected override void OnStart()
{
Engine.AudioSystem.AudioUpdate += () =>
{
updateTime = true;
};
}
}
[NodeCategory("Obsidian/Audio")]
public class SineGenerator : ProxyVoidNode<FrooxEngineContext, SineGeneratorProxy>, IExecutionChangeListener<FrooxEngineContext>
Expand Down Expand Up @@ -145,9 +164,9 @@ public void Changed(FrooxEngineContext context)
{
return;
}
proxy.Frequency = Frequency.Evaluate(context, 440f);
proxy.Amplitude = Amplitude.Evaluate(context, 1f);
proxy.Phase = Phase.Evaluate(context, 0f);
proxy.Frequency = Frequency.Evaluate(context, 440f);
}

protected override void ComputeOutputs(FrooxEngineContext context)
Expand Down

0 comments on commit a851a5f

Please sign in to comment.