Exemple #1
0
        private async void OnSelectFileTapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
        {
            var item = (sender as FrameworkElement).DataContext as FileOpenFailureItem;
            var f    = await PickMediaFileAsync();

            if (f != null)
            {
                FutureAccessListHelper.Instance.AddTempItem(new IStorageItem[] { f });

                var cueFile = _failedItems[item.FullPath];
                Added.AddRange(
                    await FileOpen.HandleFileWithCue(f,
                                                     await CueFile.CreateFromFileAsync(cueFile, false)));

                _failedItems.Remove(item.FullPath);
                _items.Remove((from i
                               in _items
                               where string.Compare(i.FullPath, item.FullPath, true) == 0
                               select i).First());

                if (_failedItems.Count == 0)
                {
                    Hide();
                }
            }
        }
Exemple #2
0
        private bool LoadTimelineDiff(CueFile cueFile, bool save = true)
        {
            if (save)
            {
                timeline.Export();
            }

            timeline.DeleteAllTargets();
            timeline.RemoveAllRepeaters();

            foreach (Cue cue in cueFile.cues)
            {
                timeline.AddTargetFromAction(timeline.GetTargetDataForCue(cue));
            }

            if (cueFile.NRCueData != null)
            {
                if (cueFile.NRCueData.pathBuilderNoteData.Count == cueFile.NRCueData.pathBuilderNoteCues.Count)
                {
                    for (int i = 0; i < cueFile.NRCueData.pathBuilderNoteCues.Count; ++i)
                    {
                        var data = timeline.GetTargetDataForCue(cueFile.NRCueData.pathBuilderNoteCues[i]);
                        data.pathBuilderData = cueFile.NRCueData.pathBuilderNoteData[i];
                        data.pathBuilderData.parentNotes.Add(data);

                        //Recalculate the notes, and remove any identical enties that would have been loaded through the cues
                        ChainBuilder.CalculateChainNotes(data);
                        foreach (TargetData genData in data.pathBuilderData.generatedNotes)
                        {
                            var foundData = timeline.FindTargetData(genData.time, genData.behavior, genData.handType);
                            if (foundData != null)
                            {
                                timeline.DeleteTargetFromAction(foundData);
                            }
                        }

                        timeline.AddTargetFromAction(data);

                        //Generate the notes, so the song is complete
                        ChainBuilder.GenerateChainNotes(data);
                    }
                }

                if (Timeline.audioLoaded)
                {
                    foreach (var section in cueFile.NRCueData.repeaterSections)
                    {
                        timeline.AddRepeaterSectionFromAction(section);
                    }
                }
                else
                {
                    timeline.loadRepeaterSectionAfterAudio = cueFile.NRCueData.repeaterSections;
                }
            }



            return(true);
        }
        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);
        }
Exemple #4
0
        public static async Task <string> HandleCueFileOpen(StorageFile cueFile, List <StorageFile> files, List <MusicPlaybackItem> add)
        {
            try
            {
                var parent = await cueFile.GetParentAsync();

                var cue = await CueFile.CreateFromFileAsync(cueFile, false);

                // Check user-opened files that are in the same directory
                var audioTrack = (from f
                                  in files
                                  where string.Compare(cue.FileName, f.Name, true) == 0
                                  select f).FirstOrDefault();

                StorageFile file = audioTrack;
                // Cannot find suitable audio track in user opened files.
                if (file == null)
                {
                    // Check parent directory
                    if (parent != null && !string.IsNullOrWhiteSpace(cue.FileName))
                    {
                        file = await parent.TryGetItemAsync(cue.FileName) as StorageFile;
                    }
                    // Try opening the file
                    else if (!string.IsNullOrWhiteSpace(cue.FileName))
                    {
                        var parentPath = cueFile.Path.Substring(0,
                                                                cueFile.Path.Length - Path.GetFileName(cueFile.Path).Length);
                        var audioTrackPath = Path.Combine(parentPath, cue.FileName);
                        file = await NativeMethods.GetStorageFileFromPathAsync(audioTrackPath) as StorageFile;
                    }
                    else
                    {
                        return(null);
                    }
                }
                // Otherwise, remove that.
                else
                {
                    files.Remove(audioTrack);
                }

                if (file != null)
                {
                    add.AddRange(await HandleFileWithCue(file, cue));
                }
                else
                {
                    return(Path.Combine(
                               Directory.GetParent(cueFile.Path).FullName,
                               cue.FileName));
                }
            }
            catch { }
            return(null);
        }
