public static MergedBin MergeBins(string file, IEnumerable <CueFile> cueFiles, string tempPath)
        {
            var mergedBin = new MergedBin();

            mergedBin.CueFiles = new List <CueFile>();

            Console.WriteLine($"Merging .bins...");
            long currentFrame = 0;

            var mergedFilename = Path.GetFileNameWithoutExtension(file) + " - MERGED.bin";

            mergedBin.Path = Path.Combine(tempPath, mergedFilename);

            var mcueFile = new CueFile()
            {
                FileName = mergedFilename,
                FileType = "BINARY",
                Tracks   = new List <CueTrack>()
            };

            mergedBin.CueFiles.Add(mcueFile);

            using (var joinedFile = new FileStream(mergedBin.Path, FileMode.Create))
            {
                foreach (var cueFile in cueFiles)
                {
                    using (var srcStream = new FileStream(Path.Combine(tempPath, cueFile.FileName), FileMode.Open))
                    {
                        srcStream.CopyTo(joinedFile);

                        foreach (var item in cueFile.Tracks)
                        {
                            var indexes = new List <CueIndex>();
                            foreach (var idx in item.Indexes)
                            {
                                var newIndex = new CueIndex();
                                newIndex.Number   = idx.Number;
                                newIndex.Position = idx.Position + Helper.PositionFromFrames(currentFrame);
                                indexes.Add(newIndex);
                            }
                            var newTrack = new CueTrack()
                            {
                                DataType = item.DataType,
                                Number   = item.Number,
                                Indexes  = indexes
                            };
                            mcueFile.Tracks.Add(newTrack);
                        }

                        var frames = srcStream.Length / 2352;
                        currentFrame += frames;
                    }
                }
            }

            return(mergedBin);
        }
Beispiel #2
0
        public static CueFile TOCtoCUE(List <TOCEntry> tocEntries, string dataPath)
        {
            var cueFile = new CueFileEntry()
            {
                FileName = dataPath,
                Tracks   = new List <CueTrack>(),
                FileType = "BINARY"
            };

            var audioLeadin = new IndexPosition {
                Seconds = 2
            };

            foreach (var track in tocEntries)
            {
                var position = new IndexPosition
                {
                    Minutes = track.Minutes,
                    Seconds = track.Seconds,
                    Frames  = track.Frames,
                };

                var indexes = new List <CueIndex>();

                if (track.TrackType == TrackTypeEnum.Audio)
                {
                    indexes.Add(new CueIndex()
                    {
                        Number   = 0,
                        Position = position - audioLeadin,
                    });
                }

                indexes.Add(new CueIndex()
                {
                    Number   = 1,
                    Position = position,
                });

                var cueTrack = new CueTrack()
                {
                    DataType = GetDataType(track.TrackType),
                    Indexes  = indexes,
                    Number   = track.TrackNo
                };


                cueFile.Tracks.Add(cueTrack);
            }

            return(new CueFile(new[] { cueFile }));
        }
Beispiel #3
0
        string crushedTrackPath;  // Autocalculated

        // --
        public TaskRestoreTrack(CueTrack tr)
        {
            name  = "Restore";
            desc  = string.Format("Restoring track {0}", tr.trackNo);
            track = tr;
        }// -----------------------------------------
