diff --git a/CUETools.ALACEnc/Program.cs b/CUETools.ALACEnc/Program.cs index f676d07..005542a 100644 --- a/CUETools.ALACEnc/Program.cs +++ b/CUETools.ALACEnc/Program.cs @@ -187,7 +187,6 @@ namespace CUETools.ALACEnc try { - settings.Validate(); if (stereo_method != null) alac.StereoMethod = Alac.LookupStereoMethod(stereo_method); if (order_method != null) diff --git a/CUETools.Codecs.ALAC/ALACWriter.cs b/CUETools.Codecs.ALAC/ALACWriter.cs index 2787ccb..c572287 100644 --- a/CUETools.Codecs.ALAC/ALACWriter.cs +++ b/CUETools.Codecs.ALAC/ALACWriter.cs @@ -40,10 +40,12 @@ namespace CUETools.Codecs.ALAC { } - public override bool IsValid() + public void Validate() { - return EncoderModeIndex >= 0 && Padding >= 0 && - (BlockSize == 0 || BlockSize >= 256 && BlockSize < Int32.MaxValue); + if (EncoderModeIndex < 0 + || Padding < 0 + || (BlockSize != 0 && (BlockSize < 256 || BlockSize >= Int32.MaxValue))) + throw new Exception("unsupported encoder settings"); } [DefaultValue(false)] @@ -105,6 +107,7 @@ namespace CUETools.Codecs.ALAC public ALACWriter(string path, Stream IO, ALACWriterSettings settings) { m_settings = settings; + m_settings.Validate(); if (Settings.PCM.BitsPerSample != 16) throw new Exception("Bits per sample must be 16."); @@ -1216,8 +1219,6 @@ namespace CUETools.Codecs.ALAC _IO = new FileStream(_path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read); if (_IO != null && !_IO.CanSeek) throw new NotSupportedException("stream doesn't support seeking"); - if (!m_settings.IsValid()) - throw new Exception("unsupported encoder settings"); encode_init(); inited = true; } diff --git a/CUETools.Codecs.FLACCL/FLACCLWriter.cs b/CUETools.Codecs.FLACCL/FLACCLWriter.cs index fd6e9c2..0a2204e 100644 --- a/CUETools.Codecs.FLACCL/FLACCLWriter.cs +++ b/CUETools.Codecs.FLACCL/FLACCLWriter.cs @@ -41,16 +41,127 @@ namespace CUETools.Codecs.FLACCL public override string GetSupportedModes(out string defaultMode) { defaultMode = "8"; - return this.AllowNonSubset ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8"; + return this.AllowNonSubset || (this.PCM != null && this.PCM.SampleRate > 48000) ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8"; } - public override bool IsValid() + public bool IsSubset() { - return EncoderModeIndex >= 0 && Padding >= 0 && - (BlockSize == 0 || (BlockSize >= 256 && BlockSize <= Flake.MAX_BLOCKSIZE)) && - (AllowNonSubset || EncoderModeIndex <= 8); + return (BlockSize == 0 || (BlockSize <= 16384 && (PCM.SampleRate > 48000 || BlockSize <= 4608))) + && (PCM.SampleRate > 48000 || MaxLPCOrder <= 12) + && MaxPartitionOrder <= 8 + ; + //The blocksize bits in the frame header must be 0001-1110. The blocksize must be <=16384; if the sample rate is <= 48000Hz, the blocksize must be <=4608. + //The sample rate bits in the frame header must be 0001-1110. + //The bits-per-sample bits in the frame header must be 001-111. + //If the sample rate is <= 48000Hz, the filter order in LPC subframes must be less than or equal to 12, i.e. the subframe type bits in the subframe header may not be 101100-111111. + //The Rice partition order in a Rice-coded residual section must be less than or equal to 8. } + public void Validate() + { + if (EncoderModeIndex < 0) + throw new Exception("unsupported encoder mode"); + var thisModeSettings = FLACCLWriterSettings.modeSettings[EncoderModeIndex]; + if (MaxLPCOrder < 0) + MaxLPCOrder = thisModeSettings.MaxLPCOrder; + if (MinFixedOrder < 0) + MinFixedOrder = thisModeSettings.MinFixedOrder; + if (MaxFixedOrder < 0) + MaxFixedOrder = thisModeSettings.MaxFixedOrder; + if (Padding < 0) + throw new Exception("unsupported padding value " + Padding.ToString()); + if (BlockSize != 0 && (BlockSize < 256 || BlockSize >= Flake.MAX_BLOCKSIZE)) + throw new Exception("unsupported block size " + BlockSize.ToString()); + if (MinLPCOrder > MaxLPCOrder || MaxLPCOrder > lpc.MAX_LPC_ORDER) + throw new Exception("invalid MaxLPCOrder " + MaxLPCOrder.ToString()); + if (MinFixedOrder < 0 || MinFixedOrder > 4) + throw new Exception("invalid MinFixedOrder " + MinFixedOrder.ToString()); + if (MaxFixedOrder < 0 || MaxFixedOrder > 4) + throw new Exception("invalid MaxFixedOrder " + MaxFixedOrder.ToString()); + if (MinPartitionOrder < 0) + throw new Exception("invalid MinPartitionOrder " + MinPartitionOrder.ToString()); + if (MinPartitionOrder > MaxPartitionOrder || MaxPartitionOrder > 8) + throw new Exception("invalid MaxPartitionOrder " + MaxPartitionOrder.ToString()); + if (!AllowNonSubset && !IsSubset()) + throw new Exception("the encoding parameters specified do not conform to the FLAC Subset"); + } + + private static FLACCLWriterSettings[] modeSettings = + { + new FLACCLWriterSettings() { + MinFixedOrder = 3, MaxFixedOrder = 2, MaxLPCOrder = 7, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 7, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 0, MaxFixedOrder = 4, MaxLPCOrder = 12, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 32, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 32, + }, + new FLACCLWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 32, + }, + }; + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MinFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MinFixedOrderDescription")] + public int MinFixedOrder { get; set; } + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MaxFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MaxFixedOrderDescription")] + public int MaxFixedOrder { get; set; } + + [DefaultValue(1)] + [Browsable(false)] + [DisplayName("MinLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MinLPCOrderDescription")] + public int MinLPCOrder { get; set; } + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MaxLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MaxLPCOrderDescription")] + public int MaxLPCOrder { get; set; } + + [DefaultValue(0)] + [DisplayName("MinPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MinPartitionOrderDescription")] + public int MinPartitionOrder { get; set; } + + [DefaultValue(8)] + [DisplayName("MaxPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MaxPartitionOrderDescription")] + public int MaxPartitionOrder { get; set; } + [DefaultValue(false)] [DisplayName("Verify")] [SRDescription(typeof(Properties.Resources), "DoVerifyDescription")] @@ -70,6 +181,7 @@ namespace CUETools.Codecs.FLACCL public bool DoRice { get; set; } [DefaultValue(false)] + [Browsable(false)] [SRDescription(typeof(Properties.Resources), "DescriptionMappedMemory")] public bool MappedMemory { get; set; } @@ -79,10 +191,12 @@ namespace CUETools.Codecs.FLACCL public int GroupSize { get; set; } [DefaultValue(8)] + [Browsable(false)] [SRDescription(typeof(Properties.Resources), "DescriptionTaskSize")] public int TaskSize { get; set; } [SRDescription(typeof(Properties.Resources), "DescriptionDefines")] + [Browsable(false)] public string Defines { get; set; } [TypeConverter(typeof(FLACCLWriterSettingsPlatformConverter))] @@ -164,7 +278,7 @@ namespace CUETools.Codecs.FLACCL int channels, ch_code; // audio sample rate in Hz - int sample_rate, sr_code0, sr_code1; + int sr_code0, sr_code1; // sample size in bits // only 16-bit is currently supported @@ -219,7 +333,8 @@ namespace CUETools.Codecs.FLACCL public FLACCLWriter(string path, Stream IO, FLACCLWriterSettings settings) { - m_settings = settings; + m_settings = settings.Clone() as FLACCLWriterSettings; + m_settings.Validate(); // FIXME: For now, only 16-bit encoding is supported if (Settings.PCM.BitsPerSample != 16 && Settings.PCM.BitsPerSample != 24) @@ -228,7 +343,6 @@ namespace CUETools.Codecs.FLACCL // throw new Exception("ChannelCount must be 2."); channels = Settings.PCM.ChannelCount; - sample_rate = Settings.PCM.SampleRate; bits_per_sample = (uint)Settings.PCM.BitsPerSample; // flake_validate_params @@ -236,8 +350,7 @@ namespace CUETools.Codecs.FLACCL _path = path; _IO = IO; - var _compressionLevel = Settings.EncoderModeIndex; - eparams.flake_set_defaults(_compressionLevel); + eparams.flake_set_defaults(m_settings); crc8 = new Crc8(); } @@ -468,62 +581,6 @@ namespace CUETools.Codecs.FLACCL } } - public int MinLPCOrder - { - get - { - return eparams.min_prediction_order; - } - set - { - if (value < 1 || value > eparams.max_prediction_order) - throw new Exception("invalid MinLPCOrder " + value.ToString()); - eparams.min_prediction_order = value; - } - } - - public int MaxLPCOrder - { - get - { - return eparams.max_prediction_order; - } - set - { - if (value > lpc.MAX_LPC_ORDER || value < eparams.min_prediction_order) - throw new Exception("invalid MaxLPCOrder " + value.ToString()); - eparams.max_prediction_order = value; - } - } - - public int MinFixedOrder - { - get - { - return eparams.min_fixed_order; - } - set - { - if (value < 0 || value > 4) - throw new Exception("invalid MinFixedOrder " + value.ToString()); - eparams.min_fixed_order = value; - } - } - - public int MaxFixedOrder - { - get - { - return eparams.max_fixed_order; - } - set - { - if (value > 4 || value < 0) - throw new Exception("invalid MaxFixedOrder " + value.ToString()); - eparams.max_fixed_order = value; - } - } - public bool DoConstant { get { return eparams.do_constant; } @@ -536,28 +593,6 @@ namespace CUETools.Codecs.FLACCL set { eparams.estimate_window = value; } } - public int MinPartitionOrder - { - get { return eparams.min_partition_order; } - set - { - if (value < 0 || value > eparams.max_partition_order) - throw new Exception("invalid MinPartitionOrder " + value.ToString()); - eparams.min_partition_order = value; - } - } - - public int MaxPartitionOrder - { - get { return eparams.max_partition_order; } - set - { - if (value > 8 || value < eparams.min_partition_order) - throw new Exception("invalid MaxPartitionOrder " + value.ToString()); - eparams.max_partition_order = value; - } - } - public TimeSpan UserProcessorTime { get { return _userProcessorTime; } @@ -1095,7 +1130,7 @@ namespace CUETools.Codecs.FLACCL task.nResidualTasks = 0; task.nTasksPerWindow = Math.Min(32, eparams.orders_per_window); - task.nResidualTasksPerChannel = task.nWindowFunctions * task.nTasksPerWindow + (eparams.do_constant ? 1 : 0) + Math.Max(0, 1 + eparams.max_fixed_order - eparams.min_fixed_order); + task.nResidualTasksPerChannel = task.nWindowFunctions * task.nTasksPerWindow + (eparams.do_constant ? 1 : 0) + Math.Max(0, 1 + m_settings.MaxFixedOrder - m_settings.MinFixedOrder); if (task.nResidualTasksPerChannel > 32) throw new Exception("too many tasks"); if (channels == 2 && channelsCount == 4) @@ -1160,7 +1195,7 @@ namespace CUETools.Codecs.FLACCL task.nResidualTasks++; } // Fixed prediction - for (int order = eparams.min_fixed_order; order <= eparams.max_fixed_order; order++) + for (int order = m_settings.MinFixedOrder; order <= m_settings.MaxFixedOrder; order++) { task.ResidualTasks[task.nResidualTasks].type = (int)SubframeType.Fixed; task.ResidualTasks[task.nResidualTasks].channel = ch; @@ -1247,7 +1282,7 @@ namespace CUETools.Codecs.FLACCL else frame.ch_mode = channels != 2 ? ChannelMode.NotStereo : ChannelMode.LeftRight; - int toUnpack = Math.Min(task.frameSize, eparams.max_prediction_order); + int toUnpack = Math.Min(task.frameSize, m_settings.MaxLPCOrder); // calculate wbits before unpacking samples. for (int ch = 0; ch < channels; ch++) { @@ -1256,7 +1291,7 @@ namespace CUETools.Codecs.FLACCL frame.subframes[ch].best.type = SubframeType.Verbatim; frame.subframes[ch].best.size = (uint)(frame.subframes[ch].obits * frame.blocksize); frame.subframes[ch].wbits = 0; - if (frame.blocksize > Math.Max(4, eparams.max_prediction_order)) + if (frame.blocksize > Math.Max(4, m_settings.MaxLPCOrder)) { if (task.BestResidualTasks[index].size < 0) throw new Exception("internal error"); @@ -1318,8 +1353,8 @@ namespace CUETools.Codecs.FLACCL encode_residual_fixed(task.frame.subframes[ch].best.residual, task.frame.subframes[ch].samples, task.frame.blocksize, task.frame.subframes[ch].best.order); - int pmin = get_max_p_order(eparams.min_partition_order, task.frame.blocksize, task.frame.subframes[ch].best.order); - int pmax = get_max_p_order(eparams.max_partition_order, task.frame.blocksize, task.frame.subframes[ch].best.order); + int pmin = get_max_p_order(m_settings.MinPartitionOrder, task.frame.blocksize, task.frame.subframes[ch].best.order); + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, task.frame.blocksize, task.frame.subframes[ch].best.order); calc_rice_params(task.frame.subframes[ch].best.rc, pmin, pmax, task.frame.subframes[ch].best.residual, (uint)task.frame.blocksize, (uint)task.frame.subframes[ch].best.order, Settings.PCM.BitsPerSample > 16 ? 1 : 0); } break; @@ -1334,8 +1369,8 @@ namespace CUETools.Codecs.FLACCL lpc.encode_residual(task.frame.subframes[ch].best.residual, task.frame.subframes[ch].samples, task.frame.blocksize, task.frame.subframes[ch].best.order, coefs, task.frame.subframes[ch].best.shift); } - int pmin = get_max_p_order(eparams.min_partition_order, task.frame.blocksize, task.frame.subframes[ch].best.order); - int pmax = get_max_p_order(eparams.max_partition_order, task.frame.blocksize, task.frame.subframes[ch].best.order); + int pmin = get_max_p_order(m_settings.MinPartitionOrder, task.frame.blocksize, task.frame.subframes[ch].best.order); + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, task.frame.blocksize, task.frame.subframes[ch].best.order); calc_rice_params(task.frame.subframes[ch].best.rc, pmin, pmax, task.frame.subframes[ch].best.residual, (uint)task.frame.blocksize, (uint)task.frame.subframes[ch].best.order, Settings.PCM.BitsPerSample > 16 ? 1 : 0); } break; @@ -1713,8 +1748,6 @@ namespace CUETools.Codecs.FLACCL { if (OpenCL.NumberOfPlatforms < 1) throw new Exception("no opencl platforms found"); - if (!m_settings.IsValid()) - throw new Exception("unsupported encoder settings"); int groupSize = m_settings.DeviceType == OpenCLDeviceType.CPU ? 1 : m_settings.GroupSize; OCLMan = new OpenCLManager(); @@ -1764,14 +1797,14 @@ namespace CUETools.Codecs.FLACCL bool UseGPURice = UseGPUOnly && m_settings.DoRice; m_blockSize = m_settings.BlockSize != 0 ? m_settings.BlockSize : - select_blocksize(sample_rate, eparams.block_time_ms); + select_blocksize(m_settings.PCM.SampleRate, eparams.block_time_ms); int maxBS = 1 << (BitReader.log2i(m_blockSize - 1) + 1); // The Defines string gets prepended to any and all sources that are compiled // and serve as a convenient way to pass configuration information to the compilation process OCLMan.Defines = - "#define MAX_ORDER " + eparams.max_prediction_order.ToString() + "\n" + + "#define MAX_ORDER " + m_settings.MaxLPCOrder.ToString() + "\n" + "#define GROUP_SIZE " + groupSize.ToString() + "\n" + "#define GROUP_SIZE_LOG " + BitReader.log2i(groupSize).ToString() + "\n" + "#define FLACCL_VERSION \"" + Vendor + "\"\n" + @@ -2049,7 +2082,7 @@ namespace CUETools.Codecs.FLACCL bitwriter.writebits(16, m_blockSize); bitwriter.writebits(24, 0); bitwriter.writebits(24, max_frame_size); - bitwriter.writebits(20, sample_rate); + bitwriter.writebits(20, m_settings.PCM.SampleRate); bitwriter.writebits(3, channels - 1); bitwriter.writebits(5, bits_per_sample - 1); @@ -2175,7 +2208,7 @@ namespace CUETools.Codecs.FLACCL // find samplerate in table for (i = 1; i < 12; i++) { - if (sample_rate == Flake.flac_samplerates[i]) + if (m_settings.PCM.SampleRate == Flake.flac_samplerates[i]) { sr_code0 = i; break; @@ -2205,7 +2238,7 @@ namespace CUETools.Codecs.FLACCL if (_IO.CanSeek && eparams.do_seektable && sample_count > 0) { - int seek_points_distance = sample_rate * 10; + int seek_points_distance = m_settings.PCM.SampleRate * 10; int num_seek_points = 1 + sample_count / seek_points_distance; // 1 seek point per 10 seconds if (sample_count % seek_points_distance == 0) num_seek_points--; @@ -2232,15 +2265,6 @@ namespace CUETools.Codecs.FLACCL struct FlakeEncodeParams { - // compression quality - // set by user prior to calling flake_encode_init - // standard values are 0 to 8 - // 0 is lower compression, faster encoding - // 8 is higher compression, slower encoding - // extended values 9 to 12 are slower and/or use - // higher prediction orders - public int compression; - // stereo decorrelation method // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. @@ -2255,46 +2279,10 @@ namespace CUETools.Codecs.FLACCL // can also be changed by user before encoding a frame public int block_time_ms; - // minimum LPC order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 1 to 32 - public int min_prediction_order; - - // maximum LPC order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 1 to 32 - public int max_prediction_order; - public int orders_per_window; public int orders_per_channel; - // minimum fixed prediction order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 4 - public int min_fixed_order; - - // maximum fixed prediction order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 4 - public int max_fixed_order; - - // minimum partition order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 8 - public int min_partition_order; - - // maximum partition order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 8 - public int max_partition_order; - // whether to use variable block sizes // set by user prior to calling flake_encode_init // 0 = fixed block size @@ -2318,25 +2306,13 @@ namespace CUETools.Codecs.FLACCL public bool do_seektable; - public int flake_set_defaults(int lvl) + public int flake_set_defaults(FLACCLWriterSettings settings) { - compression = lvl; - - if ((lvl < 0 || lvl > 12) && (lvl != 99)) - { - return -1; - } - + int lvl = settings.EncoderModeIndex; // default to level 5 params window_function = WindowFunction.Flattop | WindowFunction.Tukey; do_midside = true; block_time_ms = 100; - min_fixed_order = 0; - max_fixed_order = 4; - min_prediction_order = 1; - max_prediction_order = 12; - min_partition_order = 0; - max_partition_order = 8; variable_block_size = 0; lpc_min_precision_search = 0; lpc_max_precision_search = 0; @@ -2355,9 +2331,6 @@ namespace CUETools.Codecs.FLACCL do_midside = false; window_function = WindowFunction.Bartlett; orders_per_window = 1; - max_prediction_order = 7; - min_fixed_order = 3; - max_fixed_order = 2; break; case 1: do_constant = false; @@ -2365,54 +2338,35 @@ namespace CUETools.Codecs.FLACCL do_midside = false; window_function = WindowFunction.Bartlett; orders_per_window = 1; - min_fixed_order = 2; - max_fixed_order = 2; - max_prediction_order = 7; break; case 2: do_constant = false; do_midside = false; window_function = WindowFunction.Bartlett; orders_per_window = 1; - min_fixed_order = 2; - max_fixed_order = 2; - max_prediction_order = 8; break; case 3: do_constant = false; - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 1; orders_per_channel = 1; - max_prediction_order = 8; break; case 4: do_constant = false; - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 2; orders_per_channel = 2; - max_prediction_order = 8; break; case 5: do_constant = false; - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 4; orders_per_channel = 4; - max_prediction_order = 8; break; case 6: do_constant = false; - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 2; orders_per_channel = 2; break; case 7: do_constant = false; - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 4; orders_per_channel = 4; break; @@ -2421,26 +2375,16 @@ namespace CUETools.Codecs.FLACCL orders_per_channel = 8; break; case 9: - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 4; orders_per_channel = 4; - max_prediction_order = 32; break; case 10: - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 7; - max_prediction_order = 32; break; case 11: - min_fixed_order = 2; - max_fixed_order = 2; orders_per_window = 11; - max_prediction_order = 32; break; } - return 0; } } @@ -2574,7 +2518,7 @@ namespace CUETools.Codecs.FLACCL #endif openCLCQ = openCLProgram.Context.CreateCommandQueue(openCLProgram.Context.Devices[0], prop); - int MAX_ORDER = this.writer.eparams.max_prediction_order; + int MAX_ORDER = this.writer.m_settings.MaxLPCOrder; int MAX_FRAMES = this.writer.framesPerTask; int MAX_CHANNELSIZE = MAX_FRAMES * ((writer.m_blockSize + 3) & ~3); residualTasksLen = sizeof(FLACCLSubframeTask) * 32 * channelsCount * MAX_FRAMES; @@ -2836,9 +2780,10 @@ namespace CUETools.Codecs.FLACCL internal unsafe void EnqueueKernels() { - FlakeEncodeParams eparams = writer.eparams; + var eparams = writer.eparams; + var settings = writer.Settings as FLACCLWriterSettings; - this.max_porder = FLACCLWriter.get_max_p_order(eparams.max_partition_order, frameSize, eparams.max_prediction_order); + this.max_porder = FLACCLWriter.get_max_p_order(settings.MaxPartitionOrder, frameSize, settings.MaxLPCOrder); while ((frameSize >> max_porder) < 16 && max_porder > 0) this.max_porder--; diff --git a/CUETools.Codecs.FLAKE/Flake.cs b/CUETools.Codecs.FLAKE/Flake.cs index aa76263..86c8325 100644 --- a/CUETools.Codecs.FLAKE/Flake.cs +++ b/CUETools.Codecs.FLAKE/Flake.cs @@ -38,7 +38,12 @@ namespace CUETools.Codecs.FLAKE 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000, 0, 0, 0, 0 }; + //1100 : get 8 bit sample rate (in kHz) from end of header + //1101 : get 16 bit sample rate (in Hz) from end of header + //1110 : get 16 bit sample rate (in tens of Hz) from end of header public static readonly int[] flac_blocksizes = new int[15] { 0, 192, 576, 1152, 2304, 4608, 0, 0, 256, 512, 1024, 2048, 4096, 8192, 16384 }; + //0110 : get 8 bit (blocksize-1) from end of header + //0111 : get 16 bit (blocksize-1) from end of header public static readonly int[] flac_bitdepths = new int[8] { 0, 8, 12, 0, 16, 20, 24, 0 }; public static PredictionType LookupPredictionType(string name) diff --git a/CUETools.Codecs.FLAKE/FlakeWriter.cs b/CUETools.Codecs.FLAKE/FlakeWriter.cs index be45c82..003f25e 100644 --- a/CUETools.Codecs.FLAKE/FlakeWriter.cs +++ b/CUETools.Codecs.FLAKE/FlakeWriter.cs @@ -44,16 +44,129 @@ namespace CUETools.Codecs.FLAKE public override string GetSupportedModes(out string defaultMode) { defaultMode = "7"; - return this.AllowNonSubset ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8"; + return this.AllowNonSubset || (this.PCM != null && this.PCM.SampleRate > 48000) ? "0 1 2 3 4 5 6 7 8 9 10 11" : "0 1 2 3 4 5 6 7 8"; } - public override bool IsValid() + public bool IsSubset() { - return EncoderModeIndex >= 0 && Padding >= 0 && - (BlockSize == 0 || (BlockSize >= 256 && BlockSize <= Flake.MAX_BLOCKSIZE)) && - (AllowNonSubset || EncoderModeIndex <= 8); + return (BlockSize == 0 || (BlockSize <= 16384 && (PCM.SampleRate > 48000 || BlockSize <= 4608))) + && (PCM.SampleRate > 48000 || MaxLPCOrder <= 12) + && MaxPartitionOrder <= 8 + ; + //The blocksize bits in the frame header must be 0001-1110. The blocksize must be <=16384; if the sample rate is <= 48000Hz, the blocksize must be <=4608. + //The sample rate bits in the frame header must be 0001-1110. + //The bits-per-sample bits in the frame header must be 001-111. + //If the sample rate is <= 48000Hz, the filter order in LPC subframes must be less than or equal to 12, i.e. the subframe type bits in the subframe header may not be 101100-111111. + //The Rice partition order in a Rice-coded residual section must be less than or equal to 8. } + public void Validate() + { + if (EncoderModeIndex < 0) + throw new Exception("unsupported encoder mode"); + var thisModeSettings = FlakeWriterSettings.modeSettings[EncoderModeIndex]; + if (MaxLPCOrder < 0) + MaxLPCOrder = thisModeSettings.MaxLPCOrder; + if (MinFixedOrder < 0) + MinFixedOrder = thisModeSettings.MinFixedOrder; + if (MaxFixedOrder < 0) + MaxFixedOrder = thisModeSettings.MaxFixedOrder; + if (MaxPartitionOrder < 0) + MaxPartitionOrder = thisModeSettings.MaxPartitionOrder; + if (Padding < 0) + throw new Exception("unsupported padding value " + Padding.ToString()); + if (BlockSize != 0 && (BlockSize < 256 || BlockSize >= Flake.MAX_BLOCKSIZE)) + throw new Exception("unsupported block size " + BlockSize.ToString()); + if (MinLPCOrder > MaxLPCOrder || MaxLPCOrder > lpc.MAX_LPC_ORDER) + throw new Exception("invalid MaxLPCOrder " + MaxLPCOrder.ToString()); + if (MinFixedOrder < 0 || MinFixedOrder > 4) + throw new Exception("invalid MinFixedOrder " + MinFixedOrder.ToString()); + if (MaxFixedOrder < 0 || MaxFixedOrder > 4) + throw new Exception("invalid MaxFixedOrder " + MaxFixedOrder.ToString()); + if (MinPartitionOrder < 0) + throw new Exception("invalid MinPartitionOrder " + MinPartitionOrder.ToString()); + if (MinPartitionOrder > MaxPartitionOrder || MaxPartitionOrder > 8) + throw new Exception("invalid MaxPartitionOrder " + MaxPartitionOrder.ToString()); + if (!AllowNonSubset && !IsSubset()) + throw new Exception("the encoding parameters specified do not conform to the FLAC Subset"); + } + + private static FlakeWriterSettings[] modeSettings = + { + new FlakeWriterSettings() { + MinFixedOrder = 3, MaxFixedOrder = 2, MaxLPCOrder = 6, MaxPartitionOrder = 6, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, MaxPartitionOrder = 6, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 6, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 8, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 0, MaxFixedOrder = 2, MaxLPCOrder = 12, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 2, MaxFixedOrder = 2, MaxLPCOrder = 32, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 0, MaxFixedOrder = 4, MaxLPCOrder = 32, MaxPartitionOrder = 8, + }, + new FlakeWriterSettings() { + MinFixedOrder = 0, MaxFixedOrder = 4, MaxLPCOrder = 32, MaxPartitionOrder = 8, + }, + }; + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MinFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MinFixedOrderDescription")] + public int MinFixedOrder { get; set; } + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MaxFixedOrder")] + [SRDescription(typeof(Properties.Resources), "MaxFixedOrderDescription")] + public int MaxFixedOrder { get; set; } + + [DefaultValue(1)] + [Browsable(false)] + [DisplayName("MinLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MinLPCOrderDescription")] + public int MinLPCOrder { get; set; } + + [DefaultValue(-1)] + [Browsable(false)] + [DisplayName("MaxLPCOrder")] + [SRDescription(typeof(Properties.Resources), "MaxLPCOrderDescription")] + public int MaxLPCOrder { get; set; } + + [DefaultValue(0)] + [DisplayName("MinPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MinPartitionOrderDescription")] + public int MinPartitionOrder { get; set; } + + [DefaultValue(-1)] + [DisplayName("MaxPartitionOrder")] + [Browsable(false)] + [SRDescription(typeof(Properties.Resources), "MaxPartitionOrderDescription")] + public int MaxPartitionOrder { get; set; } + [DefaultValue(false)] [DisplayName("Verify")] [SRDescription(typeof(Properties.Resources), "DoVerifyDescription")] @@ -142,7 +255,8 @@ namespace CUETools.Codecs.FLAKE public FlakeWriter(string path, Stream IO, FlakeWriterSettings settings) { - m_settings = settings; + m_settings = settings.Clone() as FlakeWriterSettings; + m_settings.Validate(); //if (Settings.PCM.BitsPerSample != 16) // throw new Exception("Bits per sample must be 16."); @@ -161,8 +275,7 @@ namespace CUETools.Codecs.FLAKE windowBuffer = new float[Flake.MAX_BLOCKSIZE * 2 * lpc.MAX_LPC_WINDOWS]; windowScale = new double[lpc.MAX_LPC_WINDOWS]; - var _compressionLevel = Settings.EncoderModeIndex; - eparams.flake_set_defaults(_compressionLevel); + eparams.flake_set_defaults(m_settings); crc8 = new Crc8(); frame = new FlacFrame(channels * 2); @@ -346,70 +459,6 @@ namespace CUETools.Codecs.FLAKE set { eparams.variable_block_size = value; } } - public int MinPredictionOrder - { - get - { - return PredictionType == PredictionType.Fixed ? - MinFixedOrder : MinLPCOrder; - } - set - { - if (PredictionType == PredictionType.Fixed) - MinFixedOrder = value; - else - MinLPCOrder = value; - } - } - - public int MaxPredictionOrder - { - get - { - return PredictionType == PredictionType.Fixed ? - MaxFixedOrder : MaxLPCOrder; - } - set - { - if (PredictionType == PredictionType.Fixed) - MaxFixedOrder = value; - else - MaxLPCOrder = value; - } - } - - public int MinLPCOrder - { - get - { - return eparams.min_prediction_order; - } - set - { - if (value < 1) - throw new Exception("invalid MinLPCOrder " + value.ToString()); - if (eparams.max_prediction_order < value) - eparams.max_prediction_order = value; - eparams.min_prediction_order = value; - } - } - - public int MaxLPCOrder - { - get - { - return eparams.max_prediction_order; - } - set - { - if (value > lpc.MAX_LPC_ORDER) - throw new Exception("invalid MaxLPCOrder " + value.ToString()); - if (eparams.min_prediction_order > value) - eparams.min_prediction_order = value; - eparams.max_prediction_order = value; - } - } - public int EstimationDepth { get @@ -424,56 +473,6 @@ namespace CUETools.Codecs.FLAKE } } - public int MinFixedOrder - { - get - { - return eparams.min_fixed_order; - } - set - { - if (value < 0 || value > eparams.max_fixed_order) - throw new Exception("invalid MinFixedOrder " + value.ToString()); - eparams.min_fixed_order = value; - } - } - - public int MaxFixedOrder - { - get - { - return eparams.max_fixed_order; - } - set - { - if (value > 4 || value < eparams.min_fixed_order) - throw new Exception("invalid MaxFixedOrder " + value.ToString()); - eparams.max_fixed_order = value; - } - } - - public int MinPartitionOrder - { - get { return eparams.min_partition_order; } - set - { - if (value < 0 || value > eparams.max_partition_order) - throw new Exception("invalid MinPartitionOrder " + value.ToString()); - eparams.min_partition_order = value; - } - } - - public int MaxPartitionOrder - { - get { return eparams.max_partition_order; } - set - { - if (value > 8 || value < eparams.min_partition_order) - throw new Exception("invalid MaxPartitionOrder " + value.ToString()); - eparams.max_partition_order = value; - } - } - public TimeSpan UserProcessorTime { get @@ -904,8 +903,8 @@ new int[] { // 30 int orig_xx = -1; int orig_seq = 0; int maxxx = Math.Min(good_x[orig_order].Length, eparams.development_mode); - var pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, orig_order); - var pmin = Math.Min(eparams.min_partition_order, pmax); + var pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, orig_order); + var pmin = Math.Min(m_settings.MinPartitionOrder, pmax); ulong* sums = stackalloc ulong[(pmax + 1) * Flake.MAX_PARTITIONS]; while (true) @@ -1084,8 +1083,8 @@ new int[] { // 30 lpc.encode_residual(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order, coefs, frame.current.shift); } - int pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, frame.current.order); - int pmin = Math.Min(eparams.min_partition_order, pmax); + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, frame.current.order); + int pmin = Math.Min(m_settings.MinPartitionOrder, pmax); uint best_size = calc_rice_params(frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order, Settings.PCM.BitsPerSample); // not working //for (int o = 1; o <= frame.current.order; o++) @@ -1126,8 +1125,8 @@ new int[] { // 30 encode_residual_fixed(frame.current.residual, frame.subframes[ch].samples, frame.blocksize, frame.current.order); - int pmax = get_max_p_order(eparams.max_partition_order, frame.blocksize, frame.current.order); - int pmin = Math.Min(eparams.min_partition_order, pmax); + int pmax = get_max_p_order(m_settings.MaxPartitionOrder, frame.blocksize, frame.current.order); + int pmin = Math.Min(m_settings.MinPartitionOrder, pmax); frame.current.size = (uint)(frame.current.order * frame.subframes[ch].obits) + 6 + calc_rice_params(frame.current.rc, pmin, pmax, frame.current.residual, (uint)frame.blocksize, (uint)frame.current.order, Settings.PCM.BitsPerSample); @@ -1164,7 +1163,7 @@ new int[] { // 30 return; // LPC - if (n > eparams.max_prediction_order && + if (n > m_settings.MaxLPCOrder && (predict == PredictionType.Levinson || predict == PredictionType.Search) //predict == PredictionType.Search || @@ -1172,8 +1171,8 @@ new int[] { // 30 ) { float* lpcs = stackalloc float[lpc.MAX_LPC_ORDER * lpc.MAX_LPC_ORDER]; - int min_order = eparams.min_prediction_order; - int max_order = eparams.max_prediction_order; + int min_order = m_settings.MinLPCOrder; + int max_order = m_settings.MaxLPCOrder; for (int iWindow = 0; iWindow < _windowcount; iWindow++) { @@ -1257,10 +1256,10 @@ new int[] { // 30 (predict == PredictionType.Search && pass != 1) || //predict == PredictionType.Search || //(pass == 2 && frame.subframes[ch].best.type == SubframeType.Fixed) || - (n > eparams.max_fixed_order && n <= eparams.max_prediction_order)) + (n > m_settings.MaxFixedOrder && n <= m_settings.MaxLPCOrder)) { - int max_fixed_order = Math.Min(eparams.max_fixed_order, 4); - int min_fixed_order = Math.Min(eparams.min_fixed_order, max_fixed_order); + int max_fixed_order = Math.Min(m_settings.MaxFixedOrder, 4); + int min_fixed_order = Math.Min(m_settings.MinFixedOrder, max_fixed_order); for (i = min_fixed_order; i <= max_fixed_order; i++) encode_residual_fixed_sub(frame, i, ch); @@ -1426,27 +1425,27 @@ new int[] { // 30 unsafe void encode_residual_pass1(FlacFrame frame, int ch, int best_window) { - int max_prediction_order = eparams.max_prediction_order; - int max_fixed_order = eparams.max_fixed_order; - int min_fixed_order = eparams.min_fixed_order; + int max_prediction_order = m_settings.MaxLPCOrder; + int max_fixed_order = m_settings.MaxFixedOrder; + int min_fixed_order = m_settings.MinFixedOrder; int lpc_min_precision_search = eparams.lpc_min_precision_search; int lpc_max_precision_search = eparams.lpc_max_precision_search; - int max_partition_order = eparams.max_partition_order; + int max_partition_order = m_settings.MaxPartitionOrder; int estimation_depth = eparams.estimation_depth; var development_mode = eparams.development_mode; - eparams.min_fixed_order = 2; - eparams.max_fixed_order = 2; + m_settings.MinFixedOrder = 2; + m_settings.MaxFixedOrder = 2; eparams.lpc_min_precision_search = eparams.lpc_max_precision_search; - eparams.max_prediction_order = Math.Min(eparams.max_prediction_order, Math.Max(eparams.min_prediction_order, 8)); + m_settings.MaxLPCOrder = Math.Min(m_settings.MaxLPCOrder, Math.Max(m_settings.MinLPCOrder, 8)); eparams.estimation_depth = 1; eparams.development_mode = Math.Min(eparams.development_mode, -1); encode_residual(frame, ch, eparams.prediction_type, OrderMethod.Akaike, 1, best_window); - eparams.min_fixed_order = min_fixed_order; - eparams.max_fixed_order = max_fixed_order; - eparams.max_prediction_order = max_prediction_order; + m_settings.MinFixedOrder = min_fixed_order; + m_settings.MaxFixedOrder = max_fixed_order; + m_settings.MaxLPCOrder = max_prediction_order; eparams.lpc_min_precision_search = lpc_min_precision_search; eparams.lpc_max_precision_search = lpc_max_precision_search; - eparams.max_partition_order = max_partition_order; + m_settings.MaxPartitionOrder = max_partition_order; eparams.estimation_depth = estimation_depth; eparams.development_mode = development_mode; } @@ -1501,7 +1500,7 @@ new int[] { // 30 LpcContext lpc_ctx = frame.subframes[ch].lpc_ctx[0]; lpc_ctx.GetReflection(4, frame.subframes[ch].samples, frame.blocksize, frame.window_buffer); lpc_ctx.SortOrdersAkaike(frame.blocksize, 1, 1, 4, 4.5, 0.0); - frame.subframes[ch].best.size = (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) + 7.1 * frame.subframes[ch].obits * eparams.max_prediction_order); + frame.subframes[ch].best.size = (uint)Math.Max(0, lpc_ctx.Akaike(frame.blocksize, lpc_ctx.best_orders[0], 4.5, 0.0) + 7.1 * frame.subframes[ch].obits * m_settings.MaxLPCOrder); } break; case StereoMethod.Evaluate: @@ -1779,8 +1778,6 @@ new int[] { // 30 { if (_IO == null) _IO = new FileStream(_path, FileMode.Create, FileAccess.Write, FileShare.Read); - if (!m_settings.IsValid()) - throw new Exception("unsupported encoder settings"); inited = true; int header_size = flake_encode_init(); _IO.Write(header, 0, header_size); @@ -1836,7 +1833,7 @@ new int[] { // 30 return blocksize >> 1; } - for (int i = 0; i < Flake.flac_blocksizes.Length; i++) + for (int i = 8; i < Flake.flac_blocksizes.Length - 1; i++) if (target >= Flake.flac_blocksizes[i] && Flake.flac_blocksizes[i] > blocksize) { blocksize = Flake.flac_blocksizes[i]; @@ -2057,15 +2054,6 @@ new int[] { // 30 struct FlakeEncodeParams { - // compression quality - // set by user prior to calling flake_encode_init - // standard values are 0 to 8 - // 0 is lower compression, faster encoding - // 8 is higher compression, slower encoding - // extended values 9 to 12 are slower and/or use - // higher prediction orders - public int compression; - // prediction order selection method // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. @@ -2079,7 +2067,6 @@ new int[] { // 30 // 6 = log search public OrderMethod order_method; - // stereo decorrelation method // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. @@ -2096,52 +2083,16 @@ new int[] { // 30 // can also be changed by user before encoding a frame public int block_time_ms; - // minimum LPC order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 1 to 32 - public int min_prediction_order; - - // maximum LPC order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 1 to 32 - public int max_prediction_order; - // Number of LPC orders to try (for estimate mode) // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 1 to 32 public int estimation_depth; - // minimum fixed prediction order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 4 - public int min_fixed_order; - - // maximum fixed prediction order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 4 - public int max_fixed_order; - // type of linear prediction // set by user prior to calling flake_encode_init public PredictionType prediction_type; - // minimum partition order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 8 - public int min_partition_order; - - // maximum partition order - // set by user prior to calling flake_encode_init - // if set to less than 0, it is chosen based on compression. - // valid values are 0 to 8 - public int max_partition_order; - // whether to use variable block sizes // set by user prior to calling flake_encode_init // 0 = fixed block size @@ -2161,60 +2112,42 @@ new int[] { // 30 public int development_mode; - public int flake_set_defaults(int lvl) + public int flake_set_defaults(FlakeWriterSettings settings) { - compression = lvl; - - if ((lvl < 0 || lvl > 12) && (lvl != 99)) - { - return -1; - } - - // default to level 5 params + // default to level 7 params window_function = WindowFunction.Flattop | WindowFunction.Tukey; order_method = OrderMethod.Akaike; stereo_method = StereoMethod.Evaluate; window_method = WindowMethod.Evaluate; block_time_ms = 105; prediction_type = PredictionType.Search; - min_prediction_order = 1; - max_prediction_order = 12; - estimation_depth = 1; - min_fixed_order = 2; - max_fixed_order = 2; - min_partition_order = 0; - max_partition_order = 8; - variable_block_size = 0; + estimation_depth = 1; + variable_block_size = 0; lpc_min_precision_search = 1; lpc_max_precision_search = 1; do_seektable = true; development_mode = -1; // differences from level 7 - switch (lvl) + switch (settings.EncoderModeIndex) { case 0: block_time_ms = 53; prediction_type = PredictionType.Fixed; stereo_method = StereoMethod.Independent; - max_partition_order = 6; break; case 1: prediction_type = PredictionType.Levinson; stereo_method = StereoMethod.Independent; window_function = WindowFunction.Bartlett; - max_prediction_order = 8; - max_partition_order = 6; break; case 2: stereo_method = StereoMethod.Independent; window_function = WindowFunction.Bartlett; - max_partition_order = 6; break; case 3: stereo_method = StereoMethod.Estimate; window_function = WindowFunction.Bartlett; - max_prediction_order = 8; break; case 4: stereo_method = StereoMethod.Estimate; @@ -2231,23 +2164,15 @@ new int[] { // 30 break; case 8: estimation_depth = 2; - min_fixed_order = 0; lpc_min_precision_search = 0; break; case 9: window_function = WindowFunction.Bartlett; - max_prediction_order = 32; break; case 10: - min_fixed_order = 0; - max_fixed_order = 4; - max_prediction_order = 32; //lpc_max_precision_search = 2; break; case 11: - min_fixed_order = 0; - max_fixed_order = 4; - max_prediction_order = 32; estimation_depth = 5; //lpc_max_precision_search = 2; variable_block_size = 4; diff --git a/CUETools.Codecs/AudioEncoderSettings.cs b/CUETools.Codecs/AudioEncoderSettings.cs index 32c7e36..ddfcef8 100644 --- a/CUETools.Codecs/AudioEncoderSettings.cs +++ b/CUETools.Codecs/AudioEncoderSettings.cs @@ -46,17 +46,6 @@ namespace CUETools.Codecs return this.m_supported_modes; } - public virtual bool IsValid() - { - return BlockSize == 0 && Padding >= 0; - } - - public void Validate() - { - if (!IsValid()) - throw new Exception("unsupported encoder settings"); - } - public AudioEncoderSettings Clone() { return this.MemberwiseClone() as AudioEncoderSettings; diff --git a/CUETools.Converter/Program.cs b/CUETools.Converter/Program.cs index 5544300..fd8ab93 100644 --- a/CUETools.Converter/Program.cs +++ b/CUETools.Converter/Program.cs @@ -172,7 +172,6 @@ namespace CUETools.Converter settings.PCM = audioSource.PCM; settings.Padding = padding; settings.EncoderMode = encoderMode ?? settings.EncoderMode; - settings.Validate(); object o = null; try { diff --git a/CUETools.FLACCL.cmd/Program.cs b/CUETools.FLACCL.cmd/Program.cs index 36fdd82..3ffab4e 100644 --- a/CUETools.FLACCL.cmd/Program.cs +++ b/CUETools.FLACCL.cmd/Program.cs @@ -82,10 +82,7 @@ namespace CUETools.FLACCL.cmd string input_file = null; string output_file = null; string device_type = null; - int min_partition_order = -1, max_partition_order = -1, - min_lpc_order = -1, max_lpc_order = -1, - min_fixed_order = -1, max_fixed_order = -1, - min_precision = -1, max_precision = -1, + int min_precision = -1, max_precision = -1, orders_per_window = -1, orders_per_channel = -1; int input_len = 4096, input_val = 0, input_bps = 16, input_ch = 2, input_rate = 44100; int level = -1, vbr_mode = -1; @@ -152,43 +149,55 @@ namespace CUETools.FLACCL.cmd window_function = args[arg]; else if ((args[arg] == "-r" || args[arg] == "--partition-order") && ++arg < args.Length) { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_partition_order) && - int.TryParse(args[arg].Split(',')[1], out max_partition_order)) || - int.TryParse(args[arg], out max_partition_order); + int min_partition_order, max_partition_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_partition_order) + && (settings.MinPartitionOrder = min_partition_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_partition_order) + && (settings.MaxPartitionOrder = max_partition_order) != -1) + || (int.TryParse(args[arg], out max_partition_order) + && (settings.MaxPartitionOrder = max_partition_order) != -1); } else if ((args[arg] == "-l" || args[arg] == "--lpc-order") && ++arg < args.Length) { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_lpc_order) && - int.TryParse(args[arg].Split(',')[1], out max_lpc_order)) || - int.TryParse(args[arg], out max_lpc_order); + int min_lpc_order, max_lpc_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_lpc_order) + && (settings.MinLPCOrder = min_lpc_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_lpc_order) + && (settings.MaxLPCOrder = max_lpc_order) != -1) + || (int.TryParse(args[arg], out max_lpc_order) + && (settings.MaxLPCOrder = max_lpc_order) != -1); } - else if (args[arg] == "--fixed-order" && ++arg < args.Length) - { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_fixed_order) && - int.TryParse(args[arg].Split(',')[1], out max_fixed_order)) || - int.TryParse(args[arg], out max_fixed_order); - } - else if ((args[arg] == "-c" || args[arg] == "--max-precision") && ++arg < args.Length) - { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_precision) && - int.TryParse(args[arg].Split(',')[1], out max_precision)) || - int.TryParse(args[arg], out max_precision); - } - else if ((args[arg] == "-v" || args[arg] == "--vbr")) - ok = (++arg < args.Length) && int.TryParse(args[arg], out vbr_mode); - else if (args[arg] == "--orders-per-window" && ++arg < args.Length && int.TryParse(args[arg], out intarg)) - orders_per_window = intarg; - else if (args[arg] == "--orders-per-channel" && ++arg < args.Length && int.TryParse(args[arg], out intarg)) - orders_per_channel = intarg; - else if (args[arg] == "--estimate-window") - estimate_window = true; - else if ((args[arg] == "-b" || args[arg] == "--blocksize") && ++arg < args.Length && int.TryParse(args[arg], out intarg)) + else if (args[arg] == "--fixed-order" && ++arg < args.Length) + { + int min_fixed_order, max_fixed_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_fixed_order) + && (settings.MinFixedOrder = min_fixed_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_fixed_order) + && (settings.MaxFixedOrder = max_fixed_order) != -1) + || (int.TryParse(args[arg], out max_fixed_order) + && (settings.MaxFixedOrder = max_fixed_order) != -1); + } + else if ((args[arg] == "-c" || args[arg] == "--max-precision") && ++arg < args.Length) + { + ok = (args[arg].Split(',').Length == 2 && + int.TryParse(args[arg].Split(',')[0], out min_precision) && + int.TryParse(args[arg].Split(',')[1], out max_precision)) || + int.TryParse(args[arg], out max_precision); + } + else if ((args[arg] == "-v" || args[arg] == "--vbr")) + ok = (++arg < args.Length) && int.TryParse(args[arg], out vbr_mode); + else if (args[arg] == "--orders-per-window" && ++arg < args.Length && int.TryParse(args[arg], out intarg)) + orders_per_window = intarg; + else if (args[arg] == "--orders-per-channel" && ++arg < args.Length && int.TryParse(args[arg], out intarg)) + orders_per_channel = intarg; + else if (args[arg] == "--estimate-window") + estimate_window = true; + else if ((args[arg] == "-b" || args[arg] == "--blocksize") && ++arg < args.Length && int.TryParse(args[arg], out intarg)) settings.BlockSize = intarg; - else if ((args[arg] == "-p" || args[arg] == "--padding") && ++arg < args.Length && int.TryParse(args[arg], out intarg)) + else if ((args[arg] == "-p" || args[arg] == "--padding") && ++arg < args.Length && int.TryParse(args[arg], out intarg)) settings.Padding = intarg; else if (args[arg] != "-" && args[arg][0] == '-' && int.TryParse(args[arg].Substring(1), out level)) { @@ -253,35 +262,21 @@ namespace CUETools.FLACCL.cmd output_file = Path.ChangeExtension(input_file, "flac"); settings.PCM = audioSource.PCM; settings.AllowNonSubset = allowNonSubset; - FLACCLWriter encoder = new FLACCLWriter((output_file == "-" || output_file == "nul") ? "" : output_file, - output_file == "-" ? Console.OpenStandardOutput() : - output_file == "nul" ? new NullStream() : null, - settings); - encoder.FinalSampleCount = audioSource.Length; - IAudioDest audioDest = encoder; - AudioBuffer buff = new AudioBuffer(audioSource, FLACCLWriter.MAX_BLOCKSIZE); + FLACCLWriter encoder; try { - if (device_type != null) - settings.DeviceType = (OpenCLDeviceType)(Enum.Parse(typeof(OpenCLDeviceType), device_type, true)); - settings.Validate(); + if (device_type != null) + settings.DeviceType = (OpenCLDeviceType)(Enum.Parse(typeof(OpenCLDeviceType), device_type, true)); + encoder = new FLACCLWriter((output_file == "-" || output_file == "nul") ? "" : output_file, + output_file == "-" ? Console.OpenStandardOutput() : + output_file == "nul" ? new NullStream() : null, + settings); + encoder.FinalSampleCount = audioSource.Length; if (stereo_method != null) encoder.StereoMethod = Flake.LookupStereoMethod(stereo_method); if (window_function != null) encoder.WindowFunction = Flake.LookupWindowFunction(window_function); - if (min_partition_order >= 0) - encoder.MinPartitionOrder = min_partition_order; - if (max_partition_order >= 0) - encoder.MaxPartitionOrder = max_partition_order; - if (min_lpc_order >= 0) - encoder.MinLPCOrder = min_lpc_order; - if (max_lpc_order >= 0) - encoder.MaxLPCOrder = max_lpc_order; - if (min_fixed_order >= 0) - encoder.MinFixedOrder = min_fixed_order; - if (max_fixed_order >= 0) - encoder.MaxFixedOrder = max_fixed_order; if (max_precision >= 0) encoder.MaxPrecisionSearch = max_precision; if (min_precision >= 0) @@ -304,6 +299,9 @@ namespace CUETools.FLACCL.cmd return 3; } + IAudioDest audioDest = encoder; + AudioBuffer buff = new AudioBuffer(audioSource, FLACCLWriter.MAX_BLOCKSIZE); + if (!quiet) { Console.WriteLine("Filename : {0}", input_file); @@ -393,15 +391,15 @@ namespace CUETools.FLACCL.cmd encoder.UserProcessorTime.TotalSeconds > 0 ? encoder.UserProcessorTime.TotalSeconds : totalElapsed.TotalSeconds, (encoder.StereoMethod.ToString() + (encoder.OrdersPerChannel == 32 ? "" : "(" + encoder.OrdersPerChannel.ToString() + ")")).PadRight(15), encoder.WindowFunction.ToString().PadRight(15), - encoder.MaxPartitionOrder, + settings.MaxPartitionOrder, settings.GPUOnly ? "GPU" : "CPU", encoder.OrdersPerWindow, - encoder.MaxLPCOrder, + (encoder.Settings as FLACCLWriterSettings).MaxLPCOrder, encoder.MinPrecisionSearch, encoder.MaxPrecisionSearch, encoder.Settings.BlockSize, encoder.VBRMode, - encoder.MaxFixedOrder - encoder.MinFixedOrder + 1, + (encoder.Settings as FLACCLWriterSettings).MaxFixedOrder - (encoder.Settings as FLACCLWriterSettings).MinFixedOrder + 1, encoder.DoConstant ? "c" : "" ); } diff --git a/CUETools.Flake/Program.cs b/CUETools.Flake/Program.cs index 413d6e7..0121df0 100644 --- a/CUETools.Flake/Program.cs +++ b/CUETools.Flake/Program.cs @@ -138,10 +138,7 @@ namespace CUETools.FlakeExe string window_function = null; string input_file = null; string output_file = null; - int min_partition_order = -1, max_partition_order = -1, - min_lpc_order = -1, max_lpc_order = -1, - min_fixed_order = -1, max_fixed_order = -1, - min_precision = -1, max_precision = -1, + int min_precision = -1, max_precision = -1, estimation_depth = -1; int skip_a = 0, skip_b = 0; int intarg = -1, vbr_mode = -1, magic = -1; @@ -187,24 +184,36 @@ namespace CUETools.FlakeExe window_method = args[arg]; else if ((args[arg] == "-r" || args[arg] == "--partition-order") && ++arg < args.Length) { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_partition_order) && - int.TryParse(args[arg].Split(',')[1], out max_partition_order)) || - int.TryParse(args[arg], out max_partition_order); + int min_partition_order, max_partition_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_partition_order) + && (settings.MinPartitionOrder = min_partition_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_partition_order) + && (settings.MaxPartitionOrder = max_partition_order) != -1) + || (int.TryParse(args[arg], out max_partition_order) + && (settings.MaxPartitionOrder = max_partition_order) != -1); } else if ((args[arg] == "-l" || args[arg] == "--lpc-order") && ++arg < args.Length) { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_lpc_order) && - int.TryParse(args[arg].Split(',')[1], out max_lpc_order)) || - int.TryParse(args[arg], out max_lpc_order); + int min_lpc_order, max_lpc_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_lpc_order) + && (settings.MinLPCOrder = min_lpc_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_lpc_order) + && (settings.MaxLPCOrder = max_lpc_order) != -1) + || (int.TryParse(args[arg], out max_lpc_order) + && (settings.MaxLPCOrder = max_lpc_order) != -1); } else if ((args[arg] == "-f" || args[arg] == "--fixed-order") && ++arg < args.Length) { - ok = (args[arg].Split(',').Length == 2 && - int.TryParse(args[arg].Split(',')[0], out min_fixed_order) && - int.TryParse(args[arg].Split(',')[1], out max_fixed_order)) || - int.TryParse(args[arg], out max_fixed_order); + int min_fixed_order, max_fixed_order; + ok = (args[arg].Split(',').Length == 2 + && int.TryParse(args[arg].Split(',')[0], out min_fixed_order) + && (settings.MinFixedOrder = min_fixed_order) != -1 + && int.TryParse(args[arg].Split(',')[1], out max_fixed_order) + && (settings.MaxFixedOrder = max_fixed_order) != -1) + || (int.TryParse(args[arg], out max_fixed_order) + && (settings.MaxFixedOrder = max_fixed_order) != -1); } else if (args[arg] == "--skip" && ++arg < args.Length) { @@ -329,17 +338,16 @@ namespace CUETools.FlakeExe output_file = Path.ChangeExtension(input_file, "flac"); settings.PCM = audioSource.PCM; settings.AllowNonSubset = allowNonSubset; - FlakeWriter flake = new FlakeWriter((output_file == "-" || output_file == "nul") ? "" : output_file, - output_file == "-" ? Console.OpenStandardOutput() : - output_file == "nul" ? new NullStream() : null, - settings); - flake.FinalSampleCount = audioSource.Length - skip_a - skip_b; - IAudioDest audioDest = flake; - AudioBuffer buff = new AudioBuffer(audioSource, 0x10000); + FlakeWriter flake; try { - settings.Validate(); + flake = new FlakeWriter((output_file == "-" || output_file == "nul") ? "" : output_file, + output_file == "-" ? Console.OpenStandardOutput() : + output_file == "nul" ? new NullStream() : null, + settings); + flake.FinalSampleCount = audioSource.Length - skip_a - skip_b; + if (prediction_type != null) flake.PredictionType = Flake.LookupPredictionType(prediction_type); if (stereo_method != null) @@ -350,18 +358,6 @@ namespace CUETools.FlakeExe flake.OrderMethod = Flake.LookupOrderMethod(order_method); if (window_function != null) flake.WindowFunction = Flake.LookupWindowFunction(window_function); - if (min_partition_order >= 0) - flake.MinPartitionOrder = min_partition_order; - if (max_partition_order >= 0) - flake.MaxPartitionOrder = max_partition_order; - if (min_lpc_order >= 0) - flake.MinLPCOrder = min_lpc_order; - if (max_lpc_order >= 0) - flake.MaxLPCOrder = max_lpc_order; - if (min_fixed_order >= 0) - flake.MinFixedOrder = min_fixed_order; - if (max_fixed_order >= 0) - flake.MaxFixedOrder = max_fixed_order; if (min_precision >= 0) flake.MinPrecisionSearch = min_precision; if (max_precision >= 0) @@ -382,6 +378,9 @@ namespace CUETools.FlakeExe return 4; } + IAudioDest audioDest = flake; + AudioBuffer buff = new AudioBuffer(audioSource, 0x10000); + if (!quiet) { Console.WriteLine("Filename : {0}", input_file); @@ -479,12 +478,12 @@ namespace CUETools.FlakeExe flake.StereoMethod.ToString().PadRight(15), (flake.OrderMethod.ToString() + "(" + flake.EstimationDepth.ToString() + ")").PadRight(15), flake.WindowFunction, - flake.MinPartitionOrder, - flake.MaxPartitionOrder, - flake.MinLPCOrder, - flake.MaxLPCOrder, - flake.MinFixedOrder, - flake.MaxFixedOrder, + (flake.Settings as FlakeWriterSettings).MinPartitionOrder, + (flake.Settings as FlakeWriterSettings).MaxPartitionOrder, + (flake.Settings as FlakeWriterSettings).MinLPCOrder, + (flake.Settings as FlakeWriterSettings).MaxLPCOrder, + (flake.Settings as FlakeWriterSettings).MinFixedOrder, + (flake.Settings as FlakeWriterSettings).MaxFixedOrder, flake.MinPrecisionSearch, flake.MaxPrecisionSearch, flake.Settings.BlockSize, diff --git a/CUETools.Processor/AudioReadWrite.cs b/CUETools.Processor/AudioReadWrite.cs index 2f46dee..0968756 100644 --- a/CUETools.Processor/AudioReadWrite.cs +++ b/CUETools.Processor/AudioReadWrite.cs @@ -67,8 +67,15 @@ namespace CUETools.Processor var settings = encoder.settings.Clone(); settings.PCM = pcm; settings.Padding = padding; - settings.Validate(); - object o = Activator.CreateInstance(encoder.type, path, settings); + object o; + try + { + o = Activator.CreateInstance(encoder.type, path, settings); + } + catch (System.Reflection.TargetInvocationException ex) + { + throw ex.InnerException; + } if (o == null || !(o is IAudioDest)) throw new Exception("Unsupported audio type: " + path + ": " + encoder.type.FullName); dest = o as IAudioDest;