static void Main(string[] args) { try { var settings = new Settings(); // ReSharper disable once RedundantNameQualifier using (var parser = new CommandLine.Parser(x => { x.CaseSensitive = false; x.IgnoreUnknownArguments = true; })) { if (!parser.ParseArguments(args, settings)) { Console.Error.WriteLine(settings.GetUsage()); return; } } if (!settings.YouTubeOnly) { if (settings.InputFiles == null) { RunMultiDumper(ref settings); } else { // We want to expand any wildcards in the input file list (and also fully qualify them) var inputs = new List <string>(); foreach (var inputFile in settings.InputFiles) { if (File.Exists(inputFile)) { inputs.Add(Path.GetFullPath(inputFile)); continue; } var pattern = Path.GetFileName(inputFile); if (pattern == null) { throw new Exception($"Failed to match {inputFile}"); } var pathPart = inputFile.Substring(0, inputFile.Length - pattern.Length); var directory = pathPart.Length > 0 ? Path.GetFullPath(pathPart) : Directory.GetCurrentDirectory(); var files = Directory.EnumerateFiles(directory, pattern).ToList(); if (files.Count == 0) { throw new Exception($"Failed to match {inputFile}"); } inputs.AddRange(files.OrderByAlphaNumeric(x => x)); } settings.InputFiles = inputs; } if (settings.InputFiles == null || !settings.InputFiles.Any()) { Console.Error.WriteLine(settings.GetUsage()); throw new Exception("No inputs specified"); } var channels = settings.InputFiles .AsParallel() .Select(filename => { var channel = new Channel { Filename = filename, LineColor = ParseColor(settings.LineColor), LineWidth = settings.LineWidth, FillColor = ParseColor(settings.FillColor), Label = Channel.GuessNameFromMultidumperFilename(filename), Algorithm = CreateTriggerAlgorithm(settings.TriggerAlgorithm), TriggerLookaheadFrames = settings.TriggerLookahead, ZeroLineWidth = settings.ZeroLineWidth, ZeroLineColor = ParseColor(settings.ZeroLineColor), LabelFont = settings.ChannelLabelsFont == null ? null : new Font(settings.ChannelLabelsFont, settings.ChannelLabelsSize), LabelColor = ParseColor(settings.ChannelLabelsColor), HighPassFilter = settings.HighPass }; channel.LoadDataAsync().Wait(); channel.ViewWidthInMilliseconds = settings.ViewWidthMs; return(channel); }).Where(ch => ch.SampleCount > 0).ToList(); if (settings.AutoScalePercentage > 0) { float max; bool IsYm2413Percussion(Channel ch) => ch.Label.StartsWith("YM2413 ") && !ch.Label.StartsWith("YM2413 Tone"); if (settings.AutoScaleIgnoreYM2413Percussion) { var channelsToUse = channels.Where(channel => !IsYm2413Percussion(channel)).ToList(); if (channelsToUse.Count == 0) { // Fall back on overall max if all channels are percussion max = channels.Max(ch => ch.Max); } else { max = channelsToUse.Max(ch => ch.Max); } } else { max = channels.Max(ch => ch.Max); } var scale = settings.AutoScalePercentage / 100 / max; foreach (var channel in channels) { channel.Scale = scale; } } if (settings.ChannelLabelsFromVgm && settings.VgmFile != null) { TryGuessLabelsFromVgm(channels, settings.VgmFile); } if (settings.OutputFile != null) { // Emit normalized data to a WAV file for later mixing if (settings.MasterAudioFile == null && !settings.NoMasterMix) { settings.MasterAudioFile = settings.OutputFile + ".wav"; Mixer.MixToFile(channels, settings.MasterAudioFile, !settings.NoMasterMixReplayGain); } } Render(settings, channels); foreach (var channel in channels) { channel.Dispose(); } } if (settings.YouTubeTitle != null) { UploadToYouTube(settings).Wait(); } } catch (Exception e) { Console.Error.WriteLine($"Fatal: {e}"); } }