Beispiel #4
0
        static MergedBin MergeBins(string file, CueFile cueFilex, string tempPath)
        {
            var mergedBin = new MergedBin();

            mergedBin.CueFile = new CueFile();

            var cueFilePath = Path.GetDirectoryName(file);


            long currentFrame = 0;

            var mergedFilename = Path.GetFileNameWithoutExtension(file) + " - MERGED.bin";

            mergedBin.Path = Path.Combine(tempPath, mergedFilename);

            var mcueFile = new CueFileEntry()
            {
                FileName = mergedFilename,
                FileType = "BINARY",
                Tracks   = new List <CueTrack>()
            };

            mergedBin.CueFile.FileEntries.Add(mcueFile);

            using (var joinedFile = new FileStream(mergedBin.Path, FileMode.Create))
            {
                foreach (var cueFileEntry in cueFilex.FileEntries)
                {
                    var binPath = cueFileEntry.FileName;
                    if (Path.GetDirectoryName(binPath) == "" || Path.GetDirectoryName(binPath).StartsWith("..") || Path.GetDirectoryName(binPath).StartsWith("."))
                    {
                        binPath = Path.Combine(cueFilePath, cueFileEntry.FileName);
                    }

                    using (var srcStream = new FileStream(binPath, FileMode.Open))
                    {
                        srcStream.CopyTo(joinedFile);

                        foreach (var item in cueFileEntry.Tracks)
                        {
                            var indexes = new List <CueIndex>();
                            foreach (var idx in item.Indexes)
                            {
                                var newIndex = new CueIndex
                                {
                                    Number   = idx.Number,
                                    Position = idx.Position + TOCHelper.PositionFromFrames(currentFrame)
                                };
                                indexes.Add(newIndex);
                            }
                            var newTrack = new CueTrack()
                            {
                                DataType = item.DataType,
                                Number   = item.Number,
                                Indexes  = indexes
                            };
                            mcueFile.Tracks.Add(newTrack);
                        }

                        var frames = srcStream.Length / 2352;
                        currentFrame += frames;
                    }
                }
            }

            return(mergedBin);
        }
Beispiel #5
0
		public void LoadFromString(string cueString)
		{
			TextReader tr = new StringReader(cueString);

			bool track_has_pregap = false;
			bool track_has_postgap = false;
			int last_index_num = -1;
			CueFile currFile = null;
			CueTrack currTrack = null;
			for (; ; )
			{
				string line = tr.ReadLine();
				if (line == null) break;
				line = line.Trim();
				if (line == "") continue;
				var clp = new CueLineParser(line);

				string key = clp.ReadToken().ToUpper();
				switch (key)
				{
					case "REM":
						break;

					case "FILE":
						{
							currTrack = null;
							currFile = new CueFile();
							Files.Add(currFile);
							currFile.Path = clp.ReadPath().Trim('"');
							if (!clp.EOF)
							{
								string temp = clp.ReadToken().ToUpper();
								switch (temp)
								{
									case "BINARY":
										currFile.FileType = CueFileType.Binary;
										break;
									case "WAVE":
									case "MP3":
										currFile.FileType = CueFileType.Wave;
										break;
								}
								currFile.StrFileType = temp;
							}
							break;
						}
					case "TRACK":
						{
							if (currFile == null) throw new CueBrokenException("invalid cue structure");
							if (clp.EOF) throw new CueBrokenException("invalid cue structure");
							string strtracknum = clp.ReadToken();
							int tracknum;
							if (!int.TryParse(strtracknum, out tracknum))
								throw new CueBrokenException("malformed track number");
							if (clp.EOF) throw new CueBrokenException("invalid cue structure");
							if (tracknum < 0 || tracknum > 99) throw new CueBrokenException("`All track numbers must be between 1 and 99 inclusive.`");
							string strtracktype = clp.ReadToken().ToUpper();
							currTrack = new CueTrack();
							switch (strtracktype)
							{
								case "MODE1/2352": currTrack.TrackType = ETrackType.Mode1_2352; break;
								case "MODE1/2048": currTrack.TrackType = ETrackType.Mode1_2048; break;
								case "MODE2/2352": currTrack.TrackType = ETrackType.Mode2_2352; break;
								case "AUDIO": currTrack.TrackType = ETrackType.Audio; break;
								default:
									throw new CueBrokenException("unhandled track type");
							}
							currTrack.TrackNum = tracknum;
							currFile.Tracks.Add(currTrack);
							track_has_pregap = false;
							track_has_postgap = false;
							last_index_num = -1;
							break;
						}
					case "INDEX":
						{
							if (currTrack == null) throw new CueBrokenException("invalid cue structure");
							if (clp.EOF) throw new CueBrokenException("invalid cue structure");
							if (track_has_postgap) throw new CueBrokenException("`The POSTGAP command must appear after all INDEX commands for the current track.`");
							string strindexnum = clp.ReadToken();
							int indexnum;
							if (!int.TryParse(strindexnum, out indexnum))
								throw new CueBrokenException("malformed index number");
							if (clp.EOF) throw new CueBrokenException("invalid cue structure (missing index timestamp)");
							string str_timestamp = clp.ReadToken();
							if (indexnum < 0 || indexnum > 99) throw new CueBrokenException("`All index numbers must be between 0 and 99 inclusive.`");
							if (indexnum != 1 && indexnum != last_index_num + 1) throw new CueBrokenException("`The first index must be 0 or 1 with all other indexes being sequential to the first one.`");
							last_index_num = indexnum;
							CueTrackIndex cti = new CueTrackIndex(indexnum)
								{
									Timestamp = new Timestamp(str_timestamp), IndexNum = indexnum
								};
							currTrack.Indexes[indexnum] = cti;
							break;
						}
					case "PREGAP":
						if (track_has_pregap) throw new CueBrokenException("`Only one PREGAP command is allowed per track.`");
						if (currTrack.Indexes.Count > 0) throw new CueBrokenException("`The PREGAP command must appear after a TRACK command, but before any INDEX commands.`");
						currTrack.PreGap = new Timestamp(clp.ReadToken());
						track_has_pregap = true;
						break;
					case "POSTGAP":
						if (track_has_postgap) throw new CueBrokenException("`Only one POSTGAP command is allowed per track.`");
						track_has_postgap = true;
						currTrack.PostGap = new Timestamp(clp.ReadToken());
						break;
					case "CATALOG":
					case "PERFORMER":
					case "SONGWRITER":
					case "TITLE":
					case "ISRC":
						//TODO - keep these for later?
						break;
					default:
						throw new CueBrokenException("unsupported cue command: " + key);
				}
			} //end cue parsing loop
		}
