예제 #1
0
        public IEnumerable <string> Dump(Song song, Action <double> onProgress)
        {
            var args = new StringBuilder($"\"{song.Filename}\" {song.Index}");

            AddArgIfSupported(args, "sampling_rate", _samplingRate);
            AddArgIfSupported(args, "fade_length", _fadeMs);
            AddArgIfSupported(args, "loop_count", _loopCount);
            AddArgIfSupported(args, "gap_length", _gapMs);
            if (song.ForceLength > TimeSpan.Zero)
            {
                AddArgIfSupported(args, "play_length", (long)song.ForceLength.TotalMilliseconds);
            }

            _processWrapper = new ProcessWrapper(
                _multiDumperPath,
                args.ToString());
            var progressParts = Enumerable.Repeat(0.0, song.Channels.Count).ToList();
            var r             = new Regex(@"(?<channel>\d+)\|(?<position>\d+)\|(?<total>\d+)");
            var stopwatch     = Stopwatch.StartNew();

            foreach (var match in _processWrapper.Lines().Select(l => r.Match(l)).Where(m => m.Success))
            {
                var channel = Convert.ToInt32(match.Groups["channel"].Value);
                if (channel < 0 || channel > song.Channels.Count)
                {
                    continue;
                }

                var position = Convert.ToDouble(match.Groups["position"].Value);
                var total    = Convert.ToDouble(match.Groups["total"].Value);
                progressParts[channel] = position / total;
                if (stopwatch.Elapsed.TotalMilliseconds > 100)
                {
                    // Update the progress every 100ms
                    onProgress?.Invoke(progressParts.Average());
                    stopwatch.Restart();
                }
            }
            _processWrapper.Dispose();
            _processWrapper = null;

            onProgress?.Invoke(1.0);

            var baseName = Path.Combine(
                Path.GetDirectoryName(song.Filename) ?? "",
                Path.GetFileNameWithoutExtension(song.Filename));

            return(song.Channels.Select(channel => $"{baseName} - {channel}.wav"));
        }
예제 #2
0
 private string GetOutputText(string args, bool includeStdErr)
 {
     using (var p = new ProcessWrapper(
                _multiDumperPath,
                args,
                includeStdErr))
     {
         string text = string.Join("", p.Lines());
         // Try to decode any UTF-8 in there
         try
         {
             text = Encoding.UTF8.GetString(Encoding.Default.GetBytes(text));
         }
         catch (Exception)
         {
             // Ignore it, use unfixed string
         }
         return(text);
     }
 }
예제 #3
0
        public IEnumerable <string> Dump(Song song, Action <double> onProgress)
        {
            _processWrapper = new ProcessWrapper(
                _multiDumperPath,
                $"\"{song.Filename}\" {song.Index}");
            var progressParts = Enumerable.Repeat(0.0, song.Channels.Count).ToList();
            var r             = new Regex(@"(?<channel>\d+)\|(?<position>\d+)\|(?<total>\d+)");
            var stopwatch     = Stopwatch.StartNew();

            foreach (var match in _processWrapper.Lines().Select(l => r.Match(l)).Where(m => m.Success))
            {
                var channel = Convert.ToInt32(match.Groups["channel"].Value);
                if (channel < 0 || channel > song.Channels.Count)
                {
                    continue;
                }

                var position = Convert.ToDouble(match.Groups["position"].Value);
                var total    = Convert.ToDouble(match.Groups["total"].Value);
                progressParts[channel] = position / total;
                if (stopwatch.Elapsed.TotalMilliseconds > 100)
                {
                    // Update the progress every 100ms
                    onProgress?.Invoke(progressParts.Average());
                    stopwatch.Restart();
                }
            }
            _processWrapper.Dispose();
            _processWrapper = null;

            onProgress?.Invoke(1.0);

            var baseName = Path.Combine(
                Path.GetDirectoryName(song.Filename),
                Path.GetFileNameWithoutExtension(song.Filename));

            return(song.Channels.Select(channel => $"{baseName} - {channel}.wav"));
        }
예제 #4
0
        public IEnumerable <Song> GetSongs(string filename)
        {
            filename = Path.GetFullPath(filename);

            if (!File.Exists(filename))
            {
                throw new FileNotFoundException("Cannot find VGM file", filename);
            }

            string json;

            using (var p = new ProcessWrapper(
                       _multiDumperPath,
                       $"\"{filename}\" --json"))
            {
                json = string.Join("", p.Lines());
            }

            if (string.IsNullOrEmpty(json))
            {
                throw new Exception("Failed to get song data from MultiDumper");
            }

            // Extract metadata
            // Example result:
            // {
            //  "channels":[
            //      "SEGA PSG #0","SEGA PSG #1","SEGA PSG #2","SEGA PSG #3",
            //      "YM2413 #0","YM2413 #1","YM2413 #2","YM2413 #3","YM2413 #4","YM2413 #5","YM2413 #6",
            //      "YM2413 #7","YM2413 #8","YM2413 #9","YM2413 #10","YM2413 #11","YM2413 #12","YM2413 #13"],
            //  "containerinfo":
            //  {
            //      "copyright":"1988/08/14",
            //      "dumper":"sherpa",
            //      "game":"Golvellius - Valley of Doom",
            //      "system":"Sega Master System"
            //  },
            //  "songs":[
            //      {
            //          "author":"Masatomo Miyamoto, Takeshi Santo, Shin-kun, Pazu",
            //          "comment":"",
            //          "name":"Title Screen"
            //      }],
            //  "subsongCount":1
            // }
            dynamic metadata = JsonConvert.DeserializeObject(json);

            var channels = metadata.channels.ToObject <List <string> >();
            var songs    = (JArray)metadata.songs;
            var i        = 0;

            // This helps us reject any junk strings MultiDumper gives us for empty tags
            string Clean(string s) => string.IsNullOrEmpty(s) || s.Any(char.IsControl) ? string.Empty : s;

            return(songs.Cast <dynamic>().Select(s => new Song
            {
                Filename = filename,
                Index = i++,
                Name = Clean(s.name),
                Author = Clean(s.author),
                Channels = channels,
                Comment = Clean(s.comment),
                Copyright = Clean(metadata.containerinfo.copyright),
                Dumper = Clean(metadata.containerinfo.dumper),
                Game = Clean(metadata.containerinfo.game),
                System = Clean(metadata.containerinfo.system)
            }));
        }