public CueBin DumpCueBin(string baseName, CueBinPrefs prefs) { if (Structure.Sessions.Count > 1) { throw new NotSupportedException("can't dump cue+bin with more than 1 session yet"); } CueBin ret = new CueBin(); ret.baseName = baseName; ret.disc = this; if (!prefs.OneBlobPerTrack) { //this is the preferred mode of dumping things. we will always write full sectors. string cue = new CUE_Format().GenerateCUE_OneBin(Structure, prefs); var bfd = new CueBin.BinFileDescriptor { name = baseName + ".bin" }; ret.cue = string.Format("FILE \"{0}\" BINARY\n", bfd.name) + cue; ret.bins.Add(bfd); bfd.SectorSize = 2352; //skip the mandatory track 1 pregap! cue+bin files do not contain it for (int i = 150; i < Structure.LengthInSectors; i++) { bfd.abas.Add(i); bfd.aba_zeros.Add(false); } } else { //we build our own cue here (unlike above) because we need to build the cue and the output data at the same time StringBuilder sbCue = new StringBuilder(); for (int i = 0; i < Structure.Sessions[0].Tracks.Count; i++) { var track = Structure.Sessions[0].Tracks[i]; var bfd = new CueBin.BinFileDescriptor { name = baseName + string.Format(" (Track {0:D2}).bin", track.Number), SectorSize = Cue.BINSectorSizeForTrackType(track.TrackType) }; ret.bins.Add(bfd); int aba = 0; //skip the mandatory track 1 pregap! cue+bin files do not contain it if (i == 0) { aba = 150; } for (; aba < track.LengthInSectors; aba++) { int thisaba = track.Indexes[0].aba + aba; bfd.abas.Add(thisaba); bfd.aba_zeros.Add(false); } sbCue.AppendFormat("FILE \"{0}\" BINARY\n", bfd.name); sbCue.AppendFormat(" TRACK {0:D2} {1}\n", track.Number, Cue.TrackTypeStringForTrackType(track.TrackType)); foreach (var index in track.Indexes) { int x = index.aba - track.Indexes[0].aba; if (index.Number == 0 && index.aba == track.Indexes[1].aba) { //dont emit index 0 when it is the same as index 1, it is illegal for some reason } //else if (i==0 && index.num == 0) //{ // //don't generate the first index, it is illogical //} else { //track 1 included the lead-in at the beginning of it. sneak past that. //if (i == 0) x -= 150; sbCue.AppendFormat(" INDEX {0:D2} {1}\n", index.Number, new Timestamp(x).Value); } } } ret.cue = sbCue.ToString(); } return(ret); }
/// <summary> /// Generates the CUE file for the provided DiscStructure /// </summary> public string GenerateCUE_OneBin(DiscStructure structure, CueBinPrefs prefs) { if (prefs.OneBlobPerTrack) { throw new InvalidOperationException("OneBinPerTrack passed to GenerateCUE_OneBin"); } //this generates a single-file cue!!!!!!! dont expect it to generate bin-per-track! StringBuilder sb = new StringBuilder(); foreach (var session in structure.Sessions) { if (!prefs.SingleSession) { //dont want to screw around with sessions for now sb.AppendFormat("SESSION {0:D2}\n", session.num); if (prefs.AnnotateCue) { sb.AppendFormat("REM ; session (length={0})\n", session.length_aba); } } foreach (var track in session.Tracks) { ETrackType trackType = track.TrackType; //mutate track type according to our principle of canonicalization if (trackType == ETrackType.Mode1_2048 && prefs.DumpECM) { trackType = ETrackType.Mode1_2352; } sb.AppendFormat(" TRACK {0:D2} {1}\n", track.Number, Cue.TrackTypeStringForTrackType(trackType)); if (prefs.AnnotateCue) { sb.AppendFormat(" REM ; track (length={0})\n", track.LengthInSectors); } foreach (var index in track.Indexes) { //cue+bin has an implicit 150 sector pregap which neither the cue nor the bin has any awareness of //except for the baked-in sector addressing. //but, if there is an extra-long pregap, we want to reflect it this way int lba = index.aba - 150; if (lba <= 0 && index.Number == 0 && track.Number == 1) { } //dont emit index 0 when it is the same as index 1, it is illegal for some reason else if (index.Number == 0 && index.aba == track.Indexes[1].aba) { //dont emit index 0 when it is the same as index 1, it confuses some cue parsers } else { sb.AppendFormat(" INDEX {0:D2} {1}\n", index.Number, new Timestamp(lba).Value); } } } } return(sb.ToString()); }