Beispiel #6
0
        public void LoadFromString(string cueString)
        {
            TextReader tr = new StringReader(cueString);

            bool     track_has_pregap  = false;
            bool     track_has_postgap = false;
            int      last_index_num    = -1;
            CueFile  currFile          = null;
            CueTrack currTrack         = null;

            for (; ;)
            {
                string line = tr.ReadLine();
                if (line == null)
                {
                    break;
                }
                line = line.Trim();
                if (line == "")
                {
                    continue;
                }
                var clp = new CueLineParser(line);

                string key = clp.ReadToken().ToUpper();
                switch (key)
                {
                case "REM":
                    break;

                case "FILE":
                {
                    currTrack = null;
                    currFile  = new CueFile();
                    Files.Add(currFile);
                    currFile.Path = clp.ReadPath().Trim('"');
                    if (!clp.EOF)
                    {
                        string temp = clp.ReadToken().ToUpper();
                        switch (temp)
                        {
                        case "BINARY":
                            currFile.FileType = CueFileType.Binary;
                            break;

                        case "WAVE":
                        case "MP3":
                            currFile.FileType = CueFileType.Wave;
                            break;
                        }
                        currFile.StrFileType = temp;
                    }
                    break;
                }

                case "TRACK":
                {
                    if (currFile == null)
                    {
                        throw new CueBrokenException("invalid cue structure");
                    }
                    if (clp.EOF)
                    {
                        throw new CueBrokenException("invalid cue structure");
                    }
                    string strtracknum = clp.ReadToken();
                    int    tracknum;
                    if (!int.TryParse(strtracknum, out tracknum))
                    {
                        throw new CueBrokenException("malformed track number");
                    }
                    if (clp.EOF)
                    {
                        throw new CueBrokenException("invalid cue structure");
                    }
                    if (tracknum < 0 || tracknum > 99)
                    {
                        throw new CueBrokenException("`All track numbers must be between 1 and 99 inclusive.`");
                    }
                    string strtracktype = clp.ReadToken().ToUpper();
                    currTrack = new CueTrack();
                    switch (strtracktype)
                    {
                    case "MODE1/2352": currTrack.TrackType = ETrackType.Mode1_2352; break;

                    case "MODE1/2048": currTrack.TrackType = ETrackType.Mode1_2048; break;

                    case "MODE2/2352": currTrack.TrackType = ETrackType.Mode2_2352; break;

                    case "AUDIO": currTrack.TrackType = ETrackType.Audio; break;

                    default:
                        throw new CueBrokenException("unhandled track type");
                    }
                    currTrack.TrackNum = tracknum;
                    currFile.Tracks.Add(currTrack);
                    track_has_pregap  = false;
                    track_has_postgap = false;
                    last_index_num    = -1;
                    break;
                }

                case "INDEX":
                {
                    if (currTrack == null)
                    {
                        throw new CueBrokenException("invalid cue structure");
                    }
                    if (clp.EOF)
                    {
                        throw new CueBrokenException("invalid cue structure");
                    }
                    if (track_has_postgap)
                    {
                        throw new CueBrokenException("`The POSTGAP command must appear after all INDEX commands for the current track.`");
                    }
                    string strindexnum = clp.ReadToken();
                    int    indexnum;
                    if (!int.TryParse(strindexnum, out indexnum))
                    {
                        throw new CueBrokenException("malformed index number");
                    }
                    if (clp.EOF)
                    {
                        throw new CueBrokenException("invalid cue structure (missing index timestamp)");
                    }
                    string str_timestamp = clp.ReadToken();
                    if (indexnum < 0 || indexnum > 99)
                    {
                        throw new CueBrokenException("`All index numbers must be between 0 and 99 inclusive.`");
                    }
                    if (indexnum != 1 && indexnum != last_index_num + 1)
                    {
                        throw new CueBrokenException("`The first index must be 0 or 1 with all other indexes being sequential to the first one.`");
                    }
                    last_index_num = indexnum;
                    CueTrackIndex cti = new CueTrackIndex(indexnum)
                    {
                        Timestamp = new Timestamp(str_timestamp), IndexNum = indexnum
                    };
                    currTrack.Indexes[indexnum] = cti;
                    break;
                }

                case "PREGAP":
                    if (track_has_pregap)
                    {
                        throw new CueBrokenException("`Only one PREGAP command is allowed per track.`");
                    }
                    if (currTrack.Indexes.Count > 0)
                    {
                        throw new CueBrokenException("`The PREGAP command must appear after a TRACK command, but before any INDEX commands.`");
                    }
                    currTrack.PreGap = new Timestamp(clp.ReadToken());
                    track_has_pregap = true;
                    break;

                case "POSTGAP":
                    if (track_has_postgap)
                    {
                        throw new CueBrokenException("`Only one POSTGAP command is allowed per track.`");
                    }
                    track_has_postgap = true;
                    currTrack.PostGap = new Timestamp(clp.ReadToken());
                    break;

                case "CATALOG":
                case "PERFORMER":
                case "SONGWRITER":
                case "TITLE":
                case "ISRC":
                    //TODO - keep these for later?
                    break;

                default:
                    throw new CueBrokenException("unsupported cue command: " + key);
                }
            }             //end cue parsing loop
        }
        string sourceTrackFile;  // Temp name, Autocalculated

        // --
        public TaskCompressTrack(CueTrack tr) : base(null, "Encoding")
        {
            name  = "Compress";
            desc  = string.Format("Encoding track {0}", tr.trackNo);
            track = tr;
        }// -----------------------------------------
