Exemplo n.º 1
0
        static int Main(string[] args)
        {
            TextWriter stdout = Console.Out;

            Console.SetOut(Console.Error);

            DateTime start = DateTime.Now;
            TimeSpan lastPrint = TimeSpan.FromMilliseconds(0);
            bool     debug = false, quiet = false;
            string   order_method = null;
            string   input_file = null;
            string   output_file = null;
            int      skip_a = 0, skip_b = 0;
            int      intarg = -1, vbr_mode = -1, magic = -1;
            bool     do_seektable = true;
            bool     buffered     = false;
            string   coeffs       = null;
            var      settings     = new Codecs.Flake.EncoderSettings()
            {
                AllowNonSubset = true
            };
            bool allowNonSubset     = false;
            bool ignore_chunk_sizes = false;
            bool force = false;

#if FINETUNE
            int finetune_depth = -1;
#endif

            for (int arg = 0; arg < args.Length; arg++)
            {
                bool ok = true;
                try
                {
                    if (args[arg].Length == 0)
                    {
                        ok = false;
                    }
                    else if (args[arg] == "--debug")
                    {
                        debug = true;
                    }
                    else if ((args[arg] == "-f" || args[arg] == "--force"))
                    {
                        force = true;
                    }
                    else if ((args[arg] == "-q" || args[arg] == "--quiet"))
                    {
                        quiet = true;
                    }
                    else if ((args[arg] == "-V" || args[arg] == "--verify"))
                    {
                        settings.DoVerify = true;
                    }
                    else if (args[arg] == "--no-seektable")
                    {
                        do_seektable = false;
                    }
                    else if (args[arg] == "--ignore-chunk-sizes")
                    {
                        ignore_chunk_sizes = true;
                    }
                    else if (args[arg] == "--no-md5")
                    {
                        settings.DoMD5 = false;
                    }
                    else if (args[arg] == "--lax")
                    {
                        allowNonSubset = true;
                    }
                    else if (args[arg] == "--buffered")
                    {
                        buffered = true;
                    }
                    else if ((args[arg] == "-o" || args[arg] == "--output") && ++arg < args.Length)
                    {
                        output_file = args[arg];
                    }
                    else if ((args[arg] == "-T" || args[arg] == "--tag") && ++arg < args.Length)
                    {
                        var tags = settings.Tags != null ? new List <string>(settings.Tags) : new List <string>();
                        tags.Add(args[arg]);
                        settings.Tags = tags.ToArray();
                    }
                    else if ((args[arg] == "-t" || args[arg] == "--prediction-type") && ++arg < args.Length)
                    {
                        settings.PredictionType = FlakeConstants.LookupPredictionType(args[arg]);
                    }
                    else if ((args[arg] == "-s" || args[arg] == "--stereo") && ++arg < args.Length)
                    {
                        settings.StereoMethod = FlakeConstants.LookupStereoMethod(args[arg]);
                    }
                    else if ((args[arg] == "-m" || args[arg] == "--order-method") && ++arg < args.Length)
                    {
                        order_method = args[arg];
                    }
                    else if ((args[arg] == "-w" || args[arg] == "--window") && ++arg < args.Length)
                    {
                        settings.WindowFunctions = FlakeConstants.LookupWindowFunction(args[arg]);
                    }
                    else if (args[arg] == "--window-method" && ++arg < args.Length)
                    {
                        settings.WindowMethod = FlakeConstants.LookupWindowMethod(args[arg]);
                    }
                    else if ((args[arg] == "-r" || args[arg] == "--partition-order") && ++arg < args.Length)
                    {
                        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)
                    {
                        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)
                    {
                        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)
                    {
                        ok = (args[arg].Split(',').Length == 2 &&
                              int.TryParse(args[arg].Split(',')[0], out skip_a) &&
                              int.TryParse(args[arg].Split(',')[1], out skip_b)) ||
                             int.TryParse(args[arg], out skip_a);
                    }
                    else if ((args[arg] == "-e" || args[arg] == "--estimation-depth") && ++arg < args.Length)
                    {
                        settings.EstimationDepth = int.Parse(args[arg]);
                    }
                    else if (args[arg] == "--tukey-parts" && ++arg < args.Length)
                    {
                        settings.TukeyParts = int.Parse(args[arg]);
                    }
                    else if (args[arg] == "--tukey-overlap" && ++arg < args.Length)
                    {
                        settings.TukeyOverlap = double.Parse(args[arg]);
                    }
                    else if (args[arg] == "--tukey-p" && ++arg < args.Length)
                    {
                        settings.TukeyP = double.Parse(args[arg]);
                    }
                    else if ((args[arg] == "-c" || args[arg] == "--max-precision") && ++arg < args.Length)
                    {
                        int min_precision = -1, max_precision = -1;
                        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);
                        settings.MinPrecisionSearch = min_precision;
                        settings.MaxPrecisionSearch = max_precision;
                    }
                    else if (args[arg] == "--vbr")
                    {
                        ok = (++arg < args.Length) && int.TryParse(args[arg], out vbr_mode);
                    }
                    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))
                    {
                        settings.Padding = intarg;
                    }
                    else if (args[arg] == "--magic" && ++arg < args.Length)
                    {
                        ok = int.TryParse(args[arg], out magic);
                    }