Exemple #5
0
        public void Export()
        {
            string dirpath = Application.persistentDataPath;

            CueFile export = new CueFile();

            export.cues = new List <Cue>();

            foreach (Target target in orderedNotes)
            {
                if (target.data.beatLength == 0)
                {
                    target.data.beatLength = 120;
                }

                if (target.data.behavior == TargetBehavior.Metronome)
                {
                    continue;
                }
                export.cues.Add(NotePosCalc.ToCue(target, offset, false));
            }

            switch (difficultyManager.loadedIndex)
            {
            case 0:
                audicaFile.diffs.expert = export;
                break;

            case 1:
                audicaFile.diffs.advanced = export;
                break;

            case 2:
                audicaFile.diffs.moderate = export;
                break;

            case 3:
                audicaFile.diffs.beginner = export;
                break;
            }

            audicaFile.desc = desc;


            AudicaExporter.ExportToAudicaFile(audicaFile);

            NotificationShower.AddNotifToQueue(new NRNotification("Map saved successfully!"));
        }
Exemple #6
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);
        }
Exemple #7
0
        public static async Task <List <MusicPlaybackItem> > GetPlaybackItemsFromFilesAsync(IReadOnlyList <IStorageItem> items)
        {
            var files = new List <StorageFile>();
            var added = new List <MusicPlaybackItem>();

            // [| (cue file, full file path of missing file) |]
            var failedCue = new List <Tuple <StorageFile, string> >();

            foreach (var file in await GetAllFiles(items))
            {
                files.Add(file);
            }
            var listFiles = PickAndRemoveCueM3uWplFiles(files);

            foreach (var cueFile in listFiles.Item1)
            {
                try
                {
                    var failedFileName = await HandleCueFileOpen(cueFile, files, added);

                    if (failedFileName != null)
                    {
                        failedCue.Add(new Tuple <StorageFile, string>(cueFile, failedFileName));
                    }
                }
                catch { }
            }

            foreach (var m3uFile in listFiles.Item2)
            {
                await HandleM3uAsync(m3uFile, added);
            }

            foreach (var wplFile in listFiles.Item3)
            {
                await HandleWplAsync(wplFile, added);
            }

            foreach (var file in files)
            {
                try
                {
                    IMediaInfo info = null;
                    using (var stream = await file.OpenAsync(FileAccessMode.Read))
                    {
                        NativeMethods.GetMediaInfoFromStream(stream, out info);
                    }
                    if (info == null)
                    {
                        continue;
                    }
                    var cue = info.AllProperties["cuesheet"];
                    if (!string.IsNullOrWhiteSpace(cue))
                    {
                        var cueItems = await HandleFileWithCue(file,
                                                               CueFile.CreateFromString(cue));

                        added.AddRange(cueItems);
                        continue;
                    }
                    var prop = await file.GetBasicPropertiesAsync();

                    var internalEntity = DbMediaFile.FromMediaInfo(info, prop.DateModified);

                    internalEntity.IsExternal = true;

                    internalEntity.Path = file.Path;
                    internalEntity.Id   = -65535;

                    if (string.IsNullOrWhiteSpace(internalEntity.Title) &&
                        !string.IsNullOrWhiteSpace(internalEntity.Path))
                    {
                        internalEntity.Title = Path.GetFileNameWithoutExtension(internalEntity.Path);
                    }
                    added.Add(MusicPlaybackItem.CreateFromMediaFile(internalEntity));
                }
                catch { }
            }
            if (failedCue.Count > 0)
            {
                added.AddRange(
                    await FileOpenFailure.AddFailedFilePath(
                        failedCue));
            }
            return(added);
        }