Beispiel #8
0
        public void ExtractMKVSegments(String argMKVFile, List <gMKVSegment> argMKVSegmentsToExtract,
                                       String argOutputDirectory, MkvChapterTypes argChapterType, TimecodesExtractionMode argTimecodesExtractionMode, CuesExtractionMode argCueExtractionMode)
        {
            _Abort                   = false;
            _AbortAll                = false;
            _ErrorBuilder.Length     = 0;
            _MKVExtractOutput.Length = 0;
            // Analyze the MKV segments and get the initial parameters
            List <TrackParameter> initialParameters = new List <TrackParameter>();

            foreach (gMKVSegment seg in argMKVSegmentsToExtract)
            {
                if (_AbortAll)
                {
                    _ErrorBuilder.AppendLine("User aborted all the processes!");
                    break;
                }
                try
                {
                    initialParameters.AddRange(GetTrackParameters(seg, argMKVFile, argOutputDirectory, argChapterType, argTimecodesExtractionMode, argCueExtractionMode));
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    _ErrorBuilder.AppendLine(String.Format("Segment: {0}\r\nException: {1}\r\n", seg, ex.Message));
                }
            }

            // Group the initial parameters, in order to batch extract the mkv segments
            List <TrackParameter> finalParameters = new List <TrackParameter>();

            foreach (TrackParameter initPar in initialParameters)
            {
                TrackParameter currentPar = null;
                foreach (TrackParameter finalPar in finalParameters)
                {
                    if (finalPar.ExtractMode == initPar.ExtractMode)
                    {
                        currentPar = finalPar;
                        break;
                    }
                }
                if (currentPar != null)
                {
                    currentPar.TrackOutput = String.Format("{0} {1}", currentPar.TrackOutput, initPar.TrackOutput);
                }
                else
                {
                    finalParameters.Add(initPar);
                }
            }

            // Time to extract the mkv segments
            foreach (TrackParameter finalPar in finalParameters)
            {
                if (_AbortAll)
                {
                    _ErrorBuilder.AppendLine("User aborted all the processes!");
                    break;
                }
                try
                {
                    if (finalPar.WriteOutputToFile)
                    {
                        _OutputFileWriter = new StreamWriter(finalPar.OutputFilename, false, new UTF8Encoding(false, true));
                    }

                    OnMkvExtractTrackUpdated(Enum.GetName(finalPar.ExtractMode.GetType(), finalPar.ExtractMode));
                    ExtractMkvSegment(argMKVFile,
                                      String.Format("{0} {1} \"{2}\" {3}",
                                                    Enum.GetName(finalPar.ExtractMode.GetType(), finalPar.ExtractMode),
                                                    finalPar.Options,
                                                    argMKVFile,
                                                    finalPar.TrackOutput),
                                      finalPar.WriteOutputToFile);
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex);
                    _ErrorBuilder.AppendLine(String.Format("Track output: {0}\r\nException: {1}\r\n", finalPar.TrackOutput, ex.Message));
                }
                finally
                {
                    if (finalPar.WriteOutputToFile)
                    {
                        _OutputFileWriter.Close();
                        _OutputFileWriter = null;

                        try
                        {
                            // If we have chapters with CUE format, then we read the XML chapters and convert it to CUE
                            if (finalPar.ExtractMode == MkvExtractModes.chapters)
                            {
                                if (finalPar.OutputFilename.EndsWith("cue"))
                                {
                                    Chapters c = null;
                                    using (StreamReader sr = new StreamReader(finalPar.OutputFilename))
                                    {
                                        XmlSerializer serializer = new XmlSerializer(typeof(Chapters));
                                        c = (Chapters)serializer.Deserialize(sr);
                                    }
                                    Cue cue = new Cue();
                                    cue.File     = Path.GetFileName(argMKVFile);
                                    cue.FileType = "WAVE";
                                    cue.Title    = Path.GetFileName(argMKVFile);
                                    cue.Tracks   = new List <CueTrack>();

                                    if (c.EditionEntry != null &&
                                        c.EditionEntry.Length > 0 &&
                                        c.EditionEntry[0].ChapterAtom != null &&
                                        c.EditionEntry[0].ChapterAtom.Length > 0)
                                    {
                                        Int32 currentChapterTrackNumber = 1;
                                        foreach (ChapterAtom atom in c.EditionEntry[0].ChapterAtom)
                                        {
                                            CueTrack tr = new CueTrack();
                                            tr.Number = currentChapterTrackNumber;
                                            if (atom.ChapterDisplay != null &&
                                                atom.ChapterDisplay.Length > 0)
                                            {
                                                tr.Title = atom.ChapterDisplay[0].ChapterString;
                                            }
                                            if (!String.IsNullOrEmpty(atom.ChapterTimeStart) &&
                                                atom.ChapterTimeStart.Contains(":"))
                                            {
                                                String[] timeElements = atom.ChapterTimeStart.Split(new String[] { ":" }, StringSplitOptions.None);
                                                if (timeElements.Length == 3)
                                                {
                                                    // Find cue minutes from hours and minutes
                                                    Int32 hours   = Int32.Parse(timeElements[0]);
                                                    Int32 minutes = Int32.Parse(timeElements[1]) + 60 * hours;
                                                    // Convert nanoseconds to frames (each second is 75 frames)
                                                    Int64 nanoSeconds   = 0;
                                                    Int32 frames        = 0;
                                                    Int32 secondsLength = timeElements[2].Length;
                                                    if (timeElements[2].Contains("."))
                                                    {
                                                        secondsLength = timeElements[2].IndexOf(".");
                                                        nanoSeconds   = Int64.Parse(timeElements[2].Substring(timeElements[2].IndexOf(".") + 1));
                                                        // I take the integer part of the result action in order to get the first frame
                                                        frames = Convert.ToInt32(Math.Floor(Convert.ToDouble(nanoSeconds) / 1000000000.0 * 75.0));
                                                    }
                                                    tr.Index = String.Format("{0}:{1}:{2}",
                                                                             minutes.ToString("#00")
                                                                             , timeElements[2].Substring(0, secondsLength)
                                                                             , frames.ToString("00")
                                                                             );
                                                }
                                            }

                                            cue.Tracks.Add(tr);
                                            currentChapterTrackNumber++;
                                        }
                                    }

                                    StringBuilder cueBuilder = new StringBuilder();

                                    cueBuilder.AppendFormat("REM GENRE \"\"\r\n");
                                    cueBuilder.AppendFormat("REM DATE \"\"\r\n");
                                    cueBuilder.AppendFormat("PERFORMER \"\"\r\n");
                                    cueBuilder.AppendFormat("TITLE \"{0}\"\r\n", cue.Title);
                                    cueBuilder.AppendFormat("FILE \"{0}\" {1}\r\n", cue.File, cue.FileType);

                                    foreach (CueTrack tr in cue.Tracks)
                                    {
                                        cueBuilder.AppendFormat("\tTRACK {0} AUDIO\r\n", tr.Number.ToString("00"));
                                        cueBuilder.AppendFormat("\t\tTITLE \"{0}\"\r\n", tr.Title);
                                        cueBuilder.AppendFormat("\t\tPERFORMER \"\"\r\n");
                                        cueBuilder.AppendFormat("\t\tINDEX 01 {0}\r\n", tr.Index);
                                    }

                                    using (StreamWriter sw = new StreamWriter(finalPar.OutputFilename, false, Encoding.UTF8))
                                    {
                                        sw.Write(cueBuilder.ToString());
                                    }
                                }
                            }
                        }
                        catch (Exception exc)
                        {
                            Debug.WriteLine(exc);
                            _ErrorBuilder.AppendLine(String.Format("Track output: {0}\r\nException: {1}\r\n", finalPar.TrackOutput, exc.Message));
                        }
                    }
                }
            }

            // check for errors
            if (_ErrorBuilder.Length > 0)
            {
                throw new Exception(_ErrorBuilder.ToString());
            }
        }