#if FINETUNE
                    else if (args[arg] == "--depth" && ++arg < args.Length)
                    {
                        ok = int.TryParse(args[arg], out finetune_depth);
                    }
#endif
                    else if (args[arg] == "--coefs" && ++arg < args.Length)
                    {
                        coeffs = args[arg];
                    }
                    else if (args[arg] != "-" && args[arg][0] == '-' && int.TryParse(args[arg].Substring(1), out intarg))
                    {
                        ok = intarg >= 0 && intarg <= 11;
                        settings.SetEncoderModeIndex(intarg);
                    }
                    else if ((args[arg][0] != '-' || args[arg] == "-") && input_file == null)
                    {
                        input_file = args[arg];
                    }
                    else
                    {
                        ok = false;
                    }
                    if (!ok)
                    {
                        Usage();
                        return(1);
                    }
                }
                catch (Exception ex)
                {
                    Usage();
                    Console.WriteLine("");
                    Console.WriteLine("{0}: {1}", args[arg - 1], ex.Message);
                    return(5);
                }
            }
            if (input_file == null || ((input_file == "-" || Path.GetExtension(input_file) == ".flac") && output_file == null))
            {
                Usage();
                return(2);
            }

            if (!quiet)
            {
                Console.WriteLine("CUETools.Flake, Copyright (C) 2009-2014 Grigory Chudov.");
                Console.WriteLine("Initially based on Flake encoder by Justin Ruggles.");
                Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to");
                Console.WriteLine("the extent permitted by law. <http://www.gnu.org/licenses/> for details.");
            }

