Skip to content

Commit

Permalink
Splits up code and uses high level node building API to implement nod…
Browse files Browse the repository at this point in the history
…e factory
  • Loading branch information
azeno committed Oct 26, 2023
1 parent 578c151 commit 97810ff
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 243 deletions.
26 changes: 20 additions & 6 deletions src/Initialization.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#nullable enable
using System.Collections.Immutable;
using VL.Core;
using VL.Core.CompilerServices;
using VL.Lib.Basics.Resources;
Expand All @@ -11,7 +12,6 @@ namespace VL.Audio
public class Initialization : AssemblyInitializer<Initialization>
{
private IResourceProvider<GlobalEngine>? _engineProvider;
private NodeFactory? _nodeFactory;

public override void Configure(AppHost appHost)
{
Expand All @@ -22,12 +22,26 @@ public override void Configure(AppHost appHost)
}
appHost.Services.RegisterService(_engineProvider);

// Register our node factory
if (_nodeFactory is null)
// Register our nodes
appHost.RegisterNodeFactory("VL.Audio-Factory", nodeFactory =>
{
_nodeFactory = new NodeFactory(_engineProvider);
}
appHost.NodeFactoryRegistry.RegisterNodeFactory(_nodeFactory);
var nodes = ImmutableArray.CreateBuilder<IVLNodeDescription>();
//sources
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(ADSRSignal), "ADSR", "Source", "Generates an ADSR envelope in 0..1 range", "", "envelope"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(OscSignal), "Oscillator", "Source", "Creates an audio wave", "", "synthesis sine triangle square sawtooth wave"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(NoiseSignal), "Noise", "Source", "Creates different types of noise", "", "pink white"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(ValueToAudioSignal), "V2A", "Source", "Converts a value into a static audio signal", "", ""));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(GranulatorSignal), "Granulator2 (Internal)", "Source", "Reads grains from an audio file", "", "granular synthesis"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(IFFTSignal), "IFFT", "Source", "Creates an audio signal from spectrum data", "", "additive synthesis inverse"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(ValueSequenceSignal), "ValueSequence2 (Internal)", "Source", "Generates a sequence of values which are played back as an audio signal", "", "sequencer clip loop"));

//filter
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(AnalogModelingFilterSignal), "Filter", "Filter", "Analog modeling filter", "", "moog"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(OnePoleLowPassSignal), "IIR", "Filter", "Simple one pole lowpass filer, mainly for value smoothing", "", "onepole smoothing damper"));
nodes.Add(new NodeDescription(nodeFactory, _engineProvider, typeof(WaveShaperSignal), "WaveShaper", "Filter", "Wave shaper to distort the audio signal", "", "distort saturate"));

return new(nodes.ToImmutable());
});

base.Configure(appHost);
}
Expand Down
81 changes: 81 additions & 0 deletions src/Nodes/AudioSignalNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using VL.Core;
using System.Reactive.Linq;
using VL.Lib.Basics.Resources;

