From ca8bb2fff6edc16dc20271fbfc287c54f015539c Mon Sep 17 00:00:00 2001 From: Grigory Chudov Date: Fri, 23 Mar 2018 20:26:28 -0400 Subject: [PATCH] Code cleanup; Reader classes renamed to Decoders, Writers to Encoders, every Decoder must have a corresponding Settings class now just like Encoders. UserDefinedEncoders renamed to CommandLineEncoders, etc. --- CUETools.Codecs/CUEToolsCodecsConfig.cs | 16 +- CUETools.Codecs/CUEToolsUDC.cs | 271 --------- CUETools.Codecs/CUEToolsUDCList.cs | 88 --- .../AudioDecoder.cs} | 224 +++---- .../AudioEncoder.cs} | 274 ++++----- .../DecoderSettings.cs} | 8 +- .../EncoderSettings.cs} | 126 ++-- CUETools.Codecs/DummyWriter.cs | 41 -- .../AudioDecoder.cs} | 122 ++-- CUETools.Codecs/NULL/AudioEncoder.cs | 35 ++ .../AudioDecoderSettingsViewModel.cs | 112 ++++ .../AudioEncoderSettingsViewModel.cs | 165 ++++++ .../ViewModel/DecoderListViewModel.cs | 46 ++ .../ViewModel/EncoderListViewModel.cs | 47 ++ .../{WAVReader.cs => WAV/AudioDecoder.cs} | 555 +++++++++--------- .../{WAVWriter.cs => WAV/AudioEncoder.cs} | 362 ++++++------ CUETools.Codecs/WAV/DecoderSettings.cs | 19 + .../EncoderSettings.cs} | 58 +- CUETools.FLACCL.cmd/Program.cs | 2 +- CUETools.Processor/AudioReadWrite.cs | 4 +- CUETools.Processor/CUEConfig.cs | 16 +- CUETools.Processor/CUESheet.cs | 2 +- 22 files changed, 1301 insertions(+), 1292 deletions(-) delete mode 100644 CUETools.Codecs/CUEToolsUDC.cs delete mode 100644 CUETools.Codecs/CUEToolsUDCList.cs rename CUETools.Codecs/{UserDefinedReader.cs => CommandLine/AudioDecoder.cs} (89%) rename CUETools.Codecs/{UserDefinedWriter.cs => CommandLine/AudioEncoder.cs} (92%) rename CUETools.Codecs/{UserDefinedDecoderSettings.cs => CommandLine/DecoderSettings.cs} (84%) rename CUETools.Codecs/{UserDefinedEncoderSettings.cs => CommandLine/EncoderSettings.cs} (79%) delete mode 100644 CUETools.Codecs/DummyWriter.cs rename CUETools.Codecs/{SilenceGenerator.cs => NULL/AudioDecoder.cs} (83%) create mode 100644 CUETools.Codecs/NULL/AudioEncoder.cs create mode 100644 CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs create mode 100644 CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs create mode 100644 CUETools.Codecs/ViewModel/DecoderListViewModel.cs create mode 100644 CUETools.Codecs/ViewModel/EncoderListViewModel.cs rename CUETools.Codecs/{WAVReader.cs => WAV/AudioDecoder.cs} (93%) rename CUETools.Codecs/{WAVWriter.cs => WAV/AudioEncoder.cs} (97%) create mode 100644 CUETools.Codecs/WAV/DecoderSettings.cs rename CUETools.Codecs/{WAVWriterSettings.cs => WAV/EncoderSettings.cs} (95%) diff --git a/CUETools.Codecs/CUEToolsCodecsConfig.cs b/CUETools.Codecs/CUEToolsCodecsConfig.cs index ff2608f..08197c3 100644 --- a/CUETools.Codecs/CUEToolsCodecsConfig.cs +++ b/CUETools.Codecs/CUEToolsCodecsConfig.cs @@ -12,15 +12,15 @@ namespace CUETools.Codecs public class CUEToolsCodecsConfig { public Dictionary formats; - public CUEToolsUDCEncoderList encoders; - public CUEToolsUDCDecoderList decoders; + public EncoderListViewModel encoders; + public DecoderListViewModel decoders; public CUEToolsCodecsConfig(CUEToolsCodecsConfig src) { - encoders = new CUEToolsUDCEncoderList(); + encoders = new EncoderListViewModel(); foreach (var enc in src.encoders) encoders.Add(enc.Clone()); - decoders = new CUEToolsUDCDecoderList(); + decoders = new DecoderListViewModel(); foreach (var dec in src.decoders) decoders.Add(dec.Clone()); formats = new Dictionary(); @@ -30,7 +30,7 @@ namespace CUETools.Codecs public CUEToolsCodecsConfig(List encs, List decs) { - encoders = new CUEToolsUDCEncoderList(); + encoders = new EncoderListViewModel(); foreach (Type type in encs) foreach (AudioEncoderClassAttribute enc in Attribute.GetCustomAttributes(type, typeof(AudioEncoderClassAttribute))) try @@ -42,7 +42,7 @@ namespace CUETools.Codecs System.Diagnostics.Trace.WriteLine(ex.Message); } - decoders = new CUEToolsUDCDecoderList(); + decoders = new DecoderListViewModel(); foreach (Type type in decs) foreach (AudioDecoderClassAttribute dec in Attribute.GetCustomAttributes(type, typeof(AudioDecoderClassAttribute))) try @@ -66,8 +66,8 @@ namespace CUETools.Codecs encoders.Add(new AudioEncoderSettingsViewModel("nero aac", "m4a", false, "0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9", "0.4", "neroAacEnc.exe", "-q %M -if - -of %O")); encoders.Add(new AudioEncoderSettingsViewModel("qaac tvbr", "m4a", false, "10 20 30 40 50 60 70 80 90 100 110 127", "80", "qaac.exe", "-s -V %M -q 2 - -o %O")); - decoders.Add(new AudioDecoderSettingsViewModel(new CommandLineDecoderSettings("takc", "tak", "takc.exe", "-d %I -"))); - decoders.Add(new AudioDecoderSettingsViewModel(new CommandLineDecoderSettings("ffmpeg alac", "m4a", "ffmpeg.exe", "-v 0 -i %I -f wav -"))); + decoders.Add(new AudioDecoderSettingsViewModel(new CommandLine.DecoderSettings("takc", "tak", "takc.exe", "-d %I -"))); + decoders.Add(new AudioDecoderSettingsViewModel(new CommandLine.DecoderSettings("ffmpeg alac", "m4a", "ffmpeg.exe", "-v 0 -i %I -f wav -"))); } else { diff --git a/CUETools.Codecs/CUEToolsUDC.cs b/CUETools.Codecs/CUEToolsUDC.cs deleted file mode 100644 index 0b87c9d..0000000 --- a/CUETools.Codecs/CUEToolsUDC.cs +++ /dev/null @@ -1,271 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.ComponentModel; - -namespace CUETools.Codecs -{ - [JsonObject(MemberSerialization.OptIn)] - public class AudioEncoderSettingsViewModel : INotifyPropertyChanged - { - [JsonProperty] - public AudioEncoderSettings settings = null; - - public event PropertyChangedEventHandler PropertyChanged; - - [JsonConstructor] - private AudioEncoderSettingsViewModel() - { - } - - public AudioEncoderSettingsViewModel( - string _name, - string _extension, - bool _lossless, - string _supported_modes, - string _default_mode, - string _path, - string _parameters - ) - { - settings = new CommandLineEncoderSettings() { name = _name, extension = _extension, SupportedModes = _supported_modes, EncoderMode = _default_mode, Path = _path, Parameters = _parameters, lossless = _lossless }; - } - - public AudioEncoderSettingsViewModel(AudioEncoderClassAttribute enc) - { - settings = Activator.CreateInstance(enc.Settings) as AudioEncoderSettings; - if (settings == null) - throw new InvalidOperationException("invalid codec"); - } - - public AudioEncoderSettingsViewModel Clone() - { - var res = this.MemberwiseClone() as AudioEncoderSettingsViewModel; - if (settings != null) res.settings = settings.Clone(); - return res; - } - - public override string ToString() - { - return Name; - } - - public string FullName => Name + " [" + Extension + "]"; - - public string Path - { - get - { - if (settings is CommandLineEncoderSettings) - return (settings as CommandLineEncoderSettings).Path; - return ""; - } - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.Path = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); - } - } - - public string Parameters - { - get - { - if (settings is CommandLineEncoderSettings) - return (settings as CommandLineEncoderSettings).Parameters; - return ""; - } - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.Parameters = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); - } - } - - public bool Lossless - { - get => settings.Lossless; - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.lossless = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Lossless")); - } - } - - - public string Name - { - get => settings.Name; - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.name = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); - } - } - - public string Extension - { - get => settings.Extension; - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.extension = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); - } - } - - public string DotExtension => "." + Extension; - - public string SupportedModesStr - { - get - { - string defaultMode; - return this.settings.GetSupportedModes(out defaultMode); - } - set - { - var settings = this.settings as CommandLineEncoderSettings; - if (settings == null) throw new InvalidOperationException(); - settings.SupportedModes = value; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SupportedModesStr")); - } - } - - public string[] SupportedModes => this.SupportedModesStr.Split(' '); - - public int EncoderModeIndex - { - get - { - string[] modes = this.SupportedModes; - if (modes == null || modes.Length < 2) - return -1; - for (int i = 0; i < modes.Length; i++) - if (modes[i] == this.settings.EncoderMode) - return i; - return -1; - } - } - - public bool CanBeDeleted => settings is CommandLineEncoderSettings; - - public bool IsValid => - (settings != null) - && (settings is CommandLineEncoderSettings ? (settings as CommandLineEncoderSettings).Path != "" : true); - } - - [JsonObject(MemberSerialization.OptIn)] - public class AudioDecoderSettingsViewModel : INotifyPropertyChanged - { - [JsonProperty] - public AudioDecoderSettings decoderSettings = null; - - public event PropertyChangedEventHandler PropertyChanged; - - [JsonConstructor] - private AudioDecoderSettingsViewModel() - { - } - - public AudioDecoderSettingsViewModel(AudioDecoderSettings settings) - { - decoderSettings = settings; - } - - public AudioDecoderSettingsViewModel Clone() - { - var res = this.MemberwiseClone() as AudioDecoderSettingsViewModel; - if (decoderSettings != null) res.decoderSettings = decoderSettings.Clone(); - return res; - } - - public override string ToString() - { - return Name; - } - - public string FullName => Name + " [" + Extension + "]"; - - public string Path - { - get - { - if (decoderSettings is CommandLineDecoderSettings) - return (decoderSettings as CommandLineDecoderSettings).Path; - return ""; - } - set - { - if (decoderSettings is CommandLineDecoderSettings) - (decoderSettings as CommandLineDecoderSettings).Path = value; - else throw new InvalidOperationException(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); - } - } - public string Parameters - { - get - { - if (decoderSettings is CommandLineDecoderSettings) - return (decoderSettings as CommandLineDecoderSettings).Parameters; - return ""; - } - set - { - if (decoderSettings is CommandLineDecoderSettings) - (decoderSettings as CommandLineDecoderSettings).Parameters = value; - else throw new InvalidOperationException(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); - } - } - - public bool Lossless - { - get => true; - set { - throw new InvalidOperationException(); - } - } - - public string Name - { - get => decoderSettings.Name; - set - { - if (decoderSettings is CommandLineDecoderSettings) - (decoderSettings as CommandLineDecoderSettings).name = value; - else throw new InvalidOperationException(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); - } - } - - public string Extension - { - get => decoderSettings.Extension; - set - { - if (decoderSettings is CommandLineDecoderSettings) - (decoderSettings as CommandLineDecoderSettings).extension = value; - else throw new InvalidOperationException(); - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); - } - } - - public string DotExtension => "." + Extension; - - public bool CanBeDeleted => decoderSettings is CommandLineDecoderSettings; - - public bool IsValid => - (decoderSettings != null) - && (decoderSettings is CommandLineDecoderSettings ? (decoderSettings as CommandLineDecoderSettings).Path != "" : true); - } -} diff --git a/CUETools.Codecs/CUEToolsUDCList.cs b/CUETools.Codecs/CUEToolsUDCList.cs deleted file mode 100644 index 2b09bfc..0000000 --- a/CUETools.Codecs/CUEToolsUDCList.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.ComponentModel; - -namespace CUETools.Codecs -{ - public class CUEToolsUDCEncoderList : BindingList - { - public CUEToolsUDCEncoderList() - : base() - { - AddingNew += OnAddingNew; - } - - private void OnAddingNew(object sender, AddingNewEventArgs e) - { - e.NewObject = new AudioEncoderSettingsViewModel("new", "wav", true, "", "", "", ""); - } - - public bool TryGetValue(string extension, bool lossless, string name, out AudioEncoderSettingsViewModel result) - { - //result = this.Where(udc => udc.settings.Extension == extension && udc.settings.Lossless == lossless && udc.settings.Name == name).First(); - foreach (AudioEncoderSettingsViewModel udc in this) - { - if (udc.settings.Extension == extension && udc.settings.Lossless == lossless && udc.settings.Name == name) - { - result = udc; - return true; - } - } - result = null; - return false; - } - - public AudioEncoderSettingsViewModel GetDefault(string extension, bool lossless) - { - AudioEncoderSettingsViewModel result = null; - foreach (AudioEncoderSettingsViewModel udc in this) - { - if (udc.settings.Extension == extension && udc.settings.Lossless == lossless && (result == null || result.settings.Priority < udc.settings.Priority)) - { - result = udc; - } - } - return result; - } - } - - public class CUEToolsUDCDecoderList : BindingList - { - public CUEToolsUDCDecoderList() - : base() - { - AddingNew += OnAddingNew; - } - - private void OnAddingNew(object sender, AddingNewEventArgs e) - { - e.NewObject = new AudioDecoderSettingsViewModel(new CommandLineDecoderSettings("new", "wav", "", "")); - } - - public bool TryGetValue(string extension, bool lossless, string name, out AudioDecoderSettingsViewModel result) - { - foreach (AudioDecoderSettingsViewModel udc in this) - { - if (udc.decoderSettings.Extension == extension && udc.decoderSettings.Lossless == lossless && udc.decoderSettings.Name == name) - { - result = udc; - return true; - } - } - result = null; - return false; - } - - public AudioDecoderSettingsViewModel GetDefault(string extension, bool lossless) - { - AudioDecoderSettingsViewModel result = null; - foreach (AudioDecoderSettingsViewModel udc in this) - { - if (udc.decoderSettings.Extension == extension && udc.decoderSettings.Lossless == lossless && (result == null || result.decoderSettings.Priority < udc.decoderSettings.Priority)) - { - result = udc; - } - } - return result; - } - } -} diff --git a/CUETools.Codecs/UserDefinedReader.cs b/CUETools.Codecs/CommandLine/AudioDecoder.cs similarity index 89% rename from CUETools.Codecs/UserDefinedReader.cs rename to CUETools.Codecs/CommandLine/AudioDecoder.cs index f48496a..d49637b 100644 --- a/CUETools.Codecs/UserDefinedReader.cs +++ b/CUETools.Codecs/CommandLine/AudioDecoder.cs @@ -1,112 +1,112 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace CUETools.Codecs -{ - public class CommandLineDecoder : IAudioSource - { - string _path; - Process _decoderProcess; - WAV.AudioDecoder rdr; - - private CommandLineDecoderSettings m_settings; - public AudioDecoderSettings Settings => m_settings; - - public long Position - { - get - { - Initialize(); - return rdr.Position; - } - set - { - Initialize(); - rdr.Position = value; - } - } - - public long Length - { - get - { - Initialize(); - return rdr.Length; - } - } - - public long Remaining - { - get - { - Initialize(); - return rdr.Remaining; - } - } - - public AudioPCMConfig PCM - { - get - { - Initialize(); - return rdr.PCM; - } - } - - public string Path { get { return _path; } } - - public CommandLineDecoder(CommandLineDecoderSettings settings, string path, Stream IO) - { - m_settings = settings; - _path = path; - _decoderProcess = null; - rdr = null; - } - - void Initialize() - { - if (_decoderProcess != null) - return; - _decoderProcess = new Process(); - _decoderProcess.StartInfo.FileName = m_settings.Path; - _decoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%I", "\"" + _path + "\""); - _decoderProcess.StartInfo.CreateNoWindow = true; - _decoderProcess.StartInfo.RedirectStandardOutput = true; - _decoderProcess.StartInfo.UseShellExecute = false; - bool started = false; - Exception ex = null; - try - { - started = _decoderProcess.Start(); - if (started) - _decoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; - } - catch (Exception _ex) - { - ex = _ex; - } - if (!started) - { - _decoderProcess = null; - throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); - } - rdr = new WAV.AudioDecoder(new WAV.DecoderSettings(), _path, _decoderProcess.StandardOutput.BaseStream); - } - - public void Close() - { - if (rdr != null) - rdr.Close(); - if (_decoderProcess != null && !_decoderProcess.HasExited) - try { _decoderProcess.Kill(); _decoderProcess.WaitForExit(); } - catch { } - } - - public int Read(AudioBuffer buff, int maxLength) - { - Initialize(); - return rdr.Read(buff, maxLength); - } - } -} +using System; +using System.Diagnostics; +using System.IO; + +namespace CUETools.Codecs.CommandLine +{ + public class AudioDecoder : IAudioSource + { + string _path; + Process _decoderProcess; + WAV.AudioDecoder rdr; + + private DecoderSettings m_settings; + public AudioDecoderSettings Settings => m_settings; + + public long Position + { + get + { + Initialize(); + return rdr.Position; + } + set + { + Initialize(); + rdr.Position = value; + } + } + + public long Length + { + get + { + Initialize(); + return rdr.Length; + } + } + + public long Remaining + { + get + { + Initialize(); + return rdr.Remaining; + } + } + + public AudioPCMConfig PCM + { + get + { + Initialize(); + return rdr.PCM; + } + } + + public string Path { get { return _path; } } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO) + { + m_settings = settings; + _path = path; + _decoderProcess = null; + rdr = null; + } + + void Initialize() + { + if (_decoderProcess != null) + return; + _decoderProcess = new Process(); + _decoderProcess.StartInfo.FileName = m_settings.Path; + _decoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%I", "\"" + _path + "\""); + _decoderProcess.StartInfo.CreateNoWindow = true; + _decoderProcess.StartInfo.RedirectStandardOutput = true; + _decoderProcess.StartInfo.UseShellExecute = false; + bool started = false; + Exception ex = null; + try + { + started = _decoderProcess.Start(); + if (started) + _decoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + { + _decoderProcess = null; + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + } + rdr = new WAV.AudioDecoder(new WAV.DecoderSettings(), _path, _decoderProcess.StandardOutput.BaseStream); + } + + public void Close() + { + if (rdr != null) + rdr.Close(); + if (_decoderProcess != null && !_decoderProcess.HasExited) + try { _decoderProcess.Kill(); _decoderProcess.WaitForExit(); } + catch { } + } + + public int Read(AudioBuffer buff, int maxLength) + { + Initialize(); + return rdr.Read(buff, maxLength); + } + } +} diff --git a/CUETools.Codecs/UserDefinedWriter.cs b/CUETools.Codecs/CommandLine/AudioEncoder.cs similarity index 92% rename from CUETools.Codecs/UserDefinedWriter.cs rename to CUETools.Codecs/CommandLine/AudioEncoder.cs index 9755215..a14e5d0 100644 --- a/CUETools.Codecs/UserDefinedWriter.cs +++ b/CUETools.Codecs/CommandLine/AudioEncoder.cs @@ -1,137 +1,137 @@ -using System; -using System.Diagnostics; -using System.IO; - -namespace CUETools.Codecs -{ - public class CommandLineEncoder : IAudioDest - { - string _path; - Process _encoderProcess; - WAV.AudioEncoder wrt; - CyclicBuffer outputBuffer = null; - bool useTempFile = false; - string tempFile = null; - long _finalSampleCount = -1; - bool closed = false; - - public long Position - { - get - { - return wrt.Position; - } - } - - public long FinalSampleCount - { - set { _finalSampleCount = wrt.FinalSampleCount = value; } - } - - // !!!! Must not start the process in constructor, so that we can set CompressionLevel via Settings! - private CommandLineEncoderSettings m_settings; - public AudioEncoderSettings Settings => m_settings; - - public string Path { get { return _path; } } - - public CommandLineEncoder(CommandLineEncoderSettings settings, string path, Stream IO = null) - { - m_settings = settings; - _path = path; - useTempFile = m_settings.Parameters.Contains("%I"); - tempFile = path + ".tmp.wav"; - - _encoderProcess = new Process(); - _encoderProcess.StartInfo.FileName = m_settings.Path; - _encoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%O", "\"" + path + "\"").Replace("%M", m_settings.EncoderMode).Replace("%P", m_settings.Padding.ToString()).Replace("%I", "\"" + tempFile + "\""); - _encoderProcess.StartInfo.CreateNoWindow = true; - if (!useTempFile) - _encoderProcess.StartInfo.RedirectStandardInput = true; - _encoderProcess.StartInfo.UseShellExecute = false; - if (!m_settings.Parameters.Contains("%O")) - _encoderProcess.StartInfo.RedirectStandardOutput = true; - if (useTempFile) - { - wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), tempFile); - return; - } - bool started = false; - Exception ex = null; - try - { - started = _encoderProcess.Start(); - if (started) - _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; - } - catch (Exception _ex) - { - ex = _ex; - } - if (!started) - throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); - if (_encoderProcess.StartInfo.RedirectStandardOutput) - { - Stream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); - outputBuffer = new CyclicBuffer(2 * 1024 * 1024, _encoderProcess.StandardOutput.BaseStream, outputStream); - } - Stream inputStream = new CyclicBufferOutputStream(_encoderProcess.StandardInput.BaseStream, 128 * 1024); - wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), path, inputStream); - } - - public void Close() - { - if (closed) - return; - closed = true; - wrt.Close(); - if (useTempFile && (_finalSampleCount < 0 || wrt.Position == _finalSampleCount)) - { - bool started = false; - Exception ex = null; - try - { - started = _encoderProcess.Start(); - if (started) - _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; - } - catch (Exception _ex) - { - ex = _ex; - } - if (!started) - throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); - } - wrt = null; - if (!_encoderProcess.HasExited) - _encoderProcess.WaitForExit(); - if (useTempFile) - File.Delete(tempFile); - if (outputBuffer != null) - outputBuffer.Close(); - if (_encoderProcess.ExitCode != 0) - throw new Exception(String.Format("{0} returned error code {1}", m_settings.Path, _encoderProcess.ExitCode)); - } - - public void Delete() - { - Close(); - File.Delete(_path); - } - - public void Write(AudioBuffer buff) - { - try - { - wrt.Write(buff); - } - catch (IOException ex) - { - if (_encoderProcess.HasExited) - throw new IOException(string.Format("{0} has exited prematurely with code {1}", m_settings.Path, _encoderProcess.ExitCode), ex); - else - throw ex; - } - //_sampleLen += sampleCount; - } - } -} +using System; +using System.Diagnostics; +using System.IO; + +namespace CUETools.Codecs.CommandLine +{ + public class AudioEncoder : IAudioDest + { + string _path; + Process _encoderProcess; + WAV.AudioEncoder wrt; + CyclicBuffer outputBuffer = null; + bool useTempFile = false; + string tempFile = null; + long _finalSampleCount = -1; + bool closed = false; + + public long Position + { + get + { + return wrt.Position; + } + } + + public long FinalSampleCount + { + set { _finalSampleCount = wrt.FinalSampleCount = value; } + } + + // !!!! Must not start the process in constructor, so that we can set CompressionLevel via Settings! + private EncoderSettings m_settings; + public AudioEncoderSettings Settings => m_settings; + + public string Path { get { return _path; } } + + public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + _path = path; + useTempFile = m_settings.Parameters.Contains("%I"); + tempFile = path + ".tmp.wav"; + + _encoderProcess = new Process(); + _encoderProcess.StartInfo.FileName = m_settings.Path; + _encoderProcess.StartInfo.Arguments = m_settings.Parameters.Replace("%O", "\"" + path + "\"").Replace("%M", m_settings.EncoderMode).Replace("%P", m_settings.Padding.ToString()).Replace("%I", "\"" + tempFile + "\""); + _encoderProcess.StartInfo.CreateNoWindow = true; + if (!useTempFile) + _encoderProcess.StartInfo.RedirectStandardInput = true; + _encoderProcess.StartInfo.UseShellExecute = false; + if (!m_settings.Parameters.Contains("%O")) + _encoderProcess.StartInfo.RedirectStandardOutput = true; + if (useTempFile) + { + wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), tempFile); + return; + } + bool started = false; + Exception ex = null; + try + { + started = _encoderProcess.Start(); + if (started) + _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + if (_encoderProcess.StartInfo.RedirectStandardOutput) + { + Stream outputStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); + outputBuffer = new CyclicBuffer(2 * 1024 * 1024, _encoderProcess.StandardOutput.BaseStream, outputStream); + } + Stream inputStream = new CyclicBufferOutputStream(_encoderProcess.StandardInput.BaseStream, 128 * 1024); + wrt = new WAV.AudioEncoder(new WAV.EncoderSettings(settings.PCM), path, inputStream); + } + + public void Close() + { + if (closed) + return; + closed = true; + wrt.Close(); + if (useTempFile && (_finalSampleCount < 0 || wrt.Position == _finalSampleCount)) + { + bool started = false; + Exception ex = null; + try + { + started = _encoderProcess.Start(); + if (started) + _encoderProcess.PriorityClass = Process.GetCurrentProcess().PriorityClass; + } + catch (Exception _ex) + { + ex = _ex; + } + if (!started) + throw new Exception(m_settings.Path + ": " + (ex == null ? "please check the path" : ex.Message)); + } + wrt = null; + if (!_encoderProcess.HasExited) + _encoderProcess.WaitForExit(); + if (useTempFile) + File.Delete(tempFile); + if (outputBuffer != null) + outputBuffer.Close(); + if (_encoderProcess.ExitCode != 0) + throw new Exception(String.Format("{0} returned error code {1}", m_settings.Path, _encoderProcess.ExitCode)); + } + + public void Delete() + { + Close(); + File.Delete(_path); + } + + public void Write(AudioBuffer buff) + { + try + { + wrt.Write(buff); + } + catch (IOException ex) + { + if (_encoderProcess.HasExited) + throw new IOException(string.Format("{0} has exited prematurely with code {1}", m_settings.Path, _encoderProcess.ExitCode), ex); + else + throw ex; + } + //_sampleLen += sampleCount; + } + } +} diff --git a/CUETools.Codecs/UserDefinedDecoderSettings.cs b/CUETools.Codecs/CommandLine/DecoderSettings.cs similarity index 84% rename from CUETools.Codecs/UserDefinedDecoderSettings.cs rename to CUETools.Codecs/CommandLine/DecoderSettings.cs index 12dfc05..14d58bf 100644 --- a/CUETools.Codecs/UserDefinedDecoderSettings.cs +++ b/CUETools.Codecs/CommandLine/DecoderSettings.cs @@ -4,21 +4,21 @@ using System.Text; using System.ComponentModel; using Newtonsoft.Json; -namespace CUETools.Codecs +namespace CUETools.Codecs.CommandLine { [JsonObject(MemberSerialization.OptIn)] - public class CommandLineDecoderSettings : AudioDecoderSettings + public class DecoderSettings : AudioDecoderSettings { public override string Name => name; public override string Extension => extension; - public CommandLineDecoderSettings() + public DecoderSettings() : base() { } - public CommandLineDecoderSettings( + public DecoderSettings( string _name, string _extension, string _path, diff --git a/CUETools.Codecs/UserDefinedEncoderSettings.cs b/CUETools.Codecs/CommandLine/EncoderSettings.cs similarity index 79% rename from CUETools.Codecs/UserDefinedEncoderSettings.cs rename to CUETools.Codecs/CommandLine/EncoderSettings.cs index 9c485a3..6950a27 100644 --- a/CUETools.Codecs/UserDefinedEncoderSettings.cs +++ b/CUETools.Codecs/CommandLine/EncoderSettings.cs @@ -1,63 +1,63 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.ComponentModel; -using Newtonsoft.Json; - -namespace CUETools.Codecs -{ - [JsonObject(MemberSerialization.OptIn)] - public class CommandLineEncoderSettings : AudioEncoderSettings - { - public override string Name => name; - - public override string Extension => extension; - - public override Type EncoderType => typeof(CommandLineEncoder); - - public override bool Lossless => lossless; - - public CommandLineEncoderSettings() - : base() - { - } - - [JsonProperty] - public string name; - - [JsonProperty] - public string extension; - - [JsonProperty] - public bool lossless; - - [DefaultValue(null)] - [JsonProperty] - public string Path - { - get; - set; - } - - [DefaultValue(null)] - [JsonProperty] - public string Parameters - { - get; - set; - } - - [JsonProperty] - public string SupportedModes - { - get - { - return m_supported_modes; - } - set - { - m_supported_modes = value; - } - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using Newtonsoft.Json; + +namespace CUETools.Codecs.CommandLine +{ + [JsonObject(MemberSerialization.OptIn)] + public class EncoderSettings : AudioEncoderSettings + { + public override string Name => name; + + public override string Extension => extension; + + public override Type EncoderType => typeof(AudioEncoder); + + public override bool Lossless => lossless; + + public EncoderSettings() + : base() + { + } + + [JsonProperty] + public string name; + + [JsonProperty] + public string extension; + + [JsonProperty] + public bool lossless; + + [DefaultValue(null)] + [JsonProperty] + public string Path + { + get; + set; + } + + [DefaultValue(null)] + [JsonProperty] + public string Parameters + { + get; + set; + } + + [JsonProperty] + public string SupportedModes + { + get + { + return m_supported_modes; + } + set + { + m_supported_modes = value; + } + } + } +} diff --git a/CUETools.Codecs/DummyWriter.cs b/CUETools.Codecs/DummyWriter.cs deleted file mode 100644 index 5bb91e6..0000000 --- a/CUETools.Codecs/DummyWriter.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -namespace CUETools.Codecs -{ - public class DummyWriter : IAudioDest - { - AudioEncoderSettings m_settings; - - public DummyWriter(string path, AudioEncoderSettings settings) - { - m_settings = settings; - } - - public void Close() - { - } - - public void Delete() - { - } - - public long FinalSampleCount - { - set { } - } - - public AudioEncoderSettings Settings - { - get - { - return m_settings; - } - } - - public void Write(AudioBuffer buff) - { - } - - public string Path { get { return null; } } - } -} diff --git a/CUETools.Codecs/SilenceGenerator.cs b/CUETools.Codecs/NULL/AudioDecoder.cs similarity index 83% rename from CUETools.Codecs/SilenceGenerator.cs rename to CUETools.Codecs/NULL/AudioDecoder.cs index 53999b3..2944c06 100644 --- a/CUETools.Codecs/SilenceGenerator.cs +++ b/CUETools.Codecs/NULL/AudioDecoder.cs @@ -1,61 +1,61 @@ -namespace CUETools.Codecs -{ - public class SilenceGenerator : IAudioSource - { - private long _sampleOffset, _sampleCount; - private AudioPCMConfig pcm; - private int _sampleVal; - - public AudioDecoderSettings Settings { get { return null; } } - - public long Length - { - get { return _sampleCount; } - } - - public long Remaining - { - get { return _sampleCount - _sampleOffset; } - } - - public long Position - { - get { return _sampleOffset; } - set { _sampleOffset = value; } - } - - public AudioPCMConfig PCM { get { return pcm; } } - - public string Path { get { return null; } } - - public SilenceGenerator(AudioPCMConfig pcm, long sampleCount, int sampleVal) - { - this._sampleVal = sampleVal; - this._sampleOffset = 0; - this._sampleCount = sampleCount; - this.pcm = pcm; - } - - public SilenceGenerator(long sampleCount) - : this(AudioPCMConfig.RedBook, sampleCount, 0) - { - } - - public int Read(AudioBuffer buff, int maxLength) - { - buff.Prepare(this, maxLength); - - int[,] samples = buff.Samples; - for (int i = 0; i < buff.Length; i++) - for (int j = 0; j < PCM.ChannelCount; j++) - samples[i, j] = _sampleVal; - - _sampleOffset += buff.Length; - return buff.Length; - } - - public void Close() - { - } - } -} +namespace CUETools.Codecs.NULL +{ + public class AudioDecoder : IAudioSource + { + private long _sampleOffset, _sampleCount; + private AudioPCMConfig pcm; + private int _sampleVal; + + public AudioDecoderSettings Settings { get { return null; } } + + public long Length + { + get { return _sampleCount; } + } + + public long Remaining + { + get { return _sampleCount - _sampleOffset; } + } + + public long Position + { + get { return _sampleOffset; } + set { _sampleOffset = value; } + } + + public AudioPCMConfig PCM { get { return pcm; } } + + public string Path { get { return null; } } + + public AudioDecoder(AudioPCMConfig pcm, long sampleCount, int sampleVal) + { + this._sampleVal = sampleVal; + this._sampleOffset = 0; + this._sampleCount = sampleCount; + this.pcm = pcm; + } + + public AudioDecoder(long sampleCount) + : this(AudioPCMConfig.RedBook, sampleCount, 0) + { + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + int[,] samples = buff.Samples; + for (int i = 0; i < buff.Length; i++) + for (int j = 0; j < PCM.ChannelCount; j++) + samples[i, j] = _sampleVal; + + _sampleOffset += buff.Length; + return buff.Length; + } + + public void Close() + { + } + } +} diff --git a/CUETools.Codecs/NULL/AudioEncoder.cs b/CUETools.Codecs/NULL/AudioEncoder.cs new file mode 100644 index 0000000..b4d3960 --- /dev/null +++ b/CUETools.Codecs/NULL/AudioEncoder.cs @@ -0,0 +1,35 @@ +using System; + +namespace CUETools.Codecs.NULL +{ + public class AudioEncoder : IAudioDest + { + AudioEncoderSettings m_settings; + + public AudioEncoder(string path, AudioEncoderSettings settings) + { + m_settings = settings; + } + + public void Close() + { + } + + public void Delete() + { + } + + public long FinalSampleCount + { + set { } + } + + public AudioEncoderSettings Settings => m_settings; + + public void Write(AudioBuffer buff) + { + } + + public string Path => null; + } +} diff --git a/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs b/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs new file mode 100644 index 0000000..ae99ed9 --- /dev/null +++ b/CUETools.Codecs/ViewModel/AudioDecoderSettingsViewModel.cs @@ -0,0 +1,112 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + [JsonObject(MemberSerialization.OptIn)] + public class AudioDecoderSettingsViewModel : INotifyPropertyChanged + { + [JsonProperty] + public AudioDecoderSettings decoderSettings = null; + + public event PropertyChangedEventHandler PropertyChanged; + + [JsonConstructor] + private AudioDecoderSettingsViewModel() + { + } + + public AudioDecoderSettingsViewModel(AudioDecoderSettings settings) + { + decoderSettings = settings; + } + + public AudioDecoderSettingsViewModel Clone() + { + var res = this.MemberwiseClone() as AudioDecoderSettingsViewModel; + if (decoderSettings != null) res.decoderSettings = decoderSettings.Clone(); + return res; + } + + public override string ToString() + { + return Name; + } + + public string FullName => Name + " [" + Extension + "]"; + + public string Path + { + get + { + if (decoderSettings is CommandLine.DecoderSettings) + return (decoderSettings as CommandLine.DecoderSettings).Path; + return ""; + } + set + { + if (decoderSettings is CommandLine.DecoderSettings) + (decoderSettings as CommandLine.DecoderSettings).Path = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); + } + } + public string Parameters + { + get + { + if (decoderSettings is CommandLine.DecoderSettings) + return (decoderSettings as CommandLine.DecoderSettings).Parameters; + return ""; + } + set + { + if (decoderSettings is CommandLine.DecoderSettings) + (decoderSettings as CommandLine.DecoderSettings).Parameters = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); + } + } + + public bool Lossless + { + get => true; + set { + throw new InvalidOperationException(); + } + } + + public string Name + { + get => decoderSettings.Name; + set + { + if (decoderSettings is CommandLine.DecoderSettings) + (decoderSettings as CommandLine.DecoderSettings).name = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); + } + } + + public string Extension + { + get => decoderSettings.Extension; + set + { + if (decoderSettings is CommandLine.DecoderSettings) + (decoderSettings as CommandLine.DecoderSettings).extension = value; + else throw new InvalidOperationException(); + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); + } + } + + public string DotExtension => "." + Extension; + + public bool CanBeDeleted => decoderSettings is CommandLine.DecoderSettings; + + public bool IsValid => + (decoderSettings != null) + && (decoderSettings is CommandLine.DecoderSettings ? (decoderSettings as CommandLine.DecoderSettings).Path != "" : true); + } +} diff --git a/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs b/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs new file mode 100644 index 0000000..1084efa --- /dev/null +++ b/CUETools.Codecs/ViewModel/AudioEncoderSettingsViewModel.cs @@ -0,0 +1,165 @@ +using Newtonsoft.Json; +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + [JsonObject(MemberSerialization.OptIn)] + public class AudioEncoderSettingsViewModel : INotifyPropertyChanged + { + [JsonProperty] + public AudioEncoderSettings settings = null; + + public event PropertyChangedEventHandler PropertyChanged; + + [JsonConstructor] + private AudioEncoderSettingsViewModel() + { + } + + public AudioEncoderSettingsViewModel( + string _name, + string _extension, + bool _lossless, + string _supported_modes, + string _default_mode, + string _path, + string _parameters + ) + { + settings = new CommandLine.EncoderSettings() { name = _name, extension = _extension, SupportedModes = _supported_modes, EncoderMode = _default_mode, Path = _path, Parameters = _parameters, lossless = _lossless }; + } + + public AudioEncoderSettingsViewModel(AudioEncoderClassAttribute enc) + { + settings = Activator.CreateInstance(enc.Settings) as AudioEncoderSettings; + if (settings == null) + throw new InvalidOperationException("invalid codec"); + } + + public AudioEncoderSettingsViewModel Clone() + { + var res = this.MemberwiseClone() as AudioEncoderSettingsViewModel; + if (settings != null) res.settings = settings.Clone(); + return res; + } + + public override string ToString() + { + return Name; + } + + public string FullName => Name + " [" + Extension + "]"; + + public string Path + { + get + { + if (settings is CommandLine.EncoderSettings) + return (settings as CommandLine.EncoderSettings).Path; + return ""; + } + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Path = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Path")); + } + } + + public string Parameters + { + get + { + if (settings is CommandLine.EncoderSettings) + return (settings as CommandLine.EncoderSettings).Parameters; + return ""; + } + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.Parameters = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Parameters")); + } + } + + public bool Lossless + { + get => settings.Lossless; + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.lossless = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Lossless")); + } + } + + + public string Name + { + get => settings.Name; + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.name = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); + } + } + + public string Extension + { + get => settings.Extension; + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.extension = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Extension")); + } + } + + public string DotExtension => "." + Extension; + + public string SupportedModesStr + { + get + { + string defaultMode; + return this.settings.GetSupportedModes(out defaultMode); + } + set + { + var settings = this.settings as CommandLine.EncoderSettings; + if (settings == null) throw new InvalidOperationException(); + settings.SupportedModes = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SupportedModesStr")); + } + } + + public string[] SupportedModes => this.SupportedModesStr.Split(' '); + + public int EncoderModeIndex + { + get + { + string[] modes = this.SupportedModes; + if (modes == null || modes.Length < 2) + return -1; + for (int i = 0; i < modes.Length; i++) + if (modes[i] == this.settings.EncoderMode) + return i; + return -1; + } + } + + public bool CanBeDeleted => settings is CommandLine.EncoderSettings; + + public bool IsValid => + (settings != null) + && (settings is CommandLine.EncoderSettings ? (settings as CommandLine.EncoderSettings).Path != "" : true); + } +} diff --git a/CUETools.Codecs/ViewModel/DecoderListViewModel.cs b/CUETools.Codecs/ViewModel/DecoderListViewModel.cs new file mode 100644 index 0000000..33cb9a0 --- /dev/null +++ b/CUETools.Codecs/ViewModel/DecoderListViewModel.cs @@ -0,0 +1,46 @@ +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + public class DecoderListViewModel : BindingList + { + public DecoderListViewModel() + : base() + { + AddingNew += OnAddingNew; + } + + private void OnAddingNew(object sender, AddingNewEventArgs e) + { + e.NewObject = new AudioDecoderSettingsViewModel(new CommandLine.DecoderSettings("new", "wav", "", "")); + } + + public bool TryGetValue(string extension, bool lossless, string name, out AudioDecoderSettingsViewModel result) + { + foreach (AudioDecoderSettingsViewModel udc in this) + { + if (udc.decoderSettings.Extension == extension && udc.decoderSettings.Lossless == lossless && udc.decoderSettings.Name == name) + { + result = udc; + return true; + } + } + result = null; + return false; + } + + public AudioDecoderSettingsViewModel GetDefault(string extension, bool lossless) + { + AudioDecoderSettingsViewModel result = null; + foreach (AudioDecoderSettingsViewModel udc in this) + { + if (udc.decoderSettings.Extension == extension && udc.decoderSettings.Lossless == lossless && (result == null || result.decoderSettings.Priority < udc.decoderSettings.Priority)) + { + result = udc; + } + } + return result; + } + } +} diff --git a/CUETools.Codecs/ViewModel/EncoderListViewModel.cs b/CUETools.Codecs/ViewModel/EncoderListViewModel.cs new file mode 100644 index 0000000..5aee9f7 --- /dev/null +++ b/CUETools.Codecs/ViewModel/EncoderListViewModel.cs @@ -0,0 +1,47 @@ +using System; +using System.ComponentModel; + +namespace CUETools.Codecs +{ + public class EncoderListViewModel : BindingList + { + public EncoderListViewModel() + : base() + { + AddingNew += OnAddingNew; + } + + private void OnAddingNew(object sender, AddingNewEventArgs e) + { + e.NewObject = new AudioEncoderSettingsViewModel("new", "wav", true, "", "", "", ""); + } + + public bool TryGetValue(string extension, bool lossless, string name, out AudioEncoderSettingsViewModel result) + { + //result = this.Where(udc => udc.settings.Extension == extension && udc.settings.Lossless == lossless && udc.settings.Name == name).First(); + foreach (AudioEncoderSettingsViewModel udc in this) + { + if (udc.settings.Extension == extension && udc.settings.Lossless == lossless && udc.settings.Name == name) + { + result = udc; + return true; + } + } + result = null; + return false; + } + + public AudioEncoderSettingsViewModel GetDefault(string extension, bool lossless) + { + AudioEncoderSettingsViewModel result = null; + foreach (AudioEncoderSettingsViewModel udc in this) + { + if (udc.settings.Extension == extension && udc.settings.Lossless == lossless && (result == null || result.settings.Priority < udc.settings.Priority)) + { + result = udc; + } + } + return result; + } + } +} diff --git a/CUETools.Codecs/WAVReader.cs b/CUETools.Codecs/WAV/AudioDecoder.cs similarity index 93% rename from CUETools.Codecs/WAVReader.cs rename to CUETools.Codecs/WAV/AudioDecoder.cs index 024dc7c..d0cdcd0 100644 --- a/CUETools.Codecs/WAVReader.cs +++ b/CUETools.Codecs/WAV/AudioDecoder.cs @@ -1,285 +1,270 @@ -using System; -using System.IO; - -namespace CUETools.Codecs.WAV -{ - public class DecoderSettings : AudioDecoderSettings - { - public override string Name => "cuetools"; - - public override string Extension => "wav"; - - public override Type DecoderType => typeof(AudioDecoder); - - public override int Priority => 2; - - public DecoderSettings() : base() {} - - public bool IgnoreChunkSizes; - } - - [AudioDecoderClass(typeof(DecoderSettings))] - public class AudioDecoder : IAudioSource - { - Stream _IO; - BinaryReader _br; - long _dataOffset, _samplePos, _sampleLen; - private AudioPCMConfig pcm; - long _dataLen; - bool _largeFile; - string _path; - - private DecoderSettings m_settings; - public AudioDecoderSettings Settings => m_settings; - - public long Position - { - get - { - return _samplePos; - } - set - { - long seekPos; - - if (_samplePos == value) - { - return; - } - - var oldSamplePos = _samplePos; - if (_sampleLen >= 0 && value > _sampleLen) - _samplePos = _sampleLen; - else - _samplePos = value; - - if (_IO.CanSeek || _samplePos < oldSamplePos) - { - seekPos = _dataOffset + _samplePos * PCM.BlockAlign; - _IO.Seek(seekPos, SeekOrigin.Begin); - } - else - { - int offs = (int)(_samplePos - oldSamplePos) * PCM.BlockAlign; - while (offs > 0) - { - int chunk = Math.Min(offs, 16536); - _br.ReadBytes(chunk); - offs -= chunk; - } - } - } - } - - public long Length - { - get - { - return _sampleLen; - } - } - - public long Remaining - { - get - { - return _sampleLen - _samplePos; - } - } - - public AudioPCMConfig PCM { get { return pcm; } } - - public string Path { get { return _path; } } - - public AudioDecoder(DecoderSettings settings, string path, Stream IO = null) - { - m_settings = settings; - _path = path; - _IO = IO ?? new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); - _br = new BinaryReader(_IO); - - ParseHeaders(); - - if (_dataLen < 0 || m_settings.IgnoreChunkSizes) - _sampleLen = -1; - else - _sampleLen = _dataLen / pcm.BlockAlign; - } - - public AudioDecoder(DecoderSettings settings, string path, Stream IO, AudioPCMConfig _pcm) - { - m_settings = settings; - _path = path; - _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); - _br = new BinaryReader(_IO); - - _largeFile = false; - _dataOffset = 0; - _samplePos = 0; - pcm = _pcm; - _dataLen = _IO.CanSeek ? _IO.Length : -1; - if (_dataLen < 0) - _sampleLen = -1; - else - { - _sampleLen = _dataLen / pcm.BlockAlign; - if ((_dataLen % pcm.BlockAlign) != 0) - throw new Exception("odd file size"); - } - } - - public static AudioBuffer ReadAllSamples(DecoderSettings settings, string path, Stream IO = null) - { - AudioDecoder reader = new AudioDecoder(settings, path, IO); - AudioBuffer buff = new AudioBuffer(reader, (int)reader.Length); - reader.Read(buff, -1); - if (reader.Remaining != 0) - throw new Exception("couldn't read the whole file"); - reader.Close(); - return buff; - } - - public void Close() - { - if (_br != null) - { - _br.Close(); - _br = null; - } - _IO = null; - } - - private void ParseHeaders() - { - const long maxFileSize = 0x7FFFFFFEL; - const uint fccRIFF = 0x46464952; - const uint fccWAVE = 0x45564157; - const uint fccFormat = 0x20746D66; - const uint fccData = 0x61746164; - - uint lenRIFF; - bool foundFormat, foundData; - - if (_br.ReadUInt32() != fccRIFF) - { - throw new Exception("Not a valid RIFF file."); - } - - lenRIFF = _br.ReadUInt32(); - - if (_br.ReadUInt32() != fccWAVE) - { - throw new Exception("Not a valid WAVE file."); - } - - _largeFile = false; - foundFormat = false; - foundData = false; - long pos = 12; - do - { - uint ckID, ckSize, ckSizePadded; - long ckEnd; - - ckID = _br.ReadUInt32(); - ckSize = _br.ReadUInt32(); - ckSizePadded = (ckSize + 1U) & ~1U; - pos += 8; - ckEnd = pos + (long)ckSizePadded; - - if (ckID == fccFormat) - { - foundFormat = true; - - uint fmtTag = _br.ReadUInt16(); - int _channelCount = _br.ReadInt16(); - int _sampleRate = _br.ReadInt32(); - _br.ReadInt32(); // bytes per second - int _blockAlign = _br.ReadInt16(); - int _bitsPerSample = _br.ReadInt16(); - int _channelMask = 0; - pos += 16; - - if (fmtTag == 0xFFFEU && ckSize >= 34) // WAVE_FORMAT_EXTENSIBLE - { - _br.ReadInt16(); // CbSize - _br.ReadInt16(); // ValidBitsPerSample - _channelMask = _br.ReadInt32(); - fmtTag = _br.ReadUInt16(); - pos += 10; - } - - if (fmtTag != 1) // WAVE_FORMAT_PCM - throw new Exception("WAVE format tag not WAVE_FORMAT_PCM."); - - pcm = new AudioPCMConfig(_bitsPerSample, _channelCount, _sampleRate, (AudioPCMConfig.SpeakerConfig)_channelMask); - if (pcm.BlockAlign != _blockAlign) - throw new Exception("WAVE has strange BlockAlign"); - } - else if (ckID == fccData) - { - foundData = true; - - _dataOffset = pos; - if (!_IO.CanSeek || _IO.Length <= maxFileSize) - { - if (ckSize == 0 || ckSize >= 0x7fffffff) - _dataLen = -1; - else - _dataLen = (long)ckSize; - } - else - { - _largeFile = true; - _dataLen = _IO.Length - pos; - } - } - - if ((foundFormat & foundData) || _largeFile) - break; - if (_IO.CanSeek) - _IO.Seek(ckEnd, SeekOrigin.Begin); - else - _br.ReadBytes((int)(ckEnd - pos)); - pos = ckEnd; - } while (true); - - if ((foundFormat & foundData) == false || pcm == null) - throw new Exception("Format or data chunk not found."); - if (pcm.ChannelCount <= 0) - throw new Exception("Channel count is invalid."); - if (pcm.SampleRate <= 0) - throw new Exception("Sample rate is invalid."); - if ((pcm.BitsPerSample <= 0) || (pcm.BitsPerSample > 32)) - throw new Exception("Bits per sample is invalid."); - if (pos != _dataOffset) - Position = 0; - } - - public int Read(AudioBuffer buff, int maxLength) - { - buff.Prepare(this, maxLength); - - byte[] bytes = buff.Bytes; - int byteCount = (int)buff.ByteLength; - int pos = 0; - - while (pos < byteCount) - { - int len = _IO.Read(bytes, pos, byteCount - pos); - if (len <= 0) - { - if ((pos % PCM.BlockAlign) != 0 || _sampleLen >= 0) - throw new Exception("Incomplete file read."); - buff.Length = pos / PCM.BlockAlign; - _samplePos += buff.Length; - _sampleLen = _samplePos; - return buff.Length; - } - pos += len; - } - _samplePos += buff.Length; - return buff.Length; - } - } -} +using System; +using System.IO; + +namespace CUETools.Codecs.WAV +{ + [AudioDecoderClass(typeof(DecoderSettings))] + public class AudioDecoder : IAudioSource + { + Stream _IO; + BinaryReader _br; + long _dataOffset, _samplePos, _sampleLen; + private AudioPCMConfig pcm; + long _dataLen; + bool _largeFile; + string _path; + + private DecoderSettings m_settings; + public AudioDecoderSettings Settings => m_settings; + + public long Position + { + get + { + return _samplePos; + } + set + { + long seekPos; + + if (_samplePos == value) + { + return; + } + + var oldSamplePos = _samplePos; + if (_sampleLen >= 0 && value > _sampleLen) + _samplePos = _sampleLen; + else + _samplePos = value; + + if (_IO.CanSeek || _samplePos < oldSamplePos) + { + seekPos = _dataOffset + _samplePos * PCM.BlockAlign; + _IO.Seek(seekPos, SeekOrigin.Begin); + } + else + { + int offs = (int)(_samplePos - oldSamplePos) * PCM.BlockAlign; + while (offs > 0) + { + int chunk = Math.Min(offs, 16536); + _br.ReadBytes(chunk); + offs -= chunk; + } + } + } + } + + public long Length + { + get + { + return _sampleLen; + } + } + + public long Remaining + { + get + { + return _sampleLen - _samplePos; + } + } + + public AudioPCMConfig PCM { get { return pcm; } } + + public string Path { get { return _path; } } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + _path = path; + _IO = IO ?? new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); + _br = new BinaryReader(_IO); + + ParseHeaders(); + + if (_dataLen < 0 || m_settings.IgnoreChunkSizes) + _sampleLen = -1; + else + _sampleLen = _dataLen / pcm.BlockAlign; + } + + public AudioDecoder(DecoderSettings settings, string path, Stream IO, AudioPCMConfig _pcm) + { + m_settings = settings; + _path = path; + _IO = IO != null ? IO : new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, 0x10000, FileOptions.SequentialScan); + _br = new BinaryReader(_IO); + + _largeFile = false; + _dataOffset = 0; + _samplePos = 0; + pcm = _pcm; + _dataLen = _IO.CanSeek ? _IO.Length : -1; + if (_dataLen < 0) + _sampleLen = -1; + else + { + _sampleLen = _dataLen / pcm.BlockAlign; + if ((_dataLen % pcm.BlockAlign) != 0) + throw new Exception("odd file size"); + } + } + + public static AudioBuffer ReadAllSamples(DecoderSettings settings, string path, Stream IO = null) + { + AudioDecoder reader = new AudioDecoder(settings, path, IO); + AudioBuffer buff = new AudioBuffer(reader, (int)reader.Length); + reader.Read(buff, -1); + if (reader.Remaining != 0) + throw new Exception("couldn't read the whole file"); + reader.Close(); + return buff; + } + + public void Close() + { + if (_br != null) + { + _br.Close(); + _br = null; + } + _IO = null; + } + + private void ParseHeaders() + { + const long maxFileSize = 0x7FFFFFFEL; + const uint fccRIFF = 0x46464952; + const uint fccWAVE = 0x45564157; + const uint fccFormat = 0x20746D66; + const uint fccData = 0x61746164; + + uint lenRIFF; + bool foundFormat, foundData; + + if (_br.ReadUInt32() != fccRIFF) + { + throw new Exception("Not a valid RIFF file."); + } + + lenRIFF = _br.ReadUInt32(); + + if (_br.ReadUInt32() != fccWAVE) + { + throw new Exception("Not a valid WAVE file."); + } + + _largeFile = false; + foundFormat = false; + foundData = false; + long pos = 12; + do + { + uint ckID, ckSize, ckSizePadded; + long ckEnd; + + ckID = _br.ReadUInt32(); + ckSize = _br.ReadUInt32(); + ckSizePadded = (ckSize + 1U) & ~1U; + pos += 8; + ckEnd = pos + (long)ckSizePadded; + + if (ckID == fccFormat) + { + foundFormat = true; + + uint fmtTag = _br.ReadUInt16(); + int _channelCount = _br.ReadInt16(); + int _sampleRate = _br.ReadInt32(); + _br.ReadInt32(); // bytes per second + int _blockAlign = _br.ReadInt16(); + int _bitsPerSample = _br.ReadInt16(); + int _channelMask = 0; + pos += 16; + + if (fmtTag == 0xFFFEU && ckSize >= 34) // WAVE_FORMAT_EXTENSIBLE + { + _br.ReadInt16(); // CbSize + _br.ReadInt16(); // ValidBitsPerSample + _channelMask = _br.ReadInt32(); + fmtTag = _br.ReadUInt16(); + pos += 10; + } + + if (fmtTag != 1) // WAVE_FORMAT_PCM + throw new Exception("WAVE format tag not WAVE_FORMAT_PCM."); + + pcm = new AudioPCMConfig(_bitsPerSample, _channelCount, _sampleRate, (AudioPCMConfig.SpeakerConfig)_channelMask); + if (pcm.BlockAlign != _blockAlign) + throw new Exception("WAVE has strange BlockAlign"); + } + else if (ckID == fccData) + { + foundData = true; + + _dataOffset = pos; + if (!_IO.CanSeek || _IO.Length <= maxFileSize) + { + if (ckSize == 0 || ckSize >= 0x7fffffff) + _dataLen = -1; + else + _dataLen = (long)ckSize; + } + else + { + _largeFile = true; + _dataLen = _IO.Length - pos; + } + } + + if ((foundFormat & foundData) || _largeFile) + break; + if (_IO.CanSeek) + _IO.Seek(ckEnd, SeekOrigin.Begin); + else + _br.ReadBytes((int)(ckEnd - pos)); + pos = ckEnd; + } while (true); + + if ((foundFormat & foundData) == false || pcm == null) + throw new Exception("Format or data chunk not found."); + if (pcm.ChannelCount <= 0) + throw new Exception("Channel count is invalid."); + if (pcm.SampleRate <= 0) + throw new Exception("Sample rate is invalid."); + if ((pcm.BitsPerSample <= 0) || (pcm.BitsPerSample > 32)) + throw new Exception("Bits per sample is invalid."); + if (pos != _dataOffset) + Position = 0; + } + + public int Read(AudioBuffer buff, int maxLength) + { + buff.Prepare(this, maxLength); + + byte[] bytes = buff.Bytes; + int byteCount = (int)buff.ByteLength; + int pos = 0; + + while (pos < byteCount) + { + int len = _IO.Read(bytes, pos, byteCount - pos); + if (len <= 0) + { + if ((pos % PCM.BlockAlign) != 0 || _sampleLen >= 0) + throw new Exception("Incomplete file read."); + buff.Length = pos / PCM.BlockAlign; + _samplePos += buff.Length; + _sampleLen = _samplePos; + return buff.Length; + } + pos += len; + } + _samplePos += buff.Length; + return buff.Length; + } + } +} diff --git a/CUETools.Codecs/WAVWriter.cs b/CUETools.Codecs/WAV/AudioEncoder.cs similarity index 97% rename from CUETools.Codecs/WAVWriter.cs rename to CUETools.Codecs/WAV/AudioEncoder.cs index 46fd17f..c3f0685 100644 --- a/CUETools.Codecs/WAVWriter.cs +++ b/CUETools.Codecs/WAV/AudioEncoder.cs @@ -1,181 +1,181 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace CUETools.Codecs.WAV -{ - [AudioEncoderClass(typeof(EncoderSettings))] - public class AudioEncoder : IAudioDest - { - private Stream _IO; - private BinaryWriter _bw; - private long _sampleLen; - private string _path; - private long hdrLen = 0; - private bool _headersWritten = false; - private long _finalSampleCount = -1; - private List _chunks = null; - private List _chunkFCCs = null; - - public long Position - { - get - { - return _sampleLen; - } - } - - public long FinalSampleCount - { - set { _finalSampleCount = value; } - } - - private EncoderSettings m_settings; - public AudioEncoderSettings Settings => m_settings; - - public string Path { get { return _path; } } - - public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) - { - m_settings = settings; - _path = path; - _IO = IO ?? new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); - _bw = new BinaryWriter(_IO); - } - - public void WriteChunk(uint fcc, byte[] data) - { - if (_sampleLen > 0) - throw new Exception("data already written, no chunks allowed"); - if (_chunks == null) - { - _chunks = new List(); - _chunkFCCs = new List(); - } - _chunkFCCs.Add(fcc); - _chunks.Add(data); - hdrLen += 8 + data.Length + (data.Length & 1); - } - - private void WriteHeaders() - { - const uint fccRIFF = 0x46464952; - const uint fccWAVE = 0x45564157; - const uint fccFormat = 0x20746D66; - const uint fccData = 0x61746164; - - bool wavex = (Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24) || Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount); - - hdrLen += 36 + (wavex ? 24 : 0) + 8; - - uint dataLen = (uint)(_finalSampleCount * Settings.PCM.BlockAlign); - uint dataLenPadded = dataLen + (dataLen & 1); - - _bw.Write(fccRIFF); - if (_finalSampleCount <= 0) - _bw.Write((uint)0xffffffff); - else - _bw.Write((uint)(dataLenPadded + hdrLen - 8)); - _bw.Write(fccWAVE); - _bw.Write(fccFormat); - if (wavex) - { - _bw.Write((uint)40); - _bw.Write((ushort)0xfffe); // WAVEX follows - } - else - { - _bw.Write((uint)16); - _bw.Write((ushort)1); // PCM - } - _bw.Write((ushort)Settings.PCM.ChannelCount); - _bw.Write((uint)Settings.PCM.SampleRate); - _bw.Write((uint)(Settings.PCM.SampleRate * Settings.PCM.BlockAlign)); - _bw.Write((ushort)Settings.PCM.BlockAlign); - _bw.Write((ushort)((Settings.PCM.BitsPerSample + 7) / 8 * 8)); - if (wavex) - { - _bw.Write((ushort)22); // length of WAVEX structure - _bw.Write((ushort)Settings.PCM.BitsPerSample); - _bw.Write((uint)Settings.PCM.ChannelMask); - _bw.Write((ushort)1); // PCM Guid - _bw.Write((ushort)0); - _bw.Write((ushort)0); - _bw.Write((ushort)0x10); - _bw.Write((byte)0x80); - _bw.Write((byte)0x00); - _bw.Write((byte)0x00); - _bw.Write((byte)0xaa); - _bw.Write((byte)0x00); - _bw.Write((byte)0x38); - _bw.Write((byte)0x9b); - _bw.Write((byte)0x71); - } - if (_chunks != null) - for (int i = 0; i < _chunks.Count; i++) - { - _bw.Write(_chunkFCCs[i]); - _bw.Write((uint)_chunks[i].Length); - _bw.Write(_chunks[i]); - if ((_chunks[i].Length & 1) != 0) - _bw.Write((byte)0); - } - - _bw.Write(fccData); - if (_finalSampleCount <= 0) - _bw.Write((uint)0xffffffff); - else - _bw.Write(dataLen); - - _headersWritten = true; - } - - public void Close() - { - if (_finalSampleCount <= 0 && _IO.CanSeek) - { - long dataLen = _sampleLen * Settings.PCM.BlockAlign; - long dataLenPadded = dataLen + (dataLen & 1); - if (dataLenPadded + hdrLen - 8 < 0xffffffff) - { - if ((dataLen & 1) == 1) - _bw.Write((byte)0); - - _bw.Seek(4, SeekOrigin.Begin); - _bw.Write((uint)(dataLenPadded + hdrLen - 8)); - - _bw.Seek((int)hdrLen - 4, SeekOrigin.Begin); - _bw.Write((uint)dataLen); - } - } - - _bw.Close(); - - _bw = null; - _IO = null; - - if (_finalSampleCount > 0 && _sampleLen != _finalSampleCount) - throw new Exception("Samples written differs from the expected sample count."); - } - - public void Delete() - { - _bw.Close(); - _bw = null; - _IO = null; - if (_path != "") - File.Delete(_path); - } - - public void Write(AudioBuffer buff) - { - if (buff.Length == 0) - return; - buff.Prepare(this); - if (!_headersWritten) - WriteHeaders(); - _IO.Write(buff.Bytes, 0, buff.ByteLength); - _sampleLen += buff.Length; - } - } -} +using System; +using System.Collections.Generic; +using System.IO; + +namespace CUETools.Codecs.WAV +{ + [AudioEncoderClass(typeof(EncoderSettings))] + public class AudioEncoder : IAudioDest + { + private Stream _IO; + private BinaryWriter _bw; + private long _sampleLen; + private string _path; + private long hdrLen = 0; + private bool _headersWritten = false; + private long _finalSampleCount = -1; + private List _chunks = null; + private List _chunkFCCs = null; + + public long Position + { + get + { + return _sampleLen; + } + } + + public long FinalSampleCount + { + set { _finalSampleCount = value; } + } + + private EncoderSettings m_settings; + public AudioEncoderSettings Settings => m_settings; + + public string Path { get { return _path; } } + + public AudioEncoder(EncoderSettings settings, string path, Stream IO = null) + { + m_settings = settings; + _path = path; + _IO = IO ?? new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read); + _bw = new BinaryWriter(_IO); + } + + public void WriteChunk(uint fcc, byte[] data) + { + if (_sampleLen > 0) + throw new Exception("data already written, no chunks allowed"); + if (_chunks == null) + { + _chunks = new List(); + _chunkFCCs = new List(); + } + _chunkFCCs.Add(fcc); + _chunks.Add(data); + hdrLen += 8 + data.Length + (data.Length & 1); + } + + private void WriteHeaders() + { + const uint fccRIFF = 0x46464952; + const uint fccWAVE = 0x45564157; + const uint fccFormat = 0x20746D66; + const uint fccData = 0x61746164; + + bool wavex = (Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24) || Settings.PCM.ChannelMask != AudioPCMConfig.GetDefaultChannelMask(Settings.PCM.ChannelCount); + + hdrLen += 36 + (wavex ? 24 : 0) + 8; + + uint dataLen = (uint)(_finalSampleCount * Settings.PCM.BlockAlign); + uint dataLenPadded = dataLen + (dataLen & 1); + + _bw.Write(fccRIFF); + if (_finalSampleCount <= 0) + _bw.Write((uint)0xffffffff); + else + _bw.Write((uint)(dataLenPadded + hdrLen - 8)); + _bw.Write(fccWAVE); + _bw.Write(fccFormat); + if (wavex) + { + _bw.Write((uint)40); + _bw.Write((ushort)0xfffe); // WAVEX follows + } + else + { + _bw.Write((uint)16); + _bw.Write((ushort)1); // PCM + } + _bw.Write((ushort)Settings.PCM.ChannelCount); + _bw.Write((uint)Settings.PCM.SampleRate); + _bw.Write((uint)(Settings.PCM.SampleRate * Settings.PCM.BlockAlign)); + _bw.Write((ushort)Settings.PCM.BlockAlign); + _bw.Write((ushort)((Settings.PCM.BitsPerSample + 7) / 8 * 8)); + if (wavex) + { + _bw.Write((ushort)22); // length of WAVEX structure + _bw.Write((ushort)Settings.PCM.BitsPerSample); + _bw.Write((uint)Settings.PCM.ChannelMask); + _bw.Write((ushort)1); // PCM Guid + _bw.Write((ushort)0); + _bw.Write((ushort)0); + _bw.Write((ushort)0x10); + _bw.Write((byte)0x80); + _bw.Write((byte)0x00); + _bw.Write((byte)0x00); + _bw.Write((byte)0xaa); + _bw.Write((byte)0x00); + _bw.Write((byte)0x38); + _bw.Write((byte)0x9b); + _bw.Write((byte)0x71); + } + if (_chunks != null) + for (int i = 0; i < _chunks.Count; i++) + { + _bw.Write(_chunkFCCs[i]); + _bw.Write((uint)_chunks[i].Length); + _bw.Write(_chunks[i]); + if ((_chunks[i].Length & 1) != 0) + _bw.Write((byte)0); + } + + _bw.Write(fccData); + if (_finalSampleCount <= 0) + _bw.Write((uint)0xffffffff); + else + _bw.Write(dataLen); + + _headersWritten = true; + } + + public void Close() + { + if (_finalSampleCount <= 0 && _IO.CanSeek) + { + long dataLen = _sampleLen * Settings.PCM.BlockAlign; + long dataLenPadded = dataLen + (dataLen & 1); + if (dataLenPadded + hdrLen - 8 < 0xffffffff) + { + if ((dataLen & 1) == 1) + _bw.Write((byte)0); + + _bw.Seek(4, SeekOrigin.Begin); + _bw.Write((uint)(dataLenPadded + hdrLen - 8)); + + _bw.Seek((int)hdrLen - 4, SeekOrigin.Begin); + _bw.Write((uint)dataLen); + } + } + + _bw.Close(); + + _bw = null; + _IO = null; + + if (_finalSampleCount > 0 && _sampleLen != _finalSampleCount) + throw new Exception("Samples written differs from the expected sample count."); + } + + public void Delete() + { + _bw.Close(); + _bw = null; + _IO = null; + if (_path != "") + File.Delete(_path); + } + + public void Write(AudioBuffer buff) + { + if (buff.Length == 0) + return; + buff.Prepare(this); + if (!_headersWritten) + WriteHeaders(); + _IO.Write(buff.Bytes, 0, buff.ByteLength); + _sampleLen += buff.Length; + } + } +} diff --git a/CUETools.Codecs/WAV/DecoderSettings.cs b/CUETools.Codecs/WAV/DecoderSettings.cs new file mode 100644 index 0000000..fd5af34 --- /dev/null +++ b/CUETools.Codecs/WAV/DecoderSettings.cs @@ -0,0 +1,19 @@ +using System; + +namespace CUETools.Codecs.WAV +{ + public class DecoderSettings : AudioDecoderSettings + { + public override string Name => "cuetools"; + + public override string Extension => "wav"; + + public override Type DecoderType => typeof(AudioDecoder); + + public override int Priority => 2; + + public DecoderSettings() : base() { } + + public bool IgnoreChunkSizes; + } +} diff --git a/CUETools.Codecs/WAVWriterSettings.cs b/CUETools.Codecs/WAV/EncoderSettings.cs similarity index 95% rename from CUETools.Codecs/WAVWriterSettings.cs rename to CUETools.Codecs/WAV/EncoderSettings.cs index 05eba21..f9661ad 100644 --- a/CUETools.Codecs/WAVWriterSettings.cs +++ b/CUETools.Codecs/WAV/EncoderSettings.cs @@ -1,29 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace CUETools.Codecs.WAV -{ - public class EncoderSettings : AudioEncoderSettings - { - public override string Extension => "wav"; - - public override string Name => "cuetools"; - - public override Type EncoderType => typeof(WAV.AudioEncoder); - - public override int Priority => 10; - - public override bool Lossless => true; - - public EncoderSettings() - : this(null) - { - } - - public EncoderSettings(AudioPCMConfig pcm) - : base(pcm) - { - } - } -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace CUETools.Codecs.WAV +{ + public class EncoderSettings : AudioEncoderSettings + { + public override string Extension => "wav"; + + public override string Name => "cuetools"; + + public override Type EncoderType => typeof(WAV.AudioEncoder); + + public override int Priority => 10; + + public override bool Lossless => true; + + public EncoderSettings() + : this(null) + { + } + + public EncoderSettings(AudioPCMConfig pcm) + : base(pcm) + { + } + } +} diff --git a/CUETools.FLACCL.cmd/Program.cs b/CUETools.FLACCL.cmd/Program.cs index d6a2a9f..96781ee 100644 --- a/CUETools.FLACCL.cmd/Program.cs +++ b/CUETools.FLACCL.cmd/Program.cs @@ -244,7 +244,7 @@ namespace CUETools.FLACCL.cmd if (input_file == "-") audioSource = new Codecs.WAV.AudioDecoder(new Codecs.WAV.DecoderSettings() { IgnoreChunkSizes = true }, "", Console.OpenStandardInput()); else if (input_file == "nul") - audioSource = new SilenceGenerator(new AudioPCMConfig(input_bps, input_ch, input_rate), input_len, input_val); + audioSource = new Codecs.NULL.AudioDecoder(new AudioPCMConfig(input_bps, input_ch, input_rate), input_len, input_val); else if (File.Exists(input_file) && Path.GetExtension(input_file) == ".wav") audioSource = new Codecs.WAV.AudioDecoder(new Codecs.WAV.DecoderSettings(), input_file); else if (File.Exists(input_file) && Path.GetExtension(input_file) == ".flac") diff --git a/CUETools.Processor/AudioReadWrite.cs b/CUETools.Processor/AudioReadWrite.cs index 7e4fc64..aa730aa 100644 --- a/CUETools.Processor/AudioReadWrite.cs +++ b/CUETools.Processor/AudioReadWrite.cs @@ -15,7 +15,7 @@ namespace CUETools.Processor long len; if (!long.TryParse(slen, out len)) len = CDImageLayout.TimeFromString(slen) * 588; - return new SilenceGenerator(len); + return new Codecs.NULL.AudioDecoder(len); } } if (extension == ".bin") @@ -51,7 +51,7 @@ namespace CUETools.Processor { IAudioDest dest; if (audioEncoderType == AudioEncoderType.NoAudio || extension == ".dummy") - return new DummyWriter(path, new AudioEncoderSettings(pcm)) { FinalSampleCount = finalSampleCount }; + return new Codecs.NULL.AudioEncoder(path, new AudioEncoderSettings(pcm)) { FinalSampleCount = finalSampleCount }; CUEToolsFormat fmt; if (!extension.StartsWith(".") || !config.formats.TryGetValue(extension.Substring(1), out fmt)) throw new Exception("Unsupported audio type: " + path); diff --git a/CUETools.Processor/CUEConfig.cs b/CUETools.Processor/CUEConfig.cs index 9b8a984..4a63698 100644 --- a/CUETools.Processor/CUEConfig.cs +++ b/CUETools.Processor/CUEConfig.cs @@ -71,8 +71,8 @@ namespace CUETools.Processor public bool CopyAlbumArt { get; set; } public string ArLogFilenameFormat { get; set; } public string AlArtFilenameFormat { get; set; } - public CUEToolsUDCEncoderList Encoders => encoders; - public CUEToolsUDCDecoderList Decoders => decoders; + public EncoderListViewModel Encoders => encoders; + public DecoderListViewModel Decoders => decoders; public CUEConfig() : base(CUEProcessorPlugins.encs, CUEProcessorPlugins.decs) @@ -312,9 +312,9 @@ namespace CUETools.Processor int nDecoders = 0; foreach (var decoder in decoders) - if (decoder.decoderSettings is CommandLineDecoderSettings) + if (decoder.decoderSettings is Codecs.CommandLine.DecoderSettings) { - var settings = decoder.decoderSettings as CommandLineDecoderSettings; + var settings = decoder.decoderSettings as Codecs.CommandLine.DecoderSettings; sw.Save(string.Format("ExternalDecoder{0}Name", nDecoders), settings.Name); sw.Save(string.Format("ExternalDecoder{0}Extension", nDecoders), settings.Extension); sw.Save(string.Format("ExternalDecoder{0}Path", nDecoders), settings.Path); @@ -434,14 +434,14 @@ namespace CUETools.Processor try { var jsonObject = JsonConvert.DeserializeObject(sr.Load("Encoders"), - typeof(CUEToolsUDCEncoderList), + typeof(EncoderListViewModel), new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, TypeNameHandling = TypeNameHandling.Auto }); - if (jsonObject as CUEToolsUDCEncoderList == null) + if (jsonObject as EncoderListViewModel == null) throw new Exception(); - encoders = jsonObject as CUEToolsUDCEncoderList; + encoders = jsonObject as EncoderListViewModel; encoders.Where(x => !x.IsValid).ToList().ForEach(x => encoders.Remove(x)); AudioEncoderSettingsViewModel tmp; encodersBackup.Where(x => !encoders.TryGetValue(x.Extension, x.Lossless, x.Name, out tmp)).ToList().ForEach(x => encoders.Add(x)); @@ -503,7 +503,7 @@ namespace CUETools.Processor string parameters = sr.Load(string.Format("ExternalDecoder{0}Parameters", nDecoders)); AudioDecoderSettingsViewModel decoder; if (!decoders.TryGetValue(extension, true, name, out decoder)) - decoders.Add(new AudioDecoderSettingsViewModel(new CommandLineDecoderSettings(name, extension, path, parameters))); + decoders.Add(new AudioDecoderSettingsViewModel(new Codecs.CommandLine.DecoderSettings(name, extension, path, parameters))); else { decoder.Extension = extension; diff --git a/CUETools.Processor/CUESheet.cs b/CUETools.Processor/CUESheet.cs index 61df6d8..482f941 100644 --- a/CUETools.Processor/CUESheet.cs +++ b/CUETools.Processor/CUESheet.cs @@ -3972,7 +3972,7 @@ namespace CUETools.Processor if (sourceInfo.Path == null) { - audioSource = new SilenceGenerator(sourceInfo.Offset + sourceInfo.Length); + audioSource = new Codecs.NULL.AudioDecoder(sourceInfo.Offset + sourceInfo.Length); } else {