using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text.Json.Serialization; using static QuikDawEditor.EDITING.StaticProperties; using static QuikDawEditor.EDITING.MiscMethods; using static QuikDawEditor.EDITING.AudioMethods; using System.Windows.Threading; using System.IO; using System.Text.Json; using System.Diagnostics; using System.Windows.Shapes; using System.Windows.Media; using System.Windows; using System.Windows.Controls; using QuikDawEditor.Properties; using System.Windows.Media.Imaging; using QuikDawEditor.Undo; using QuikDawEditor.EDITING.PianoRollModel; using QuikDawEditor.MiscClasses; namespace QuikDawEditor.EditingClasses; public partial class Project : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public string RelRes() { ReleaseResources(); return "Resources released"; } private DispatcherTimer backupTimer = new DispatcherTimer(); public Project() { hiddenTracks.CollectionChanged += HiddenTracks_CollectionChanged; Tracks.CollectionChanged += Tracks_CollectionChanged; RecordInputs.CollectionChanged += RecordInputs_CollectionChanged; backupTimer = new DispatcherTimer() { Interval = new TimeSpan(0, Convert.ToInt32(Settings.Default.AutoSaveIntervalString), 0) }; backupTimer.Tick += BackupTimer_Tick; } //private bool _IsAudioLoading = false; //[JsonIgnore(Condition = JsonIgnoreCondition.Always)] //public bool IsAudioLoading { get { return _IsAudioLoading; } set { _IsAudioLoading = value; NotifyPropertyChanged(nameof(IsAudioLoading)); } } //private double _AudioLoadingPercent = 0; //[JsonIgnore(Condition = JsonIgnoreCondition.Always)] //public double AudioLoadingPercent { get { return _AudioLoadingPercent; } set { _AudioLoadingPercent = value; NotifyPropertyChanged(nameof(AudioLoadingPercent)); NotifyPropertyChanged(nameof(AudioLoadingText)); } } //internal string loadingAudioFileName = ""; //public string AudioLoadingText { get { return "Loading audio: " + loadingAudioFileName + " (" + Math.Round(100D * AudioLoadingPercent) + "%)"; } } [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public PianoRollModel pianoRoll { get; set; } = new PianoRollModel(); private double _ViewXZoomFac = 1; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public double ViewXZoomFac { get { return _ViewXZoomFac; } set { _ViewXZoomFac = value; projPlayer.ZoomModifiedUICounter = (int)Math.Truncate(projPlayer.PlayPosUpdateCycle * (3D / editingProject.ViewXZoomFac)); NotifyPropertyChanged(nameof(ViewXZoomFac)); } } private string _ProjectName; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public string ProjectName { get { return _ProjectName; } set { _ProjectName = value; NotifyPropertyChanged(nameof(ProjectName)); } } internal string ProjectDirectory { get { return System.IO.Path.GetDirectoryName(OpenedOriginalFilePath); } } internal string OpenedOriginalFilePath; private bool _NeedsSaving = false; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public bool NeedsSaving { get { return _NeedsSaving; } set { _NeedsSaving = value; NotifyPropertyChanged(nameof(NeedsSavingBackground)); } } public SolidColorBrush NeedsSavingBackground { get { return NeedsSaving ? Brushes.LightCoral : Brushes.Beige; } } private bool _AutomationRecordingEnabled = true; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public bool AutomationRecordingEnabled { get { return _AutomationRecordingEnabled; } set { _AutomationRecordingEnabled = value; NotifyPropertyChanged(nameof(AutomationRecordingEnabled)); } } public void UpdateAllClips(IEnumerable tracks) { foreach (Track t in tracks) { t.myTrackSampleProvider.myTrack = t; t.UpdateMyClipsToOwner(); if (t.SubTracks.Count > 0) UpdateAllClips(t.SubTracks); } } public void Create60BPMBasedMs() { } internal void ToggleTimeBeatsView() { projPlayer.IsTimePlayScale = !projPlayer.IsTimePlayScale; UpdateProjectGridLines(); projPlayer.ToggleScaleGrid(); } internal void ToggleBeatsPerMeasure() { if (projPlayer.IsTimePlayScale) return; BeatsPerMeasure += 1; if (BeatsPerMeasure > 4) BeatsPerMeasure = 3; projPlayer.NotifyPropertyChanged("PlayScaleImageSource"); projPlayer.NotifyPropertyChanged("PlayTimeCodeString"); UpdateProjectGridLines(); projPlayer.ToggleScaleGrid(); } [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public ObservableCollection hiddenTracks { get; set; } = new ObservableCollection(); [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public ObservableCollection RecordInputs { get; set; } = new ObservableCollection(); public double LeftDPWidth { get { depthCount = 0; GetRightOffsetDepth(Tracks); return 200 + depthCount * 10D; } } int depthCount = 0; public void GetRightOffsetDepth(IEnumerable tracks) { foreach (Track t in tracks) { if (t.IsSubmixTrack) { if (t.SubTracks.Count > 0) { depthCount += 1; GetRightOffsetDepth(t.SubTracks); } } } } public void UpdateLeftDPWidth() { NotifyPropertyChanged(nameof(LeftDPWidth)); } public Track GetRecordingTrack { get { return Tracks.Where(t => t.IsRecordingArmed).FirstOrDefault(); } } public Track GetAutomationRecordingTrack { get { return Tracks.Where(t => t.IsAutomationRecording).FirstOrDefault(); } } private void RecordInputs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { foreach (Track t in this.Tracks) t.UpdateRecInToolTip(); } private void BackupTimer_Tick(object sender, EventArgs e) { if (Settings.Default.AutoSave) Backup(); } public void Backup() { string backupName = ProjectBackupsDirectory + "\\" + ProjectName + "_Backup from " + DateTime.UtcNow.ToString("yyyy-MM-dd HH-mm-ss"); JsonSerializerOptions jso = new JsonSerializerOptions() { WriteIndented = true, IgnoreReadOnlyFields = true, IgnoreReadOnlyProperties = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; string returnstring = JsonSerializer.Serialize(this, typeof(Project), jso); File.WriteAllText(backupName, returnstring); projPlayer.SendLocalMessage("Backed up project: " + System.IO.Path.GetFileName(backupName)); } public void Save() { try { //Copy current project file as backup if (File.Exists(EditingProjectDataFileName)) File.Copy(EditingProjectDataFileName, ProjectBackupsDirectory + "\\" + ProjectName + "_Backup from " + DateTime.UtcNow.ToString("yyyy-MM-dd HH-mm-ss")); else { // File was renamed so move old file to backups if (EditingProjectDataFileName != OpenedOriginalFilePath) { try { File.Move(OpenedOriginalFilePath, ProjectBackupsDirectory + "\\" + System.IO.Path.GetFileName(OpenedOriginalFilePath)); } catch { } OpenedOriginalFilePath = EditingProjectDataFileName; } } JsonSerializerOptions jso = new JsonSerializerOptions() { IgnoreReadOnlyFields = true, IgnoreReadOnlyProperties = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; string returnstring = JsonSerializer.Serialize(this, typeof(Project), jso); File.WriteAllLines(EditingProjectDataFileName, new string[] { BeatsPerMinute.ToString() }); File.AppendAllText(EditingProjectDataFileName, returnstring); DeleteOrphanAudio(); NeedsSaving = false; projPlayer.SendLocalMessage("Project: " + ProjectName + " was saved. (" + DateTime.Now.ToString() + ")"); } catch (Exception ex) { Debug.WriteLine("Error trying to save on server\n" + ex.Message); } } private void Tracks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { //Debug.WriteLine("trackcollection changed--------"); if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { foreach (Track newTrack in e.NewItems) newTrack.myTrackSampleProvider.myTrack = newTrack; } } [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public bool HiddenTracksMenuVisible { get; set; } = false; private void HiddenTracks_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { HiddenTracksMenuVisible = hiddenTracks.Count > 0; NotifyPropertyChanged(nameof(HiddenTracksMenuVisible)); } public bool IsTimePlayScale { get { return projPlayer == null ? true : projPlayer.IsTimePlayScale; } } public void UpdatePlayScale() { NotifyPropertyChanged(nameof(IsTimePlayScale)); } private double _projectEndPointMs = 100000; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public double projectEndPointMs { get { return _projectEndPointMs; } set { _projectEndPointMs = value; NotifyPropertyChanged(nameof(projectEndPointMs)); NotifyPropertyChanged(nameof(projectEndPointMsReal)); } } public double projectEndPointMsReal { get { return projectEndPointMs - 20000; } } public void UpdateProjectEndPointMarker() { NotifyPropertyChanged(nameof(projectEndPointMsReal)); } private Visibility _ClipGainSliderVisibility = Visibility.Hidden; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public Visibility ClipGainSliderVisibility { get { return _ClipGainSliderVisibility; } set { _ClipGainSliderVisibility = value; NotifyPropertyChanged(nameof(ClipGainSliderVisibility)); } } private Thickness _ClipGainSliderMargin; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public Thickness ClipGainSliderMargin { get { return _ClipGainSliderMargin; } set { _ClipGainSliderMargin = value; NotifyPropertyChanged(nameof(ClipGainSliderMargin)); } } internal Clip GainAdjustingClip = null; internal float preSliderGainValue; private float _GainSliderValue = 0; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public float GainSliderValue { get { return _GainSliderValue; } set { _GainSliderValue = value; NotifyPropertyChanged(nameof(GainSliderValue)); } } [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public MovableImage trackFloatCanvas { get; set; } = new MovableImage(); internal double TracksContentSVVerticalOffset = 0; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public MovableImage clipFloatCanvas { get; set; } = new MovableImage(); internal Track movingTrack = null; internal Track dragOverTrack = null; internal void TrackDropCompleted() { movingTrack.ContentHidden = false; trackFloatCanvas.IsVisible = false; UpdateAllClips(Tracks); undoActions.Add(new TrackMoveUndo(movingTrack.premovingParentTrack == null ? "" : movingTrack.premovingParentTrack.UndoTrackID, movingTrack.preMoveIndex, movingTrack.UndoTrackID)); NeedsSaving = true; } internal void UpdateRangeSelectionBrush() { NotifyPropertyChanged(nameof(LoopRangeSelectionBrush)); } public SolidColorBrush LoopRangeSelectionBrush { get { return projPlayer.IsProjectLooped ? new SolidColorBrush(Colors.LightGreen) { Opacity = 0.4 } : new SolidColorBrush(Colors.LightGray) { Opacity = 0.4 }; } } public double LoopRangeRightMs { get { return LoopRangeLeftMs + LoopRangeWidthMs; } } private BitmapSource _ProjectSnapshot = null; [JsonIgnore(Condition = JsonIgnoreCondition.Always)] public BitmapSource ProjectSnapshot { get { return _ProjectSnapshot; } set { _ProjectSnapshot = value; NotifyPropertyChanged(nameof(ProjectSnapshot)); } } private void GetAllTracks(ObservableCollection tracks) { foreach (Track t in tracks) { AllTracks.Add(t); if (t.IsSubmixTrack) GetAllTracks(t.SubTracks); } } List AllTracks = new List(); internal List GetAllTracksInProject { get { AllTracks.Clear(); GetAllTracks(Tracks); return AllTracks; } } public void UpdateLoopRange() { NotifyPropertyChanged(nameof(LoopRangeWidthPix)); NotifyPropertyChanged(nameof(LoopRangeMargin)); } internal List GetSelectedMidiClips { get { return GetAllClips.Where(c => c.IsMidiClip && c.IsSelected).ToList(); } } internal List GetAllSelectedClips { get { return GetAllClips.Where(c=>c.IsSelected).ToList(); } } internal List GetAllClips { get { allClipsInTrack.Clear(); GetAllClipsInProject(Tracks); return allClipsInTrack; } } List allClipsInTrack = new List(); internal void GetAllClipsInProject(ObservableCollection tracks) { foreach (Track t in tracks) { if (t.IsSubmixTrack) GetAllClipsInProject(t.SubTracks); else foreach (Clip c in t.Clips) allClipsInTrack.Add(c); } } internal void ResetClipToBPM(Clip clipToReset) { clipToReset._ClipVirtualStartMs = TranslateMsToCurrentBPM(clipToReset.clipVirtualStartMs60BPM); if (clipToReset.clipType == ClipType.Midi) { clipToReset._ClipRelativeLoopStartMs = TranslateMsToCurrentBPM(clipToReset.clipRelativeLoopStartMs60BPM); clipToReset._ClipSourceLenMilliseconds = TranslateMsToCurrentBPM(clipToReset.clipSourceLenMs60BPM); clipToReset._ClipWidthMs = TranslateMsToCurrentBPM(clipToReset.clipWidthMs60BPM); foreach (GainPoint gp in clipToReset.GainPoints) gp._sourcePointms = TranslateMsToCurrentBPM(gp.sourcePointms60BPM); foreach (QDMidiEvent mevent in clipToReset.ClipMidiEvents) { mevent.ClipRelTimeMs = TranslateMsToCurrentBPM(mevent.ClipRelTimeMs60BPM); if (mevent is QDMidiNote) { QDMidiNote mnote = (QDMidiNote)mevent; mnote.ClipRelNoteOffTimeMs = TranslateMsToCurrentBPM(mnote.ClipRelNoteOffTimeMs60BPM); mnote.UpdateNoteMsValues(); mnote.UpdateNoteMsValuesMidiClip(); } } clipToReset.UpdateMidiImageSource(); } clipToReset.NotifyClipPropertyChanged(); } internal void ResetAllClipsToBPM() { foreach (Clip c in GetAllClips) ResetClipToBPM(c); if (pianoRoll.IsVisible) pianoRoll.UpdatePianoRollDisplayAll(); } Clip rightMostClip = null; double cliprightmostms = 0; internal Clip GetProjectRightMostClip(ObservableCollection tracks) { cliprightmostms = rightMostClip == null ? 0 : rightMostClip.ClipRightMs; foreach (Track t in tracks) { if (t.Clips.Count > 0) { if (t.Clips.Last().ClipRightMs > cliprightmostms) { rightMostClip = t.Clips.Last(); cliprightmostms = rightMostClip.ClipRightMs; } } if (t.IsSubmixTrack) rightMostClip = GetProjectRightMostClip(t.SubTracks); } return rightMostClip; } }