#if FINETUNE
            var prefix = new List <int>();
            if (coeffs != null)
            {
                var ps = coeffs.Split(',');
                for (int i = 0; i < ps.Length; i++)
                {
                    prefix.Add(ps[i].StartsWith("0x") ? int.Parse(ps[i].Substring(2), System.Globalization.NumberStyles.HexNumber) : int.Parse(ps[i]));
                }
            }
            string codefmt = "0x{0:x" + (max_lpc_order / 4 + 1).ToString() + "}";

            int max_prefix = magic >= 0 ? magic : 8;
            do
            {
                FineTuneTask best_task = null;
                var          tasks     = new Dictionary <int, FineTuneTask>();
                if (prefix.Count == 0)
                {
                    tasks.Add((1 << max_lpc_order) - 1, new FineTuneTask((1 << max_lpc_order) - 1, 1));
                    tasks.Add((2 << max_lpc_order) - 1, new FineTuneTask((2 << max_lpc_order) - 1, 2));
                    //tasks.Add((3 << max_lpc_order) - 1, new FineTuneTask((3 << max_lpc_order) - 1, 3));
                    //tasks.Add((4 << max_lpc_order) - 1, new FineTuneTask((4 << max_lpc_order) - 1, 4));
                }
                else
                {
                    foreach (var c in prefix)
                    {
                        tasks.Add(c, new FineTuneTask(c, 1));
                        tasks.Add((1 << max_lpc_order) ^ c, new FineTuneTask((1 << max_lpc_order) ^ c, 2));
                    }
                }
                int total_added_tasks = tasks.Values.Count;

                do
                {
                    foreach (var task in tasks.Values)
                    {
                        if (!task.done)
                        {
                            var prefixc = new List <int>(prefix);
                            prefixc.Add(task.code);
                            for (int i = 1; i < max_lpc_order; i++)
                            {
                                FlakeWriter.SetCoefs(i, new int[0]);
                            }
                            FlakeWriter.SetCoefs(max_lpc_order, prefixc.ToArray());
                            magic = prefixc.Count;
#endif

            IAudioSource audioSource;
            if (input_file == "-")
            {
                audioSource = new Codecs.WAV.AudioDecoder(new Codecs.WAV.DecoderSettings()
                {
                    IgnoreChunkSizes = ignore_chunk_sizes
                }
                                                          , "", Console.OpenStandardInput());
            }
            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")
            {
                audioSource = new Codecs.Flake.AudioDecoder(new Codecs.Flake.DecoderSettings(), input_file);
            }
            else
            {
                Usage();
                return(3);
            }

            if (buffered)
            {
                audioSource = new AudioPipe(audioSource, 0x10000);
            }
            if (output_file == null)
            {
                output_file = Path.ChangeExtension(input_file, "flac");
            }
            if (File.Exists(output_file) && !force)
            {
                Usage();
                Console.WriteLine();
                Console.WriteLine("File '{0}' already exists.", output_file);
                return(9);
            }
            settings.PCM            = audioSource.PCM;
            settings.AllowNonSubset = allowNonSubset;
            AudioEncoder flake;

            try
            {
                flake = new AudioEncoder(settings, (output_file == "-" || output_file == "nul") ? "" : output_file,
                                         output_file == "-" ? Console.OpenStandardOutput() :
                                         output_file == "nul" ? new NullStream() : null);
                flake.FinalSampleCount = audioSource.Length < 0 ? -1 : audioSource.Length - skip_a - skip_b;

                if (order_method != null)
                {
                    flake.OrderMethod = FlakeConstants.LookupOrderMethod(order_method);
                }
                if (vbr_mode >= 0)
                {
                    flake.VBRMode = vbr_mode;
                }
                if (magic >= 0)
                {
                    flake.DevelopmentMode = magic;
                }
                flake.DoSeekTable = do_seektable;
            }
            catch (Exception ex)
            {
                Usage();
                Console.WriteLine("");
                Console.WriteLine("Error: {0}.", ex.Message);
                return(4);
            }

            IAudioDest audioDest = flake;
            AudioBuffer buff     = new AudioBuffer(audioSource, 0x10000);

            if (!quiet)
            {
                Console.WriteLine("Filename  : {0}", input_file);
                Console.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, TimeSpan.FromSeconds(audioSource.Length * 1.0 / audioSource.PCM.SampleRate));
            }

            bool keepRunning = true;
            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                keepRunning = false;
                if (e.SpecialKey == ConsoleSpecialKey.ControlC)
                {
                    e.Cancel = true;
                }
                else
                {
                    audioDest.Delete();
                }
            };

            start = DateTime.Now;

#if !DEBUG
            try
#endif
            {
                audioSource.Position = skip_a;
                while (audioSource.Read(buff, skip_b == 0 ? -1 : (int)audioSource.Remaining - skip_b) != 0)
                {
                    audioDest.Write(buff);
                    TimeSpan elapsed = DateTime.Now - start;
                    if (!quiet)
                    {
                        if ((elapsed - lastPrint).TotalMilliseconds > 60)
                        {
                            long length = Math.Max(audioSource.Position, audioSource.Length);
                            Console.Error.Write("\rProgress  : {0:00}%; {1:0.00}x; {2}/{3}",
                                                100.0 * audioSource.Position / length,
                                                audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate,
                                                elapsed,//.ToString(@"[-][d’.’]hh’:’mm’:’ss[‘.’ff]"),
                                                TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * length)
                                                );
                            lastPrint = elapsed;
                        }
                    }
                    if (!keepRunning)
                    {
                        throw new Exception("Aborted");
                    }
                }
                audioDest.Close();
            }
#if !DEBUG
            catch (Exception ex)
            {
                Console.Error.Write("\r                                                                         \r");
                Console.WriteLine("Error     : {0}", ex.Message);
                audioDest.Delete();
                audioSource.Close();
                return(5);
            }
#endif

            TimeSpan totalElapsed = DateTime.Now - start;
            if (!quiet)
            {
                Console.Error.Write("\r                                                                         \r");
                Console.WriteLine("Results   : {0:0.00}x; {2} bytes in {1} seconds;",
                                  audioSource.Position / totalElapsed.TotalSeconds / audioSource.PCM.SampleRate,
                                  totalElapsed,
                                  flake.TotalSize
                                  );
            }
            audioSource.Close();

#if FINETUNE
            task.size = flake.TotalSize;
            Console.SetOut(stdout);
            Console.Out.WriteLine("{0}\t{1:0.00}\t{2}..{3}\t{4}\t{5}\t{6}/{7}\t{8}\t{9}\t{10}\t{11}",
                                  flake.TotalSize,
                                  flake.UserProcessorTime.TotalSeconds > 0 ? flake.UserProcessorTime.TotalSeconds : totalElapsed.TotalSeconds,
                                  flake.MinLPCOrder,
                                  flake.MaxLPCOrder,
                                  flake.BlockSize,
                                  task.gen,
                                  task.no.ToString().PadLeft(total_added_tasks.ToString().Length, '0'),
                                  total_added_tasks,
                                  task.min_depth,
                                  best_task != null && task.size < best_task.size ? "+" + (best_task.size - task.size).ToString() : task.IsImprovement ? "*" : "",
                                  string.Join(",", prefixc.ConvertAll(x => string.Format(codefmt, x)).ToArray()),
                                  string.Join(",", task.parents.ConvertAll(p => string.Format(codefmt, p.code)).ToArray())
                                  );
#else
            if (debug)
            {
                settings = flake.Settings as Codecs.Flake.EncoderSettings;
                Console.SetOut(stdout);
                Console.Out.WriteLine("{17}\t{0}\t{1:0.000}\t{2}\t{3}\t{4}\t{5}\t{6}..{7}\t{8}..{9}\t{10}..{11}\t{12}..{13}\t{14}\t{15}\t{16}\t{18}",
                                      flake.TotalSize,
                                      flake.UserProcessorTime.TotalSeconds > 0 ? flake.UserProcessorTime.TotalSeconds : totalElapsed.TotalSeconds,
                                      settings.PredictionType.ToString().PadRight(15),
                                      settings.StereoMethod.ToString().PadRight(15),
                                      (flake.OrderMethod.ToString() + "(" + settings.EstimationDepth.ToString() + ")").PadRight(15),
                                      (settings.WindowMethod.ToString().PadRight(10) + "(" +
                                       ((settings.WindowFunctions & WindowFunction.Tukey1X) != 0 ? "X" : (settings.WindowFunctions & WindowFunction.Tukey) != 0 ? "T" : (settings.WindowFunctions & WindowFunction.Tukey1A) != 0 ? "A" : (settings.WindowFunctions & WindowFunction.Tukey1B) != 0 ? "B" : " ") +
                                       ((settings.WindowFunctions & WindowFunction.Tukey2X) != 0 ? "X" : (settings.WindowFunctions & WindowFunction.Tukey2) != 0 ? "2" : (settings.WindowFunctions & WindowFunction.Tukey2A) != 0 ? "A" : (settings.WindowFunctions & WindowFunction.Tukey2B) != 0 ? "B" : " ") +
                                       ((settings.WindowFunctions & WindowFunction.Tukey3X) != 0 ? "X" : (settings.WindowFunctions & WindowFunction.Tukey3) != 0 ? "3" : (settings.WindowFunctions & WindowFunction.Tukey3A) != 0 ? "A" : (settings.WindowFunctions & WindowFunction.Tukey3B) != 0 ? "B" : " ") +
                                       ((settings.WindowFunctions & WindowFunction.Tukey4X) != 0 ? "X" : ((settings.WindowFunctions & WindowFunction.Tukey4) != 0 ? "4" : (settings.WindowFunctions & WindowFunction.Tukey4A) != 0 ? "A" : (settings.WindowFunctions & WindowFunction.Tukey4B) != 0 ? "B" : " ") +
                                        ((settings.WindowFunctions & WindowFunction.Welch) == 0 ? "" : "W") +
                                        ((settings.WindowFunctions & WindowFunction.Hann) == 0 ? "" : "H") +
                                        ((settings.WindowFunctions & WindowFunction.Flattop) == 0 ? "" : "F") +
                                        ((settings.WindowFunctions & WindowFunction.Bartlett) == 0 ? "" : "B")).PadRight(1))
                                      + ((settings.WindowFunctions & (WindowFunction.Tukey1X | WindowFunction.Tukey2X | WindowFunction.Tukey2X | WindowFunction.Tukey3X | WindowFunction.Tukey4X)) != 0 ?
                                         ("," + settings.TukeyOverlap.ToString("F3").PadLeft(6) + "," + settings.TukeyP.ToString("F3")) : "").PadRight(13)
                                      + ")",
                                      settings.MinPartitionOrder,
                                      settings.MaxPartitionOrder,
                                      settings.MinLPCOrder,
                                      settings.MaxLPCOrder,
                                      settings.MinFixedOrder,
                                      settings.MaxFixedOrder,
                                      settings.MinPrecisionSearch,
                                      settings.MaxPrecisionSearch,
                                      flake.Settings.BlockSize,
                                      flake.VBRMode,
                                      coeffs ?? "",
                                      audioSource.Position * audioSource.PCM.BlockAlign,
                                      settings.GuessEncoderMode().ToString().Replace("-1", "?")
                                      );
            }
#endif

#if FINETUNE
            if (best_task == null || task.size < best_task.size)
            {
                best_task = task;
            }
        }

        var promising_tasks = new List <FineTuneTask>();
        promising_tasks.AddRange(tasks.Values);
        promising_tasks.RemoveAll(task => !task.IsImprovement);
        promising_tasks.Sort((task1, task2) => task1.size.CompareTo(task2.size));
        if (finetune_depth >= 0 && promising_tasks.Count > finetune_depth)
        {
            promising_tasks.RemoveRange(finetune_depth, promising_tasks.Count - finetune_depth);
        }
        total_added_tasks = 0;
        foreach (var c in promising_tasks)
        {
            foreach (var c1 in c.GetDerivativeCodes(max_lpc_order))
            {
                if (!tasks.ContainsKey(c1))
                {
                    var new_task = new FineTuneTask(c1, ++total_added_tasks, c);
                    foreach (var c2 in new_task.GetDerivativeCodes(max_lpc_order))
                    {
                        if (tasks.ContainsKey(c2) && tasks[c2].done && !new_task.parents.Contains(tasks[c2]))
                        {
                            new_task.parents.Add(tasks[c2]);
                        }
                    }
                    new_task.min_depth = int.MaxValue;
                    foreach (var p in new_task.parents)
                        if (promising_tasks.IndexOf(p) >= 0)
                        {
                            new_task.min_depth = Math.Min(new_task.min_depth, Math.Max(p.min_depth, promising_tasks.IndexOf(p) + 1));
                        }
}
                    tasks.Add(c1, new_task);
                }
            }
        }
        if (total_added_tasks == 0)
        {
            break;
        }
    } while (true)
    {
        ;
    }

    prefix.Add(best_task.code);
} while (prefix.Count < max_prefix)
Exemplo n.º 2
0
        static int Main(string[] args)
        {
            TextWriter stdout = Console.Out;

            Console.SetOut(Console.Error);

            var settings = new Codecs.FLACCL.EncoderSettings()
            {
                AllowNonSubset = true
            };
            TimeSpan lastPrint = TimeSpan.FromMilliseconds(0);
            bool     debug = false, quiet = false;
            string   stereo_method = null;
            string   window_function = null;
            string   input_file = null;
            string   output_file = null;
            string   device_type = null;
            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;
            bool do_seektable    = true;
            bool estimate_window = false;
            bool buffered        = false;
            bool ok                 = true;
            bool allowNonSubset     = false;
            bool ignore_chunk_sizes = false;
            int  intarg;

            for (int arg = 0; arg < args.Length; arg++)
            {
                if (args[arg].Length == 0)
                {
                    ok = false;
                }
                else if (args[arg] == "--debug")
                {
                    debug = true;
                }
                else if ((args[arg] == "-q" || args[arg] == "--quiet"))
                {
                    quiet = true;
                }
                else if (args[arg] == "--verify")
                {
                    settings.DoVerify = true;
                }
                else if (args[arg] == "--no-seektable")
                {
                    do_seektable = false;
                }
                else if (args[arg] == "--ignore-chunk-sizes")
                {
                    ignore_chunk_sizes = true;
                }
                else if (args[arg] == "--slow-gpu")
                {
                    settings.GPUOnly = false;
                }
                else if (args[arg] == "--fast-gpu")
                {
                    settings.DoRice = true;
                }
                else if (args[arg] == "--no-md5")
                {
                    settings.DoMD5 = false;
                }
                else if (args[arg] == "--lax")
                {
                    allowNonSubset = true;
                }
                else if (args[arg] == "--buffered")
                {
                    buffered = true;
                }
                else if (args[arg] == "--cpu-threads")
                {
                    int val = settings.CPUThreads;
                    ok = (++arg < args.Length) && int.TryParse(args[arg], out val);
                    settings.CPUThreads = val;
                }
                else if (args[arg] == "--group-size" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    settings.GroupSize = intarg;
                }
                else if (args[arg] == "--task-size" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    settings.TaskSize = intarg;
                }
                else if (args[arg] == "--define" && arg + 2 < args.Length)
                {
                    settings.Defines += "#define " + args[++arg] + " " + args[++arg] + "\n";
                }
                else if (args[arg] == "--opencl-platform" && ++arg < args.Length)
                {
                    settings.Platform = args[arg];
                }
                else if (args[arg] == "--mapped-memory")
                {
                    settings.MappedMemory = true;
                }
                else if (args[arg] == "--opencl-type" && ++arg < args.Length)
                {
                    device_type = args[arg];
                }
                else if (args[arg] == "--input-length" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    input_len = intarg;
                }
                else if (args[arg] == "--input-value" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    input_val = intarg;
                }
                else if (args[arg] == "--input-bps" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    input_bps = intarg;
                }
                else if (args[arg] == "--input-channels" && ++arg < args.Length && int.TryParse(args[arg], out intarg))
                {
                    input_ch = intarg;
                }
                else if ((args[arg] == "-o" || args[arg] == "--output") && ++arg < args.Length)
                {
                    output_file = args[arg];
                }
                else if ((args[arg] == "-s" || args[arg] == "--stereo") && ++arg < args.Length)
                {
                    stereo_method = args[arg];
                }
                else if ((args[arg] == "-w" || args[arg] == "--window") && ++arg < args.Length)
                {
                    window_function = args[arg];
                }
                else if ((args[arg] == "-r" || args[arg] == "--partition-order") && ++arg < args.Length)
                {
                    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)
                {
                    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)
                {
                    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))
                {
                    settings.Padding = intarg;
                }
                else if (args[arg] != "-" && args[arg][0] == '-' && int.TryParse(args[arg].Substring(1), out level))
                {
                    ok = level >= 0 && level <= 11;
                    settings.SetEncoderModeIndex(level);
                }
                else if ((args[arg][0] != '-' || args[arg] == "-") && input_file == null)
                {
                    input_file = args[arg];
                }
                else
                {
                    ok = false;
                }
                if (!ok)
                {
                    break;
                }
            }
            if (!quiet)
            {
                Console.WriteLine("{0}, Copyright (C) 2010-2021 Grigory Chudov.", Codecs.FLACCL.AudioEncoder.Vendor);
                Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to");
                Console.WriteLine("the extent permitted by law. <http://www.gnu.org/licenses/> for details.");
            }
            if (!ok || input_file == null)
            {
                Usage();
                return(1);
            }

            if (((input_file == "-" || Path.GetExtension(input_file) == ".flac") && output_file == null))
            {
                Usage();
                Console.WriteLine();
                Console.WriteLine("Output file not specified.");
                return(2);
            }

            IAudioSource audioSource;

            try
            {
                if (input_file == "-")
                {
                    audioSource = new Codecs.WAV.AudioDecoder(new Codecs.WAV.DecoderSettings()
                    {
                        IgnoreChunkSizes = true
                    }, "", Console.OpenStandardInput());
                }
                else if (input_file == "nul")
                {
                    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")
                {
                    audioSource = new AudioDecoder(new DecoderSettings(), input_file);
                }
                else
                {
                    Usage();
                    Console.WriteLine();
                    Console.WriteLine("Input file \"{0}\" does not exist.", input_file);
                    return(2);
                }
            }
            catch (Exception ex)
            {
                Usage();
                Console.WriteLine("");
                Console.WriteLine("Error: {0}.", ex.Message);
                return(3);
            }
            if (buffered)
            {
                audioSource = new AudioPipe(audioSource, Codecs.FLACCL.AudioEncoder.MAX_BLOCKSIZE);
            }
            if (output_file == null)
            {
                output_file = Path.ChangeExtension(input_file, "flac");
            }
            settings.PCM            = audioSource.PCM;
            settings.AllowNonSubset = allowNonSubset;
            Codecs.FLACCL.AudioEncoder encoder;

            try
            {
                if (device_type != null)
                {
                    settings.DeviceType = (OpenCLDeviceType)(Enum.Parse(typeof(OpenCLDeviceType), device_type, true));
                }
                encoder = new Codecs.FLACCL.AudioEncoder((output_file == "-" || output_file == "nul") ? "" : output_file,
                                                         output_file == "-" ? Console.OpenStandardOutput() :
                                                         output_file == "nul" ? new NullStream() : null,
                                                         settings);
                settings = encoder.Settings as Codecs.FLACCL.EncoderSettings;
                encoder.FinalSampleCount = audioSource.Length;
                if (stereo_method != null)
                {
                    encoder.StereoMethod = FlakeConstants.LookupStereoMethod(stereo_method);
                }
                if (window_function != null)
                {
                    encoder.WindowFunction = FlakeConstants.LookupWindowFunction(window_function);
                }
                if (max_precision >= 0)
                {
                    encoder.MaxPrecisionSearch = max_precision;
                }
                if (min_precision >= 0)
                {
                    encoder.MinPrecisionSearch = min_precision;
                }
                if (vbr_mode >= 0)
                {
                    encoder.VBRMode = vbr_mode;
                }
                if (orders_per_window >= 0)
                {
                    encoder.OrdersPerWindow = orders_per_window;
                }
                if (orders_per_channel >= 0)
                {
                    encoder.OrdersPerChannel = orders_per_channel;
                }
                if (estimate_window)
                {
                    encoder.EstimateWindow = estimate_window;
                }
                encoder.DoSeekTable = do_seektable;
            }
            catch (Exception ex)
            {
                Usage();
                Console.WriteLine("");
                Console.WriteLine("Error: {0}.", ex.Message);
                return(3);
            }

            IAudioDest  audioDest = encoder;
            AudioBuffer buff      = new AudioBuffer(audioSource, Codecs.FLACCL.AudioEncoder.MAX_BLOCKSIZE);

            if (!quiet)
            {
                Console.WriteLine("Filename  : {0}", input_file);
                Console.WriteLine("File Info : {0} Hz; {1} channel; {2} bit; {3}", audioSource.PCM.SampleRate, audioSource.PCM.ChannelCount, audioSource.PCM.BitsPerSample, TimeSpan.FromSeconds(audioSource.Length * 1.0 / audioSource.PCM.SampleRate));
                Console.WriteLine("Device    : {0}, Platform: \"{1}\", Version: {2}, Driver: {3}", settings.Device.Trim(), settings.Platform, settings.PlatformVersion.Trim(), settings.DriverVersion.Trim());
            }

            bool keepRunning = true;

            Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e)
            {
                keepRunning = false;
                if (e.SpecialKey == ConsoleSpecialKey.ControlC)
                {
                    e.Cancel = true;
                }
                else
                {
                    audioDest.Delete();
                }
            };

            DateTime start = DateTime.Now;

            try
            {
                audioDest.Write(buff);
                start = DateTime.Now;
                while (audioSource.Read(buff, -1) != 0)
                {
                    audioDest.Write(buff);
                    TimeSpan elapsed = DateTime.Now - start;
                    if (!quiet)
                    {
                        if ((elapsed - lastPrint).TotalMilliseconds > 60)
                        {
                            long length = Math.Max(audioSource.Position, audioSource.Length);
                            Console.Error.Write("\rProgress  : {0:00}%; {1:0.00}x; {2}/{3}",
                                                100.0 * audioSource.Position / length,
                                                audioSource.Position / elapsed.TotalSeconds / audioSource.PCM.SampleRate,
                                                elapsed,
                                                TimeSpan.FromMilliseconds(elapsed.TotalMilliseconds / audioSource.Position * length)
                                                );
                            lastPrint = elapsed;
                        }
                    }
                    if (!keepRunning)
                    {
                        throw new Exception("Aborted");
                    }
                }
                audioDest.Close();
            }
            catch (OpenCLNet.OpenCLBuildException ex)
            {
                Console.Error.Write("\r                                                                         \r");
                Console.WriteLine("Error     : {0}", ex.Message);
                Console.WriteLine("{0}", ex.BuildLogs[0]);
                if (debug)
                {
                    using (StreamWriter sw = new StreamWriter("debug.txt", true))
                        sw.WriteLine("{0}\n{1}\n{2}", ex.Message, ex.StackTrace, ex.BuildLogs[0]);
                }
                audioDest.Delete();
                audioSource.Close();
                return(4);
            }
