using NAudio.Midi; using QuikDawEditor.SampleProviders; using QuikDawEditor.VST; using static QuikDawEditor.EDITING.MidiMethods; namespace QuikDawEditor; public partial class ProjectPlayer : INotifyPropertyChanged { public string RelRes() { ReleaseResources(); return "Resources released"; } public event PropertyChangedEventHandler PropertyChanged; internal void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public MasterMixingSampleProvider mmsp; public readonly BufferedSampleProvider bufferedSampleProvider; internal bool IsZooming = false; //internal WaveOutEvent playWaveOut; //internal WaveInEvent recordWaveIn; internal MidiIn midiIn; internal Clip copyingClip; internal bool AutoScrollingOn = false; public ClipSelectionRect ClipSelectionRect { get; set; } = new ClipSelectionRect(); // { IsVisible = true, rectTop = 100, rectLeft = 500, rectWidth = 400, rectHeight = 350 }; public LyricWindow lyricWindow { get; set; } = new LyricWindow() { Owner = (EditorWindow)App.Current.MainWindow, DataContext = editingProject }; public delegate void SendProcessMessageHandler(string message); public event SendProcessMessageHandler SendProcessMessage; public void SendLocalMessage(string mess) { SendProcessMessage(mess); } public delegate void ScaleGridToggledHandler(); public event ScaleGridToggledHandler ScaleGridToggled; public void ToggleScaleGrid() { ScaleGridToggled(); } public delegate void ScrollTracksContentSVForwardHandler(double scrollPix); public event ScrollTracksContentSVForwardHandler ScrollTracksContentSVForward; public delegate void UpdateProjectEndPointHandler(); public event UpdateProjectEndPointHandler UpdateProjectEndPoint; public void UpdateEndPoint() { UpdateProjectEndPoint(); NotifyPropertyChanged(nameof(TotalTimeCodeString)); } public double BeatsPerMinuteProject { get { return Math.Round(BeatsPerMinute); } set { if (BeatsPerMinute != value) { oldBPMvalue = BeatsPerMinute; BeatsPerMinute = Math.Round(value); NotifyPropertyChanged(nameof(BeatsPerMinuteProject)); } } } bool _IsProjectLooped = false; public bool IsProjectLooped { get { return _IsProjectLooped; } set { _IsProjectLooped = value; NotifyPropertyChanged(nameof(LoopButImageSource)); editingProject.UpdateRangeSelectionBrush(); } } public bool LoopRangeRectSelected { get { return editingProject == null ? false : editingProject.LoopRangeSelected; } } public string PlayScaleImageSource { get { return IsTimePlayScale ? "/EDITING/images/Clock.png" : editingProject.BeatsPerMeasure == 3 ? "/EDITING/images/TimeSig34.png" : "/EDITING/images/TimeSig44.png"; } } public string PlayButImageSource { get { return IsProjectPlaying ? "/EDITING/images/PauseButImg.png" : "/EDITING/images/PlayButImg.png"; } } public string LoopButImageSource { get { return IsProjectLooped ? "/EDITING/images/LoopButOnImg.png" : "/EDITING/images/LoopButOffImg.png"; } } public string RecButImgSource { get { return "/EDITING/images/" + ((IsProjectRecording ? "RecordStopImg.png" : "RecordButImg.png")); } } public bool IsProjectNotPlaying { get { return !IsProjectPlaying; } } private bool HasArmedTrack { get { return editingProject.GetAllTracksInProject.Where(t => t.IsRecordingArmed).Count() > 0; } } public void NotifyTrackArmed() { NotifyPropertyChanged(nameof(RecordButEnabled)); } public bool RecordButEnabled { get { return AudioDeviceOK && HasArmedTrack && (IsProjectNotPlaying | IsProjectRecording); } } private bool _PlayControlsDPDisabled = false; public bool PlayControlsDPDisabled { get { return _PlayControlsDPDisabled; } set { _PlayControlsDPDisabled = value; NotifyPropertyChanged(nameof(ControlsDPCoverVisible)); } } public bool ControlsDPCoverVisible { get { return IsProjectRecording | PlayControlsDPDisabled; } } private bool _IsTimePlayScale = false; public bool IsTimePlayScale { get { return _IsTimePlayScale; } set { _IsTimePlayScale = value; editingProject.UpdatePlayScale(); NotifyPropertyChanged(nameof(PlayTimeCodeString)); NotifyPropertyChanged(nameof(PlayScaleImageSource)); } } public void Dispose() { try { try { projPlayTimer.MicroTimerElapsed -= projPlayTimer_MicroTimerElapsed; playAsioOut?.Dispose(); //playWaveOut?.Dispose(); } catch (Exception ex1) { MessageBox.Show("Error disposing asioout or waveout\n" + ex1.Message); } //try { mmsp = null; } catch(Exception ex3) { MessageBox.Show("error making mmsp null\n" + ex3.Message); } try { foreach (Track t in editingProject.GetAllTracksInProject) { foreach (Clip c in t.Clips) c.Dispose(); foreach (ActiveVstPlugin avp in t.TrackInstrumentVsts) avp.Close(); foreach (ActiveVstPlugin avp in t.TrackEffectVsts) avp.Close(); //t.myTrackSampleProvider = null; // can cause errors on dispose because previous reads still reading t.TrackInstrumentVsts.Clear(); t.TrackEffectVsts.Clear(); if (t.trackType == TrackType.Midi) t.vstiWin?.Close(); t.fxWindow?.Close(); } foreach (Track t in editingProject.GetAllTracksInProject) if (t.trackType != TrackType.Submix) t.myTrackSampleProvider = null; } catch (Exception ex2) { MessageBox.Show("Error disposing tracks or effects\n" + ex2.Message); } try { mmsp = null; } catch (Exception ex3) { MessageBox.Show("error making mmsp null\n" + ex3.Message); } lyricWindow.userClosing = false; lyricWindow.Close(); try { editingProject?.Tracks.Clear(); } catch { } //catch(Exception ex4) { MessageBox.Show("Error clearing the damn tracks\n" + ex4.Message); } ISPROJECTLOADED = false; } catch (Exception ex) { MessageBox.Show("Error disposing project player:\n" + ex.Message); } } private void UpdateTrackArmButs(ObservableCollection tracks) { foreach (Track t in tracks.Where(ttra => ttra.IsAudioTrack)) { t.UpdateArmButEnabled(); if (t.IsSubmixTrack) UpdateTrackArmButs(t.SubTracks); } } public ProjectPlayer() { mmsp = new MasterMixingSampleProvider(DefaultPlayWaveFormat, editingProject) { ReadFully = true }; bufferedSampleProvider = new BufferedSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2)) { DiscardOnBufferOverflow = true , BufferDuration = new TimeSpan(0, 10, 0) }; AudioDeviceOK = InitializeAudio(); CreateMetronome(); } public void CreateMetronome() { Clip MetronomeClip = new Clip("Metronome", ClipType.Audio) { ClipSourceLenMilliseconds = BeatsPerMinute, ClipWidthMs = MillisecondsPerBeat }; MetronomeClip.GainPoints.Add(new GainPoint() { sourcePointms = 0, GainValue = 1 }); MetronomeClip.GainPoints.Add(new GainPoint() { sourcePointms = MetronomeClip.ClipWidthMs, GainValue = 1 }); MetronomeClip.myClipSampleProvider = new ClipSampleProvider() { myClipStream = new ClipStream(AppDomain.CurrentDomain.BaseDirectory + "\\audio\\MetronomeBeat6sec.mp3") }; MetronomeClip.myClipSampleProvider.AssignSampleProvider(false); editingProject.MasterTrack.MetronomeCSP = MetronomeClip.myClipSampleProvider; } public void TogglePlayPauseCurrentProject() { IsProjectPlaying = !IsProjectPlaying || editingProject.pianoRoll.clipPlaying; switch (IsProjectPlaying) { case true: if (editingProject.pianoRoll.clipPlaying) { editingProject.pianoRoll.StopPlay(); editingProject.pianoRoll.clipPlaying = false; //StopAllNotes(); CurrentPlayingPosMS = editingProject.pianoRoll.keepPlayPos; } break; case false: StopAllNotes(); bufferedSampleProvider.ClearBuffer(); break; } } public void StartPlayTimer() { projPlayTimer.Start(); } public void StopPlayTimer() { projPlayTimer.Stop();} public bool IsPianoRollPlaying { get {return editingProject.pianoRoll.clipPlaying; } } public bool CanMixdown { get { return AudioDeviceOK && IsProjectNotPlaying && editingProject.GetAllTracksInProject.Where(t=>t.Clips.Count > 0).Count() > 0 ; } } public void UpdateCanMixdown() { NotifyPropertyChanged(nameof(CanMixdown)); } bool _IsProjectPlaying = false; public bool IsProjectPlaying { get { return _IsProjectPlaying; } set { _IsProjectPlaying = value; InfoText = _IsProjectPlaying ? "Playing" : "Stopped"; foreach (Track t in editingProject.GetAllTracksInProject) { t.IsProjectPlayingEnabled = !_IsProjectPlaying; t.TrackOutputVolume = 0; //meters to zero t.UpdateArmButEnabled(); } NotifyPropertyChanged(nameof(IsProjectNotPlaying)); NotifyPropertyChanged(nameof(CanMixdown)); NotifyPropertyChanged(nameof(PlayButImageSource)); NotifyPropertyChanged(nameof(IsProjectPlaying)); NotifyPropertyChanged(nameof(RecordButEnabled)); if (!_IsProjectPlaying) StopAllNotes(); } } }