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

Add ADSR Envelope node and adjust frequency modulator's modulation range #68

Merged
merged 1 commit into from
Dec 30, 2024
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
6 changes: 3 additions & 3 deletions ProjectObsidian/Components/Audio/FrequencyModulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Obsidian.Components.Audio
[Category(new string[] { "Obsidian/Audio" })]
public class FrequencyModulator : Component, IAudioSource, IWorldElement
{
[Range(0f, 1000f, "0.00")]
[Range(0f, 5f, "0.00")]
public readonly Sync<float> ModulationIndex;

public readonly SyncRef<IAudioSource> CarrierSource;
Expand Down Expand Up @@ -35,7 +35,7 @@ public int ChannelCount
protected override void OnAwake()
{
base.OnAwake();
ModulationIndex.Value = 100f; // Default modulation index
ModulationIndex.Value = 1f; // Default modulation index
}

public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
Expand Down Expand Up @@ -74,7 +74,7 @@ public void Read<S>(Span<S> buffer) where S : unmanaged, IAudioSample<S>
float modulatedValue = (float)(carrierValue * Math.Sin(2 * Math.PI * modulationIndex * modulatorValue));

// Write modulated value to the buffer
buffer[i] = buffer[i].Bias(buffer[i].AbsoluteAmplitude - modulatedValue);
buffer[i] = buffer[i].Bias(buffer[i].AbsoluteAmplitude - modulatedValue);
}
}
}
Expand Down
75 changes: 75 additions & 0 deletions ProjectObsidian/ProtoFlux/Math/ADSR_Envelope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System;
using ProtoFlux.Core;
using ProtoFlux.Runtimes.Execution;
using FrooxEngine.ProtoFlux;
using FrooxEngine;
using System.Threading.Tasks;
using Elements.Core;

namespace ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math
{
[NodeCategory("Obsidian/Math")]
public class ADSR_Envelope : AsyncActionNode<FrooxEngineContext>
{
public readonly ValueInput<float> AttackTime;
public readonly ValueInput<float> DecayTime;
public readonly ValueInput<float> SustainTime;
public readonly ValueInput<float> SustainValue;
public readonly ValueInput<float> ReleaseTime;

[DefaultValueAttribute(CurvePreset.Smooth)]
public ValueInput<CurvePreset> Curve;

public ObjectInput<IField<float>> Target;

public AsyncCall OnStarted;

public Continuation OnDone;

protected override async Task<IOperation> RunAsync(FrooxEngineContext context)
{
IField<float> field = Target.Evaluate(context);
if (field == null)
{
return null;
}

CurvePreset curve = Curve.Evaluate(context, CurvePreset.Smooth);
float attackTime = AttackTime.Evaluate(context);
float decayTime = DecayTime.Evaluate(context);
float sustainValue = SustainValue.Evaluate(context);
float sustainTime = SustainTime.Evaluate(context);
float releaseTime = ReleaseTime.Evaluate(context);

// ATTACK: tween from 0 to 1 over attackTime seconds
TaskCompletionSource<bool> completion = new TaskCompletionSource<bool>();
field.TweenFromTo(0f, 1f, attackTime, curve, null, delegate
{
completion.SetResult(result: true);
});
await OnStarted.ExecuteAsync(context);
await completion.Task;

// DECAY: tween from 1 to min(sustainValue, 1) over decayTime seconds
TaskCompletionSource<bool> completion2 = new TaskCompletionSource<bool>();
field.TweenFromTo(1f, MathX.Min(sustainValue, 1f), decayTime, curve, null, delegate
{
completion2.SetResult(result: true);
});
await completion2.Task;

// SUSTAIN: stay at min(sustainValue, 1) for sustainTime seconds
await Task.Delay(TimeSpan.FromSeconds(sustainTime));

// RELEASE: tween from min(sustainValue, 1) to 0 over releaseTime seconds
TaskCompletionSource<bool> completion3 = new TaskCompletionSource<bool>();
field.TweenFromTo(MathX.Min(sustainValue, 1f), 0f, releaseTime, curve, null, delegate
{
completion3.SetResult(result: true);
});
await completion3.Task;

return OnDone.Target;
}
}
}
Loading