Exemple #8
0
        public static async Task <IEnumerable <MusicPlaybackItem> > HandleFileWithCue(StorageFile file, CueFile cue)
        {
            //Cue files will only have track number
            var items = cue.Indices
                        .OrderBy(c => ParseWithDefaultFallback(
                                     c.TrackInfo.TrackNumber));
            List <MusicPlaybackItem> files = new List <MusicPlaybackItem>();
            IMediaInfo info = null;

            using (var stream = await file.OpenAsync(FileAccessMode.Read))
            {
                NativeMethods.GetMediaInfoFromStream(
                    stream,
                    out info);
            }
            if (info == null)
            {
                return(files);
            }
            var prop = await file.GetBasicPropertiesAsync();

            foreach (ManagedAudioIndexCue item in items)
            {
                if (item.TrackInfo.Duration == TimeSpan.Zero)
                {
                    (item.TrackInfo as CueMediaInfo).Duration
                          = item.Duration
                          = info.Duration - item.StartTime;
                }
                var internalEntity = DbMediaFile.FromMediaInfo(item.TrackInfo, prop.DateModified);
                internalEntity.IsExternal = true;
                internalEntity.StartTime  = (int)item.StartTime.TotalMilliseconds;
                internalEntity.Path       = file.Path;
                internalEntity.Id         = -65535;
                files.Add(MusicPlaybackItem.CreateFromMediaFile(internalEntity));
            }
            return(files);
        }
Exemple #9
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
		}
Exemple #10
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
        }
