mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 05:48:07 -04:00
This commit imports the C# engine code and game files, excluding C++ source code. [Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
278 lines
6.3 KiB
C#
278 lines
6.3 KiB
C#
namespace Editor;
|
|
|
|
public partial class SoundPlayer : Widget
|
|
{
|
|
private readonly TimelineView Timeline;
|
|
|
|
public bool Playing { get; set; }
|
|
public bool Repeating { get; set; }
|
|
public float Time { get; private set; }
|
|
|
|
public ToolBar ToolBar { get; private set; }
|
|
|
|
private readonly Option PlayOption;
|
|
|
|
private bool _prevPlay = false;
|
|
|
|
public SoundPlayer( Widget parent ) : base( parent )
|
|
{
|
|
Name = "Timeline";
|
|
WindowTitle = "Timeline";
|
|
SetWindowIcon( "timeline" );
|
|
|
|
Layout = Layout.Column();
|
|
|
|
var header = Layout.AddRow();
|
|
|
|
ToolBar = header.Add( new ToolBar( this ) );
|
|
ToolBar.NoSystemBackground = false;
|
|
ToolBar.SetIconSize( 18 );
|
|
PlayOption = ToolBar.AddOption( "Play", "play_arrow", () => Playing = !Playing );
|
|
|
|
var timecode = header.Add( new Label( this ) );
|
|
timecode.Bind( "Text" ).ReadOnly().From( () =>
|
|
{
|
|
TimeSpan t = TimeSpan.FromSeconds( Timeline.Time );
|
|
TimeSpan d = TimeSpan.FromSeconds( Timeline.Duration );
|
|
return $"{t.ToString( @"mm\:ss\.fff" )} / {d.ToString( @"mm\:ss\.fff" )}";
|
|
}, null );
|
|
timecode.Alignment = TextFlag.RightCenter;
|
|
|
|
var skipStart = ToolBar.AddOption( "Skip to Start", "skip_previous", () => Timeline.MoveScrubber( 0 ) );
|
|
ToolBar.AddSeparator();
|
|
var loop = ToolBar.AddOption( "Loop", "repeat" );
|
|
loop.Bind( "Checked" ).From( this, nameof( Repeating ) );
|
|
loop.Checkable = true;
|
|
|
|
Timeline = Layout.Add( new TimelineView( this ), 1 );
|
|
}
|
|
|
|
public void Play()
|
|
{
|
|
Playing = true;
|
|
}
|
|
|
|
public void Play( float start )
|
|
{
|
|
Timeline.MoveScrubber( start );
|
|
Play();
|
|
}
|
|
|
|
public void SetSamples( short[] samples, float duration, string sound )
|
|
{
|
|
Timeline.SetSamples( samples, duration, sound );
|
|
}
|
|
|
|
protected override void OnPaint()
|
|
{
|
|
base.OnPaint();
|
|
|
|
Paint.Antialiasing = false;
|
|
Paint.ClearPen();
|
|
Paint.SetBrush( Theme.WidgetBackground );
|
|
Paint.DrawRect( LocalRect );
|
|
}
|
|
|
|
[EditorEvent.Frame]
|
|
protected void OnFrame()
|
|
{
|
|
Timeline.OnFrame();
|
|
Time = Timeline.Time;
|
|
|
|
PlayOption.Text = Playing ? "Pause" : "Play";
|
|
PlayOption.Icon = Playing ? "pause" : "play_arrow";
|
|
|
|
if ( Application.FocusWidget.IsValid() )
|
|
{
|
|
if ( Application.IsKeyDown( KeyCode.Space ) && Application.KeyboardModifiers.HasFlag( KeyboardModifiers.Ctrl ) && !_prevPlay )
|
|
{
|
|
Play( 0 );
|
|
}
|
|
else if ( Application.IsKeyDown( KeyCode.Space ) && !_prevPlay )
|
|
{
|
|
Playing = !Playing;
|
|
}
|
|
_prevPlay = Application.IsKeyDown( KeyCode.Space );
|
|
}
|
|
}
|
|
|
|
public class TimelineView : GraphicsView
|
|
{
|
|
private readonly SoundPlayer Timeline;
|
|
private readonly TimeAxis TimeAxis;
|
|
private readonly Scrubber Scrubber;
|
|
private readonly WaveForm WaveForm;
|
|
|
|
public float ZoomLevel { get; set; } = 1.0f;
|
|
public float Duration { get; private set; }
|
|
public float Time { get; set; }
|
|
public bool Scrubbing { get; set; }
|
|
public string Sound { get; private set; }
|
|
public SoundHandle SoundHandle { get; private set; }
|
|
|
|
public TimelineView( SoundPlayer parent ) : base( parent )
|
|
{
|
|
Timeline = parent;
|
|
SceneRect = new( 0, Size );
|
|
HorizontalScrollbar = ScrollbarMode.On;
|
|
VerticalScrollbar = ScrollbarMode.Off;
|
|
Scale = 1;
|
|
Time = 0;
|
|
|
|
WaveForm = new WaveForm( this );
|
|
Add( WaveForm );
|
|
|
|
TimeAxis = new TimeAxis( this );
|
|
Add( TimeAxis );
|
|
|
|
Scrubber = new Scrubber( this );
|
|
Add( Scrubber );
|
|
|
|
DoLayout();
|
|
}
|
|
|
|
protected override void DoLayout()
|
|
{
|
|
base.DoLayout();
|
|
|
|
var size = Size;
|
|
size.x = MathF.Max( Size.x, PositionFromTime( Duration ) );
|
|
SceneRect = new( 0, size );
|
|
TimeAxis.Size = new Vector2( size.x, Theme.RowHeight );
|
|
Scrubber.Size = new Vector2( 9, size.y );
|
|
|
|
var r = SceneRect;
|
|
r.Position = Vector2.Zero.WithY( Theme.RowHeight );
|
|
r.Size = new Vector2( PositionFromTime( Duration ), Size.y - Theme.RowHeight );
|
|
WaveForm.SceneRect = r;
|
|
WaveForm.Analyse();
|
|
|
|
Scrubber.Position = Scrubber.Position.WithX( PositionFromTime( Time ) - 3 ).SnapToGrid( 1.0f );
|
|
}
|
|
|
|
protected override void OnResize()
|
|
{
|
|
base.OnResize();
|
|
DoLayout();
|
|
}
|
|
|
|
public override void OnDestroyed()
|
|
{
|
|
base.OnDestroyed();
|
|
|
|
SoundHandle?.Stop( 0.0f );
|
|
SoundHandle = null;
|
|
}
|
|
|
|
public Rect VisibleRect { get; private set; }
|
|
|
|
public void OnFrame()
|
|
{
|
|
Time = Time.Clamp( 0, Duration );
|
|
|
|
if ( !Timeline.Playing )
|
|
{
|
|
SoundHandle?.Stop( 0.0f );
|
|
SoundHandle = null;
|
|
}
|
|
|
|
VisibleRect = Rect.FromPoints( ToScene( LocalRect.TopLeft ), ToScene( LocalRect.BottomRight ) );
|
|
|
|
if ( Timeline.Playing && !Scrubbing )
|
|
{
|
|
Time += RealTime.Delta;
|
|
var time = Time % Duration;
|
|
if ( time < Time )
|
|
{
|
|
if ( Timeline.Repeating )
|
|
{
|
|
Time = time;
|
|
if ( SoundHandle.IsValid() )
|
|
{
|
|
SoundHandle.Time = Time;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
time = 0;
|
|
Time = time;
|
|
SoundHandle?.Stop( 0.0f );
|
|
Timeline.Playing = false;
|
|
}
|
|
}
|
|
|
|
if ( Timeline.Playing && !SoundHandle.IsValid() )
|
|
{
|
|
SoundHandle = EditorUtility.PlaySound( Sound, Time );
|
|
SoundHandle.Occlusion = false;
|
|
SoundHandle.DistanceAttenuation = false;
|
|
}
|
|
|
|
Scrubber.Position = Scrubber.Position.WithX( PositionFromTime( Time ) - 3 ).SnapToGrid( 1.0f );
|
|
}
|
|
|
|
if ( SoundHandle.IsValid() )
|
|
{
|
|
SoundHandle.Paused = Scrubbing;
|
|
}
|
|
|
|
TimeAxis.Update();
|
|
WaveForm.Update();
|
|
|
|
if ( Scrubbing || Timeline.Playing )
|
|
{
|
|
CenterOn( Scrubber.Position );
|
|
}
|
|
}
|
|
|
|
public float PositionFromTime( float time )
|
|
{
|
|
return (time / Duration).Clamp( 0, 1 ) * (Width * ZoomLevel);
|
|
}
|
|
|
|
public float TimeFromPosition( float position )
|
|
{
|
|
return (position / (Width * ZoomLevel)).Clamp( 0, 1 ) * Duration;
|
|
}
|
|
|
|
public void SetSamples( short[] samples, float duration, string sound )
|
|
{
|
|
Sound = sound;
|
|
Duration = duration;
|
|
WaveForm.SetSamples( samples, duration );
|
|
}
|
|
|
|
public void MoveScrubber( float position, bool centreOn = true )
|
|
{
|
|
Scrubber.Position = Vector2.Right * (position - 4).SnapToGrid( 1.0f );
|
|
Time = TimeFromPosition( Scrubber.Position.x + 4 );
|
|
|
|
if ( SoundHandle.IsValid() )
|
|
{
|
|
SoundHandle.Time = Time;
|
|
}
|
|
|
|
if ( centreOn )
|
|
{
|
|
CenterOn( Scrubber.Position );
|
|
VisibleRect = Rect.FromPoints( ToScene( LocalRect.TopLeft ), ToScene( LocalRect.BottomRight ) );
|
|
}
|
|
|
|
WaveForm.Update();
|
|
}
|
|
|
|
protected override void OnWheel( WheelEvent e )
|
|
{
|
|
ZoomLevel *= e.Delta > 0 ? 1.1f : 0.90f;
|
|
ZoomLevel = ZoomLevel.Clamp( 1.0f, 20.0f );
|
|
|
|
DoLayout();
|
|
|
|
TimeAxis.Update();
|
|
WaveForm.Update();
|
|
|
|
e.Accept();
|
|
}
|
|
}
|
|
}
|