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 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 NotesToPlay = new(); List NotesToStop = new(); protected override void OnDisabled() { Sfxr.TriggerReleaseAll(); StopSequence(); } protected override void OnUpdate() { if ( !IsPlaying ) return; Sfxr ??= GameObject.Components.Get(); 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(); } 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; } } }