using NAudio.Lame; using NAudio.Wave; using QuikDawEditor.EditingClasses; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Threading; using static QuikDawEditor.EDITING.StaticProperties; namespace QuikDawEditor; public partial class MixdownsWindow : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } //int progressval = 0; bool selectionMixdown = false; Point MixdownSelectionRange; string mixdownFileName = "mix"; BackgroundWorker mixdownBW; public void MixdownProjectToFile(bool mixdownSelection, double selStart, double selEnd, string mixFileName) { selectionMixdown = mixdownSelection; MixdownSelectionRange = new Point(selStart, selEnd); mixdownFileName = mixFileName; CoverDP.Visibility = Visibility.Visible; coverMessageText = "Mixing down:\n" + mixdownFileName; IsMixingDown = true; mixdownBW = new BackgroundWorker() { WorkerReportsProgress = true }; mixdownBW.DoWork += MixdownBW_DoWork; mixdownBW.ProgressChanged += MixdownBW_ProgressChanged; mixdownBW.RunWorkerCompleted += MixdownBW_RunWorkerCompleted; mixdownBW.RunWorkerAsync(); } private void MixdownBW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { coverMessageText = "Mixdown complete:\nWriting file: 0%"; IsMixingDown = false; projPlayer.IsProjectPlaying = false; projPlayer.mmsp.ResetAllClips(0); projPlayer.AudioPlayerPlay(); projPlayer.StartPlayTimer(); } private void MixdownBW_ProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == -1) coverMessageText = "Error creating file"; else coverMessageText = "Mixing down: " + e.ProgressPercentage.ToString() + "%\n" + mixdownFileName; } private void MixdownBW_DoWork(object sender, DoWorkEventArgs e) { projPlayer.AudioPlayerStop(); projPlayer.StopPlayTimer(); projPlayer.IsProjectPlaying = true; projPlayer.CurrentPlayingPosMS = selectionMixdown ? MixdownSelectionRange.X : 0; double runningPlayPosMs = projPlayer.CurrentPlayingPosMS; //MasterMixingSampleProvider saveMSP = projPlayer.mmsp; projPlayer.mmsp.ResetAllClips(runningPlayPosMs); IWaveProvider waveProv = projPlayer.mmsp.ToWaveProvider16(); // IWaveProvider waveProv = saveMSP.ToWaveProvider(); var outWFormat = waveProv.WaveFormat; double endPointMs = 0; double bytePosInSavingFile = 0; foreach (Track t in editingProject.GetAllTracksInProject) foreach (Clip c in t.Clips) endPointMs = Math.Max(endPointMs, c.ClipRightMs); endPointMs = selectionMixdown ? MixdownSelectionRange.Y : endPointMs; //Debug.WriteLine("Full length time = " + TimeSpan.FromMilliseconds(endPointMs).ToString().Substring(0, 8)); double BytesPerSec = (double)outWFormat.SampleRate * (double)outWFormat.Channels * (double)(outWFormat.BitsPerSample / 8D); //176,400 int waveBytesCount = (int)((endPointMs - MixdownSelectionRange.X) / 1000D * BytesPerSec); //int waveBytesCount = (int)(endPointMs / 1000D * BytesPerSec); Debug.WriteLine("Number of wave bytes = " + waveBytesCount.ToString("N0")); //double playIncrement = 20; //int BufferSize = 3528; double playIncrement = 10; int BufferSize = 1764; //double playIncrement = 100; //int BufferSize = 17640; //int BufferSize = 8820; byte[] writeBytes = new byte[BufferSize]; List SaveWaveBytes = new List(); mixdownBW.ReportProgress(0); try { while (runningPlayPosMs < endPointMs) { int readcount = 0; try { //readcount = waveProv.Read(writeBytes, 0, writeBytes.Length); readcount = projPlayer.mmsp.ToWaveProvider16().Read(writeBytes, 0, writeBytes.Length); } catch (Exception exx) { Debug.WriteLine("Error in readingwaveprov16: " + exx.Message); } if (readcount > 0) { SaveWaveBytes.AddRange(writeBytes); bytePosInSavingFile += readcount; if (bytePosInSavingFile % (readcount * playIncrement * 2) == 0) { int percentDone = (int)Math.Round((double)(bytePosInSavingFile / waveBytesCount) * 100, 0); mixdownBW.ReportProgress(percentDone); Debug.WriteLine("CreatingWaveBytes: " + bytePosInSavingFile.ToString("N0") + " (" + percentDone.ToString() + "%) "); } } runningPlayPosMs += playIncrement; projPlayer.CurrentPlayingPosMS = runningPlayPosMs; } } catch (Exception ex) { Debug.WriteLine("\nSending Exception Streaming: " + ex.Message + "\nsendBytesLen=" + writeBytes.Length.ToString()); } Debug.WriteLine("\nRead actual bytes count=" + bytePosInSavingFile.ToString("N0")); try { string mixdownFilePath = ProjectMixdownDirectory + "\\" + mixdownFileName; //approxMp3FileSize = (int)((endPointMs / 1000D) / 50D * 620000D); approxMp3FileSize = (int)(((endPointMs - MixdownSelectionRange.X) / 1000D) / 50D * 620000D); LameConfig lconf = new LameConfig() { OutputSampleRate = 44100, ABRRateKbps = 96, BitRate = 96 }; LameMP3FileWriter lame3 = new LameMP3FileWriter(mixdownFilePath, waveProv.WaveFormat, lconf); Debug.WriteLine("Approx mp3filesize=" + approxMp3FileSize.ToString()); lame3.OnProgress += Lame3_OnProgress; lame3.MinProgressTime = 500; lame3.Write(SaveWaveBytes.ToArray(), 0, SaveWaveBytes.Count); lame3.Close(); Dispatcher.Invoke(() => { CoverDP.Visibility = Visibility.Hidden; GetMixdownFilesList(); }, DispatcherPriority.Normal); projPlayer.mmsp.ResetAllClips(0); } catch (Exception ex) { Debug.WriteLine("Error mixing down:\n" + ex.Message); mixdownBW.ReportProgress(-1); } } int approxMp3FileSize = 0; private string _coverMessageText; public string coverMessageText { get { return _coverMessageText; } set { _coverMessageText = value; NotifyPropertyChanged(nameof(coverMessageText)); } } private void Lame3_OnProgress(object writer, long inputBytes, long outputBytes, bool finished) { int percentDone = (int) ((double)outputBytes / (double)approxMp3FileSize * 100D); Dispatcher.Invoke(() => { coverMessageText = "Mixdown complete:\nWriting file: " + percentDone.ToString() + "%"; }, DispatcherPriority.Background); //Debug.WriteLine("\rWriting: " + outputBytes.ToString("N0") + " /" + approxMp3FileSize.ToString() + " (" + Math.Round((double)outputBytes / (double)approxMp3FileSize * 100, 0).ToString() + "%) "); if (finished) Debug.WriteLine("\nDone!"); } public void ChangeMixdownFileName(string oldFileName, string newFileName) { string mixdownDir = ProjectMixdownDirectory; if (!File.Exists(mixdownDir + "\\" + oldFileName)) return; try { File.Move(mixdownDir + "\\" + oldFileName, mixdownDir + "\\" + newFileName); } catch { Debug.WriteLine("File: " + oldFileName + " is inaccessible"); } GetMixdownFilesList(); } public void DeleteMixdownFileName(string fileName) { string mixdownDir = ProjectMixdownDirectory; if (!File.Exists(mixdownDir + "\\" + fileName)) return; try {File.Delete(mixdownDir + "\\" + fileName);} catch { Debug.WriteLine("File: " + fileName + " is inaccessible"); } GetMixdownFilesList(); } }