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.

This commit is contained in:
Grigory Chudov
2018-03-23 20:26:28 -04:00
parent 16fccfe5c9
commit ca8bb2fff6
22 changed files with 1301 additions and 1292 deletions

View File

@@ -12,15 +12,15 @@ namespace CUETools.Codecs
public class CUEToolsCodecsConfig
{
public Dictionary<string, CUEToolsFormat> 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<string, CUEToolsFormat>();
@@ -30,7 +30,7 @@ namespace CUETools.Codecs
public CUEToolsCodecsConfig(List<Type> encs, List<Type> 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
{

View File

@@ -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);
}
}

View File

@@ -1,88 +0,0 @@
using System;
using System.ComponentModel;
namespace CUETools.Codecs
{
public class CUEToolsUDCEncoderList : BindingList<AudioEncoderSettingsViewModel>
{
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<AudioDecoderSettingsViewModel>
{
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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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,

View File

@@ -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;
}
}
}
}

View File

@@ -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; } }
}
}

View File

@@ -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()
{
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.ComponentModel;
namespace CUETools.Codecs
{
public class DecoderListViewModel : BindingList<AudioDecoderSettingsViewModel>
{
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;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.ComponentModel;
namespace CUETools.Codecs
{
public class EncoderListViewModel : BindingList<AudioEncoderSettingsViewModel>
{
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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<byte[]> _chunks = null;
private List<uint> _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<byte[]>();
_chunkFCCs = new List<uint>();
}
_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<byte[]> _chunks = null;
private List<uint> _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<byte[]>();
_chunkFCCs = new List<uint>();
}
_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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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)
{
}
}
}

View File

@@ -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")

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
{