Code/SFXRSequencer.cs
using System.Collections.Generic;
using System.Linq;
using Sandbox;
namespace SFXR;
[Title( "SFXR Sequencer" )]
[Category( "SFXR" )]
[Icon( "view_comfy" )]
public class SFXRSequencer : Component
{
[Property, Group( "Settings" )]
public float BPM { get; set; } = 120;
[Property, Group( "Settings" )]
public int BeatsPerBar { get; set; } = 4;
[Property, Group( "Notes" )]
public List<Note> Notes { get; set; } = new();
[Property, Group( "Controls" )]
public SFXRSequencerControls Controls { get; set; } = new();
public bool IsPlaying { get; private set; } = false;
public float CurrentTime { get; private set; } = 0f;
SFXRComponent Sfxr;
List<Note> NotesToPlay = new();
List<Note> NotesToStop = new();
protected override void OnDisabled()
{
Sfxr.TriggerReleaseAll();
StopSequence();
}
protected override void OnUpdate()
{
if ( !IsPlaying ) return;
Sfxr ??= GameObject.Components.Get<SFXRComponent>();
if ( Sfxr is null )
{
Log.Error( "SFXRSequencer requires an SFXRComponent to be attached to the same GameObject" );
return;
}
CurrentTime += Time.Delta;
for ( int i = 0; i < NotesToStop.Count; i++ )
{
var note = NotesToStop[i];
var time = BeatsToSeconds( note.Time + note.Length );
if ( CurrentTime >= time )
{
Sfxr.TriggerNoteRelease( note.Frequency );
NotesToStop.RemoveAt( i );
i--;
}
}
for ( int i = 0; i < NotesToPlay.Count; i++ )
{
var note = NotesToPlay[i];
var time = BeatsToSeconds( note.Time );
if ( CurrentTime >= time )
{
// Sfxr.Frequency.Start = note.Frequency;
// Sfxr.Length = BeatsToSeconds( note.Length );
// Sfxr.MasterVolume = note.Volume;
Sfxr.TriggerNotePress( note.Frequency, note.Volume );
NotesToStop.Add( note );
NotesToPlay.RemoveAt( i );
i--;
}
}
if ( NotesToPlay.Count == 0 && NotesToStop.Count == 0 )
{
IsPlaying = false;
}
}
public void PlaySequence()
{
if ( Sfxr is null )
{
Sfxr = GameObject.Components.Get<SFXRComponent>();
}
if ( !Sfxr.Enabled ) return;
IsPlaying = true;
CurrentTime = 0f;
NotesToPlay.Clear();
NotesToPlay.AddRange( Notes );
}
public void StopSequence()
{
IsPlaying = false;
CurrentTime = 0f;
}
public void PlayRange( float start, float end )
{
IsPlaying = true;
CurrentTime = BeatsToSeconds( start );
Sfxr.TriggerReleaseAll();
NotesToStop.Clear();
NotesToPlay.Clear();
NotesToPlay.AddRange( Notes.Where( x => x.Time >= start && x.Time <= end ) );
}
float BeatsToSeconds( float beats )
{
return beats * (60f / BPM / BeatsPerBar);
}
public class Note
{
[Property] public float Time { get; set; }
[Property] public float Frequency { get; set; }
[Property] public float Length { get; set; }
[Property] public float Volume { get; set; }
public Note()
{
Time = 0;
Frequency = 440;
Length = 1f;
Volume = 1f;
}
}
}