namespace VL.Audio
{
sealed class AudioSignalNode : FactoryBasedVLNode, IVLNode
{
AudioSignal FSignalInstance;
IResourceHandle<GlobalEngine> FEngineHandle;

class MyPin : IVLPin
{
public object Value { get; set; }
public Type Type { get; set; }
public string Name { get; set; }
}

readonly NodeDescription description;

public AudioSignalNode(NodeDescription description, IResourceHandle<GlobalEngine> engineHandle, NodeContext nodeContext) : base(nodeContext)
{
this.description = description;
FSignalInstance = (AudioSignal)Activator.CreateInstance(description.Signal);
FEngineHandle = engineHandle;

foreach (var input in description.Inputs)
FInputsMap.Add(input.Name, new MyPin() { Name = input.Name, Type = input.Type, Value = input.DefaultValue });

Inputs = FInputsMap.Values.ToArray();

foreach (var output in description.Outputs)
FOutputsMap.Add(output.Name, new MyPin() { Name = output.Name, Type = output.Type, Value = output.DefaultValue });

Outputs = FOutputsMap.Values.ToArray();
}

public IVLNodeDescription NodeDescription => description;

Dictionary<string, IVLPin> FInputsMap = new Dictionary<string, IVLPin>();
Dictionary<string, IVLPin> FOutputsMap = new Dictionary<string, IVLPin>();

public IVLPin[] Inputs { get; }

public IVLPin[] Outputs { get; }

public void Update()
{
var apply = true;
//if (FInputsMap.TryGetValue("Apply", out var pin))
// apply = (bool)pin.Value;

if (apply)
{
foreach (var param in FSignalInstance.InParams)
if (param.GetValueType() == typeof(double))
param.SetValue((double)(float)FInputsMap[param.Name].Value);
else
param.SetValue(FInputsMap[param.Name].Value);
Outputs[0].Value = FSignalInstance;
}
else
Outputs[0].Value = FInputsMap["Input"].Value;

foreach (var param in FSignalInstance.OutParams)
if (param.GetValueType() == typeof(double))
FOutputsMap[param.Name].Value = (float)(double)param.GetValue();
else
FOutputsMap[param.Name].Value = param.GetValue();
}

public void Dispose()
{
FSignalInstance.Dispose();
FEngineHandle.Dispose();
}
}
}
100 changes: 100 additions & 0 deletions src/Nodes/NodeDescription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using VL.Core;
using System.Reactive.Linq;
using VL.Lib.Basics.Resources;

namespace VL.Audio
{
sealed class NodeDescription : IVLNodeDescription, IInfo, ITaggedInfo
{
readonly IResourceProvider<GlobalEngine> _engineProvider;
readonly ImmutableArray<string> _tags;
readonly List<PinDescription> _inputs = new List<PinDescription>();
readonly List<PinDescription> _outputs = new List<PinDescription>();

public NodeDescription(IVLNodeDescriptionFactory factory, IResourceProvider<GlobalEngine> engineProvider, Type signalType, string name, string category, string summary, string remarks, string tags)
{
Factory = factory;
_engineProvider = engineProvider;
Signal = signalType;
Name = name;
Category = "Audio." + category;
Summary = summary;
Remarks = remarks;
_tags = tags.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToImmutableArray();

using (var signal = (AudioSignal)Activator.CreateInstance(signalType))
{
foreach (var input in signal.InParams)
_inputs.Add(new PinDescription(input.Name, DoubleToSingleT(input.GetValueType()), DoubleToSingleV(input.GetDefaultValue()), ""));

//if (category == "Filter")
// inputs.Add(new PinDescription("Apply", typeof(bool), true, ""));

_outputs.Add(new PinDescription("Output", typeof(AudioSignal), null, ""));

foreach (var output in signal.OutParams)
_outputs.Add(new PinDescription(output.Name, DoubleToSingleT(output.GetValueType()), DoubleToSingleV(output.GetDefaultValue()), ""));
}
}

Type DoubleToSingleT(Type type)
{
if (type == typeof(double))
return typeof(float);
else
return type;
}

object DoubleToSingleV(object value)
{
if (value != null && value.GetType() == typeof(double))
return (float)(double)value;
else
return value;
}

public IVLNodeDescriptionFactory Factory { get; }

public Type Signal { get; private set; }

public string Name { get; private set; }

public string Category { get; private set; }

public bool Fragmented => false;

public IReadOnlyList<IVLPinDescription> Inputs => _inputs;

public IReadOnlyList<IVLPinDescription> Outputs => _outputs;

public IEnumerable<Core.Diagnostics.Message> Messages
{
get
{
yield break;
}
}

public string Summary { get; private set; }

public string Remarks { get; private set; }

public IObservable<object> Invalidated => Observable.Never<object>();

ImmutableArray<string> ITaggedInfo.Tags => _tags;

public IVLNode CreateInstance(NodeContext context)
{
var engineHandle = _engineProvider.GetHandle();
return new AudioSignalNode(this, engineHandle, context);
}

public bool OpenEditor()
{
return false;
}
}
}
Loading

0 comments on commit 97810ff

Please sign in to comment.