#if !DEBUG
            catch (Exception ex)
            {
                Console.Error.Write("\r                                                                         \r");
                Console.WriteLine("Error     : {0}", ex.Message);
                if (debug)
                {
                    using (StreamWriter sw = new StreamWriter("debug.txt", true))
                        sw.WriteLine("{0}\n{1}", ex.Message, ex.StackTrace);
                }
                audioDest.Delete();
                audioSource.Close();
                return(4);
            }
#endif

            TimeSpan totalElapsed = DateTime.Now - start;
            if (!quiet)
            {
                Console.Error.Write("\r                                                                         \r");
                Console.WriteLine("Results   : {0:0.00}x; {2} bytes in {1} seconds;",
                                  audioSource.Position / totalElapsed.TotalSeconds / audioSource.PCM.SampleRate,
                                  totalElapsed,
                                  encoder.TotalSize
                                  );
            }
            audioSource.Close();

            if (debug)
            {
                Console.SetOut(stdout);
                Console.Out.WriteLine("{0}\t{1}\t{2}\t{3}\t{4} ({5})\t{6}/{7}+{12}{13}\t{8}..{9}\t{10}\t{11}",
                                      encoder.TotalSize,
                                      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),
                                      settings.MaxPartitionOrder,
                                      settings.GPUOnly ? "GPU" : "CPU",
                                      encoder.OrdersPerWindow,
                                      settings.MaxLPCOrder,
                                      encoder.MinPrecisionSearch,
                                      encoder.MaxPrecisionSearch,
                                      encoder.Settings.BlockSize,
                                      encoder.VBRMode,
                                      settings.MaxFixedOrder - settings.MinFixedOrder + 1,
                                      encoder.DoConstant ? "c" : ""
                                      );
            }
            return(0);
        }