OverviewFilesCommitsIssuesDocsReleasesPeers

ifsrenderer-linux / WpfDisplay / ViewModels / ChannelViewModel.cs

199 lines · csharp ref:
#nullable enable
using System;
using System.Collections.ObjectModel;
using System.Linq;

using Cavern.Channels;

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

using IFSEngine.Animation;
using IFSEngine.Animation.ChannelDrivers;

using WpfDisplay.Helper;

namespace WpfDisplay.ViewModels;

public partial class ChannelViewModel : ObservableObject
{
    public string Name
    {
        get => channel.Name;
        set
        {
            channel.Name = value;
            OnPropertyChanged(nameof(Name));
        }
    }
    public string Path { get; }

    public AnimationViewModel AnimationVM { get; }

    public readonly Channel channel;
    [ObservableProperty]
    public partial ObservableCollection<KeyframeViewModel> Keyframes { get; set; } = [];

    [ObservableProperty]
    public partial bool HasAudioDriver { get; set; } = false;

    [ObservableProperty]
    public partial ReferenceChannel SelectedAudioChannelOption { get; set; } = default!;

    private float Sampler(AudioChannelDriver d, double t)
    {
        if (AnimationVM.Audio is null)
            return 0.0f;
        return CavernHelper.CavernSampler(AnimationVM.Audio, d.AudioChannelId, d.MinFrequency, d.MaxFrequency, t);
    }

    public bool IsDriverEnabled
    {
        get => EffectStrength != 0.0;
        set
        {
            AnimationVM.Workspace.TakeSnapshot();
            EffectStrength = value ? 1.0f : 0.0f;
            AnimationVM.Workspace.Renderer.InvalidateParamsBuffer();
            AnimationVM.Workspace.RaiseAnimationFrameChanged();
        }
    }

    public double EffectStrength
    {
        get => channel.AudioChannelDriver?.EffectMultiplier ?? 1;
        set
        {
            if (channel.AudioChannelDriver is not null)
                channel.AudioChannelDriver.EffectMultiplier = value;
            OnPropertyChanged(nameof(EffectStrength));
        }
    }

    private ValueSliderSettings? _effectSlider;
    public ValueSliderSettings EffectSlider => _effectSlider ??= new()
    {
        Label = "Effect strength",
        ToolTip = "Effect strength",
        DefaultValue = 1,
        Increment = 0.01,
        ValueWillChange = AnimationVM.Workspace.TakeSnapshot,
        ValueChanged = (v) => AnimationVM.Workspace.Renderer.InvalidateParamsBuffer()
    };

    public double MinFreq
    {
        get => channel.AudioChannelDriver?.MinFrequency ?? 1;
        set
        {
            if (channel.AudioChannelDriver is not null)
                channel.AudioChannelDriver.MinFrequency = (int)value;
        }
    }

    private ValueSliderSettings? _minFreqSlider;
    public ValueSliderSettings MinFreqSlider => _minFreqSlider ??= new()
    {
        Label = "Min. Frequency",
        ToolTip = "Minimum Frequency",
        DefaultValue = 0,
        Increment = 1,
        MinValue = 0,
        ValueWillChange = AnimationVM.Workspace.TakeSnapshot,
        ValueChanged = (v) => AnimationVM.Workspace.Renderer.InvalidateParamsBuffer()
    };

    public double MaxFreq
    {
        get => channel.AudioChannelDriver?.MaxFrequency ?? 1;
        set
        {
            if (channel.AudioChannelDriver is not null)
                channel.AudioChannelDriver.MaxFrequency = (int)value;
        }
    }

    private ValueSliderSettings? _maxFreqSlider;
    public ValueSliderSettings MaxFreqSlider => _maxFreqSlider ??= new()
    {
        Label = "Max. Frequency",
        ToolTip = "Maximum Frequency",
        DefaultValue = 20000,
        Increment = 1,
        MaxValue = 20000,
        ValueWillChange = AnimationVM.Workspace.TakeSnapshot,
        ValueChanged = (v) => AnimationVM.Workspace.Renderer.InvalidateParamsBuffer()
    };

    public ChannelViewModel(AnimationViewModel vm, string path, Channel c)
    {
        AnimationVM = vm;
        Path = path;
        channel = c;

        SelectedAudioChannelOption = (ReferenceChannel)(c.AudioChannelDriver?.AudioChannelId ?? 0);
        channel.AudioChannelDriver?.SetSamplerFunction(Sampler);
        HasAudioDriver = c.AudioChannelDriver != null;

        UpdateKeyframes();
    }

    public void RemoveKeyframe(KeyframeViewModel kvm)
    {
        Keyframes.Remove(kvm);
        channel.Keyframes.Remove(kvm._k);
    }

    public void UpdateKeyframes()
    {
        var removed = Keyframes.Where(k => !channel.Keyframes.Contains(k._k));
        foreach (var kvm in removed)
            Keyframes.Remove(kvm);
        var newKeyframes = channel.Keyframes.Where(k => !Keyframes.Any(kvm => kvm._k == k));
        foreach (var k in newKeyframes)
            Keyframes.Add(new KeyframeViewModel(AnimationVM, this, k, false));
    }

    [RelayCommand]
    public void InsertKeyframe()
    {
        if (!AnimationVM.KeyframeInsertPosition.HasValue) throw new InvalidOperationException();
        AnimationVM.Workspace.TakeSnapshot();
        var keyframePosition = TimeOnly.FromTimeSpan(TimeSpan.FromSeconds(AnimationVM.KeyframeInsertPosition.Value));
        var eval = channel.EvaluateAt(AnimationVM.KeyframeInsertPosition.Value);
        AnimationVM.AddOrUpdateChannel(Name, Path, eval, keyframePosition);
        AnimationVM.KeyframeInsertPosition = null;
    }

    //TODO: add ChannelDriverEnum Command Parameter
    [RelayCommand]
    public void AddChannelDriver()
    {
        AnimationVM.Workspace.TakeSnapshot();
        channel.AudioChannelDriver ??= new AudioChannelDriver();
        SelectedAudioChannelOption = (ReferenceChannel)channel.AudioChannelDriver.AudioChannelId;
        channel.AudioChannelDriver.SetSamplerFunction(Sampler);
        AnimationVM.Workspace.Renderer.InvalidateParamsBuffer();
        HasAudioDriver = true;
        OnPropertyChanged(string.Empty);
        AnimationVM.Workspace.RaiseAnimationFrameChanged();
    }

    //TODO: add ChannelDriver Command Parameter
    [RelayCommand]
    public void RemoveChannelDriver()
    {
        AnimationVM.Workspace.TakeSnapshot();
        channel.AudioChannelDriver = null;
        AnimationVM.Workspace.Renderer.InvalidateParamsBuffer();
        HasAudioDriver = false;
        OnPropertyChanged(string.Empty);
        AnimationVM.Workspace.RaiseAnimationFrameChanged();
    }


    [RelayCommand]
    public void CloseChannelEditor() => AnimationVM.CloseChannelEditor();

}