Exemple #11
0
    public void ExportAsCues()
    {
        //Pick folder
        //string prevDir = PlayerPrefs.GetString("recentDirCues", "");


        string diff;

        switch (DifficultyManager.I.loadedIndex)
        {
        case 0:
            diff = "Expert";
            break;

        case 1:
            diff = "Advanced";
            break;

        case 2:
            diff = "Standard";
            break;

        default:
            diff = "Easy";
            break;
        }
        string fileName = Path.GetFileName(Timeline.audicaFile.filepath)?.Replace(".audica", "");

        fileName = fileName + "_NRExport-" + diff + ".cues";

        string path;



        if (!String.IsNullOrEmpty(NRSettings.config.cuesSavePath))
        {
            path = Path.Combine(NRSettings.config.cuesSavePath, fileName);
        }

        else
        {
            path = StandaloneFileBrowser.SaveFilePanel("Find community_maps/maps folder in Audica folder", Path.Combine(Application.dataPath, @"../"), fileName, "cues");
            if (String.IsNullOrEmpty(path))
            {
                return;
            }

            NRSettings.config.cuesSavePath = Path.GetDirectoryName(path);
            NRSettings.SaveSettingsJson();
        }


        //Ensure all chains are generated
        List <TargetData> nonGeneratedNotes = new List <TargetData>();

        foreach (Target note in Timeline.instance.notes)
        {
            if (note.data.behavior == TargetBehavior.NR_Pathbuilder && note.data.pathBuilderData.createdNotes == false)
            {
                nonGeneratedNotes.Add(note.data);
            }
        }

        foreach (var data in nonGeneratedNotes)
        {
            ChainBuilder.GenerateChainNotes(data);
        }

        CueFile export = new CueFile();

        export.cues      = new List <Cue>();
        export.NRCueData = new NRCueData();

        foreach (Target target in Timeline.orderedNotes)
        {
            if (target.data.beatLength == 0)
            {
                target.data.beatLength = Constants.SixteenthNoteDuration;
            }

            if (target.data.behavior == TargetBehavior.Metronome)
            {
                continue;
            }

            var cue = NotePosCalc.ToCue(target, Timeline.offset);

            if (target.data.behavior == TargetBehavior.NR_Pathbuilder)
            {
                export.NRCueData.pathBuilderNoteCues.Add(cue);
                export.NRCueData.pathBuilderNoteData.Add(target.data.pathBuilderData);
                continue;
            }

            export.cues.Add(cue);
        }


        File.WriteAllText(path, JsonUtility.ToJson(export));

        NotificationShower.Queue(new NRNotification("Saved cues!"));
    }
 public static string CuesToJson(CueFile cueFile)
 {
     return(JsonUtility.ToJson(cueFile, true));
 }
        private void ConvertMultiToSingleBin_OnClick(object sender, RoutedEventArgs e)
        {
            var openFileDialog = new Ookii.Dialogs.Wpf.VistaOpenFileDialog();

            openFileDialog.Filter      = "Supported files|*.bin;*.cue|All files|*.*";
            openFileDialog.Multiselect = true;
            var openResult = openFileDialog.ShowDialog();

            if (!openResult.GetValueOrDefault(false))
            {
                return;
            }

            var saveFileDialog = new Ookii.Dialogs.Wpf.VistaSaveFileDialog();

            saveFileDialog.Filter       = "Supported files|*.bin;";
            saveFileDialog.DefaultExt   = ".bin";
            saveFileDialog.AddExtension = true;
            var saveResult = saveFileDialog.ShowDialog();

            if (!saveResult.GetValueOrDefault(false))
            {
                return;
            }

            bool   generatedCue = false;
            string tempFile     = "";

            var trackRegex = new Regex("Track (\\d+)");

            if (openFileDialog.FileNames.Length > 1)
            {
                if (!openFileDialog.FileNames.All(f =>
                {
                    var match = trackRegex.Match(f);
                    return(Path.GetExtension(f).ToLower() == ".bin" &&
                           match.Success &&
                           int.TryParse(match.Groups[1].Value, out var dummy));
                }))
                {
                    MessageBox.Show(Window, "Please multi-select only .bins ending in (Track #)",
                                    "PSXPackager",
                                    MessageBoxButton.OK, MessageBoxImage.Information);
                    return;
                }

                var cueFile = new CueFile();

                var index = 1;
                foreach (var fileName in openFileDialog.FileNames.OrderBy(f => int.Parse(trackRegex.Match(f).Groups[1].Value)))
                {
                    cueFile.FileEntries.Add(new CueFileEntry()
                    {
                        FileName = fileName,
                        FileType = "BINARY",
                        Tracks   = index == 1
                            ? new List <CueTrack>()
                        {
                            new CueTrack()
                            {
                                DataType = CueTrackType.Data,
                                Number   = index,
                                Indexes  = new List <CueIndex>()
                                {
                                    new CueIndex()
                                    {
                                        Number = 1, Position = new IndexPosition(0, 0, 0)
                                    }
                                }
                            }
                        }
                            : new List <CueTrack>()
                        {
                            new CueTrack()
                            {
                                DataType = CueTrackType.Audio,
                                Number   = index,
                                Indexes  = new List <CueIndex>()
                                {
                                    new CueIndex()
                                    {
                                        Number = 0, Position = new IndexPosition(0, 0, 0)
                                    },
                                    new CueIndex()
                                    {
                                        Number = 1, Position = new IndexPosition(0, 2, 0)
                                    }
                                }
                            }
                        }
                    });
                    index++;
                }

                tempFile = Path.GetTempFileName() + ".cue";

                CueFileWriter.Write(cueFile, tempFile);

                generatedCue = true;
            }
            else if (Path.GetExtension(openFileDialog.FileName).ToLower() == ".cue")
            {
                tempFile = openFileDialog.FileName;
            }
            else
            {
                MessageBox.Show(Window, "Please select the CUE file, or if you do not have a CUE file, multi-select all the .bins ending in (Track #)",
                                "PSXPackager",
                                MessageBoxButton.OK, MessageBoxImage.Information);
            }

            var folder     = Path.GetDirectoryName(Path.GetFullPath(saveFileDialog.FileName));
            var filename   = Path.GetFileName(saveFileDialog.FileName);
            var processing = new Popstation.Processing(null, null, null);

            var(binfile, cuefile) = processing.ProcessCue(tempFile, Path.GetTempPath());

            var cueFileName = Path.GetFileNameWithoutExtension(filename) + ".cue";
            var outputPath  = Path.Combine(folder, saveFileDialog.FileName);

            if (File.Exists(outputPath))
            {
                File.Delete(outputPath);
            }

            File.Move(binfile, outputPath);

            if (generatedCue)
            {
                var updatedCueFile = CueFileReader.Read(cuefile);
                var fileEntry      = updatedCueFile.FileEntries.First();
                fileEntry.FileName = filename;
                CueFileWriter.Write(updatedCueFile, Path.Combine(folder, cueFileName));
            }

            MessageBox.Show(Window, $"Merged .bins to {outputPath}", "PSXPackager",
                            MessageBoxButton.OK, MessageBoxImage.Information);
        }