some work on the disc system
This commit is contained in:
parent
ca628e6278
commit
35f2691666
|
@ -4,6 +4,8 @@ using System.Text.RegularExpressions;
|
|||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
|
||||
//this rule is not supported correctly: `The first track number can be greater than one, but all track numbers after the first must be sequential.`
|
||||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
partial class Disc
|
||||
|
@ -17,157 +19,202 @@ namespace BizHawk.Disc
|
|||
var session = new DiscTOC.Session();
|
||||
session.num = 1;
|
||||
TOC.Sessions.Add(session);
|
||||
var pregap_sector = new Sector_Zero();
|
||||
|
||||
int curr_track = 1;
|
||||
|
||||
int track_counter = 1;
|
||||
int curr_lba = 0;
|
||||
foreach (var cue_file in cue.Files)
|
||||
{
|
||||
//make a raw file blob for the source binfile
|
||||
//structural validation
|
||||
if (cue_file.Tracks.Count < 1) throw new Cue.CueBrokenException("`You must specify at least one track per file.`");
|
||||
|
||||
int blob_sectorsize = Cue.BINSectorSizeForTrackType(cue_file.Tracks[0].TrackType);
|
||||
|
||||
//make a blob for the file
|
||||
Blob_RawFile blob = new Blob_RawFile();
|
||||
blob.PhysicalPath = Path.Combine(cueDir, cue_file.Path);
|
||||
Blobs.Add(blob);
|
||||
|
||||
//structural validation
|
||||
if (cue_file.Tracks.Count < 1) throw new Cue.CueBrokenException("Found a cue file with no tracks");
|
||||
int blob_length_lba = (int)(blob.Length / blob_sectorsize);
|
||||
int blob_leftover = (int)(blob.Length - blob_length_lba * blob_sectorsize);
|
||||
|
||||
//structural validation: every track must be the same type with cue/bin (i think)
|
||||
var trackType = cue_file.Tracks[0].TrackType;
|
||||
for (int i = 1; i < cue_file.Tracks.Count; i++)
|
||||
//TODO - make CueTimestamp better, and also make it a struct, and also just make it DiscTimestamp
|
||||
//TODO - wav handling
|
||||
//TODO - mp3 decode
|
||||
|
||||
//start timekeeping for the blob. every time we hit an index, this will advance
|
||||
int blob_timestamp = 0;
|
||||
|
||||
//for each track within the file, create an index 0 if it is missing.
|
||||
//also check to make sure there is an index 1
|
||||
for (int t = 0; t < cue_file.Tracks.Count; t++)
|
||||
{
|
||||
if (cue_file.Tracks[i].TrackType != trackType) throw new Cue.CueBrokenException("cue has different track types per datafile (not supported now; maybe never)");
|
||||
var cue_track = cue_file.Tracks[t];
|
||||
if (!cue_track.Indexes.ContainsKey(1))
|
||||
throw new Cue.CueBrokenException("Track was missing an index 01");
|
||||
if (!cue_track.Indexes.ContainsKey(0))
|
||||
{
|
||||
//index 0 will default to the same as index 1.
|
||||
//i am not sure whether it is valid to have two indexes with the same timestamp.
|
||||
//we will do this to simplify some processing, but we can purge it in a later pass if we need to.
|
||||
var cti = new Cue.CueTrackIndex(0);
|
||||
cue_track.Indexes[0] = cti;
|
||||
cti.Timestamp = cue_track.Indexes[1].Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
//structural validaton: make sure file is a correct size and analyze its length
|
||||
long flen = new FileInfo(blob.PhysicalPath).Length;
|
||||
int numlba;
|
||||
int leftover = 0;
|
||||
switch (trackType)
|
||||
//validate that the first index in the file is 00:00:00
|
||||
if (cue_file.Tracks[0].Indexes[0].Timestamp.LBA != 0) throw new Cue.CueBrokenException("`The first index of a file must start at 00:00:00.`");
|
||||
|
||||
|
||||
//for each track within the file:
|
||||
for (int t = 0; t < cue_file.Tracks.Count; t++)
|
||||
{
|
||||
case Cue.ECueTrackType.Audio:
|
||||
numlba = (int)(flen / 2352);
|
||||
leftover = (int)(flen - numlba * 2352);
|
||||
break;
|
||||
var cue_track = cue_file.Tracks[t];
|
||||
|
||||
case Cue.ECueTrackType.Mode1_2352:
|
||||
case Cue.ECueTrackType.Mode2_2352:
|
||||
if (flen % 2352 != 0) throw new Cue.CueBrokenException("Found a modeN_2352 cue file that is wrongly-sized");
|
||||
numlba = (int)(flen / 2352);
|
||||
break;
|
||||
case Cue.ECueTrackType.Mode1_2048:
|
||||
if (flen % 2048 != 0) throw new Cue.CueBrokenException("Found a modeN_2048 cue file that is wrongly-sized");
|
||||
numlba = (int)(flen / 2048);
|
||||
break;
|
||||
//record the disc LBA that this sector started on
|
||||
int track_disc_lba_start = Sectors.Count;
|
||||
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
//record the pregap location. it will default to the start of the track unless we supplied a pregap command
|
||||
int track_disc_pregap_lba = track_disc_lba_start;
|
||||
|
||||
List<DiscTOC.Track> new_toc_tracks = new List<DiscTOC.Track>();
|
||||
for (int i = 0; i < cue_file.Tracks.Count; i++)
|
||||
{
|
||||
bool last_track = (i == cue_file.Tracks.Count - 1);
|
||||
//enforce a rule of our own: every track within the file must have the same sector size
|
||||
//we do know that files can change between track types within a file, but we're not sure what to do if the sector size changes
|
||||
if (Cue.BINSectorSizeForTrackType(cue_track.TrackType) != blob_sectorsize) throw new Cue.CueBrokenException("Found different sector sizes within a cue file. We don't know how to handle that.");
|
||||
|
||||
var cue_track = cue_file.Tracks[i];
|
||||
if (cue_track.TrackNum != track_counter) throw new Cue.CueBrokenException("Missing a track in the middle of the cue");
|
||||
track_counter++;
|
||||
|
||||
DiscTOC.Track toc_track = new DiscTOC.Track();
|
||||
toc_track.num = track_counter;
|
||||
//check integrity of track sequence and setup data structures
|
||||
//TODO - check for skipped tracks in cue parser instead
|
||||
if (cue_track.TrackNum != curr_track) throw new Cue.CueBrokenException("Found a cue with skipped tracks");
|
||||
var toc_track = new DiscTOC.Track();
|
||||
toc_track.num = curr_track;
|
||||
toc_track.TrackType = cue_track.TrackType;
|
||||
session.Tracks.Add(toc_track);
|
||||
new_toc_tracks.Add(toc_track);
|
||||
|
||||
//analyze indices
|
||||
int idx;
|
||||
for (idx = 0; idx <= 99; idx++)
|
||||
//check whether a pregap is requested.
|
||||
//when this happens for the first track in a file, some empty sectors are generated
|
||||
//when it happens for any other track, its just another way of specifying index 0 LBA
|
||||
if (cue_track.PreGap.LBA > 0)
|
||||
{
|
||||
if (!cue_track.Indexes.ContainsKey(idx))
|
||||
{
|
||||
if (idx == 0) continue;
|
||||
if (idx == 1) throw new Cue.CueBrokenException("cue track is missing an index 1");
|
||||
break;
|
||||
}
|
||||
var cue_index = cue_track.Indexes[idx];
|
||||
//todo - add pregap/postgap from cue?
|
||||
if (t == 0)
|
||||
for (int i = 0; i < cue_track.PreGap.LBA; i++)
|
||||
{
|
||||
Sectors.Add(new SectorEntry(pregap_sector));
|
||||
}
|
||||
else track_disc_pregap_lba -= cue_track.PreGap.LBA;
|
||||
}
|
||||
|
||||
DiscTOC.Index toc_index = new DiscTOC.Index();
|
||||
toc_index.num = idx;
|
||||
//look ahead to the next track's index 0 so we can see how long this track's last index is
|
||||
//or, for the last track, use the length of the file
|
||||
int track_length_lba;
|
||||
if (t == cue_file.Tracks.Count - 1)
|
||||
track_length_lba = blob_length_lba - blob_timestamp;
|
||||
else track_length_lba = cue_file.Tracks[t + 1].Indexes[0].Timestamp.LBA - blob_timestamp;
|
||||
//toc_track.length_lba = track_length_lba; //xxx
|
||||
|
||||
//find out how many indexes we have
|
||||
int num_indexes = 0;
|
||||
for (num_indexes = 0; num_indexes <= 99; num_indexes++)
|
||||
if (!cue_track.Indexes.ContainsKey(num_indexes)) break;
|
||||
|
||||
//for each index, calculate length of index and then emit it
|
||||
for (int index = 0; index < num_indexes; index++)
|
||||
{
|
||||
bool is_last_index = index == num_indexes - 1;
|
||||
|
||||
//install index into hierarchy
|
||||
var toc_index = new DiscTOC.Index();
|
||||
toc_index.num = index;
|
||||
toc_track.Indexes.Add(toc_index);
|
||||
toc_index.lba = cue_index.Timestamp.LBA + curr_lba;
|
||||
if (index == 0) toc_index.lba = track_disc_pregap_lba;
|
||||
else toc_index.lba = Sectors.Count;
|
||||
|
||||
//toc_index.lba += 150; //TODO - consider whether to add 150 here
|
||||
|
||||
//calculate length of the index
|
||||
//if it is the last index then we use our calculation from before, otherwise we check the next index
|
||||
int index_length_lba;
|
||||
if (is_last_index)
|
||||
index_length_lba = track_disc_lba_start + track_length_lba - blob_timestamp;
|
||||
else index_length_lba = cue_track.Indexes[index + 1].Timestamp.LBA - blob_timestamp;
|
||||
|
||||
//emit sectors
|
||||
for (int lba = 0; lba < index_length_lba; lba++)
|
||||
{
|
||||
bool is_last_lba_in_index = (lba == index_length_lba-1);
|
||||
bool is_last_lba_in_track = is_last_lba_in_index && is_last_index;
|
||||
|
||||
switch (cue_track.TrackType)
|
||||
{
|
||||
case ETrackType.Audio: //all 2352 bytes are present
|
||||
case ETrackType.Mode1_2352: //2352 bytes are present, containing 2048 bytes of user data as well as ECM
|
||||
case ETrackType.Mode2_2352: //2352 bytes are present, containing 2336 bytes of user data, with no ECM
|
||||
{
|
||||
//these cases are all 2352 bytes
|
||||
//in all these cases, either no ECM is present or ECM is provided.
|
||||
//so we just emit a Sector_Raw
|
||||
Sector_RawBlob sector_rawblob = new Sector_RawBlob();
|
||||
sector_rawblob.Blob = blob;
|
||||
sector_rawblob.Offset = (long)blob_timestamp * 2352;
|
||||
Sector_Raw sector_raw = new Sector_Raw();
|
||||
sector_raw.BaseSector = sector_rawblob;
|
||||
//take care to handle final sectors that are too short.
|
||||
if (is_last_lba_in_track && blob_leftover>0)
|
||||
{
|
||||
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
|
||||
sector_zeropad.BaseSector = sector_rawblob;
|
||||
sector_zeropad.BaseLength = 2352 - blob_leftover;
|
||||
sector_raw.BaseSector = sector_zeropad;
|
||||
Sectors.Add(new SectorEntry(sector_raw));
|
||||
}
|
||||
Sectors.Add(new SectorEntry(sector_raw));
|
||||
break;
|
||||
}
|
||||
case ETrackType.Mode1_2048:
|
||||
//2048 bytes are present. ECM needs to be generated to create a full sector
|
||||
{
|
||||
//ECM needs to know the sector number so we have to record that here
|
||||
int curr_disc_lba = Sectors.Count;
|
||||
var sector_2048 = new Sector_Mode1_2048(curr_disc_lba + 150);
|
||||
sector_2048.Blob = new ECMCacheBlob(blob);
|
||||
sector_2048.Offset = (long)blob_timestamp * 2048;
|
||||
if (blob_leftover > 0) throw new Cue.CueBrokenException("TODO - Incomplete 2048 byte/sector bin files (iso files) not yet supported.");
|
||||
break;
|
||||
}
|
||||
} //switch(TrackType)
|
||||
|
||||
//we've emitted an LBA, so consume it from the blob
|
||||
blob_timestamp++;
|
||||
|
||||
} //lba emit loop
|
||||
|
||||
} //index loop
|
||||
|
||||
//check whether a postgap is requested. if it is, we need to generate silent sectors
|
||||
for (int i = 0; i < cue_track.PostGap.LBA; i++)
|
||||
{
|
||||
Sectors.Add(new SectorEntry(pregap_sector));
|
||||
}
|
||||
|
||||
//look for extra indices (i.e. gaps)
|
||||
for (; idx <= 99; idx++)
|
||||
{
|
||||
if (cue_track.Indexes.ContainsKey(idx))
|
||||
throw new Cue.CueBrokenException("cue track is has an index gap");
|
||||
}
|
||||
//we're done with the track now.
|
||||
//record its length:
|
||||
toc_track.length_lba = Sectors.Count - track_disc_lba_start;
|
||||
curr_track++;
|
||||
|
||||
} //track loop
|
||||
} //file loop
|
||||
|
||||
//analyze length of each track and index
|
||||
DiscTOC.Index last_toc_index = null;
|
||||
foreach (var toc_track in new_toc_tracks)
|
||||
{
|
||||
foreach (var toc_index in toc_track.Indexes)
|
||||
{
|
||||
if (last_toc_index != null)
|
||||
last_toc_index.length_lba = toc_index.lba - last_toc_index.lba;
|
||||
last_toc_index = toc_index;
|
||||
}
|
||||
}
|
||||
if (last_toc_index != null)
|
||||
last_toc_index.length_lba = (curr_lba + numlba) - last_toc_index.lba;
|
||||
|
||||
//generate the sectors from this file
|
||||
long curr_src_addr = 0;
|
||||
for (int i = 0; i < numlba; i++)
|
||||
{
|
||||
ISector sector;
|
||||
switch (trackType)
|
||||
{
|
||||
case Cue.ECueTrackType.Audio:
|
||||
//all 2352 bytes are present
|
||||
case Cue.ECueTrackType.Mode1_2352:
|
||||
//2352 bytes are present, containing 2048 bytes of user data as well as ECM
|
||||
case Cue.ECueTrackType.Mode2_2352:
|
||||
//2352 bytes are present, containing 2336 bytes of user data, replacing ECM
|
||||
{
|
||||
Sector_RawBlob sector_rawblob = new Sector_RawBlob();
|
||||
sector_rawblob.Blob = blob;
|
||||
sector_rawblob.Offset = curr_src_addr;
|
||||
curr_src_addr += 2352;
|
||||
Sector_Raw sector_raw = new Sector_Raw();
|
||||
sector_raw.BaseSector = sector_rawblob;
|
||||
if (i == numlba - 1 && leftover != 0)
|
||||
{
|
||||
Sector_ZeroPad sector_zeropad = new Sector_ZeroPad();
|
||||
sector_zeropad.BaseSector = sector_rawblob;
|
||||
sector_zeropad.BaseLength = 2352 - leftover;
|
||||
sector_raw.BaseSector = sector_zeropad;
|
||||
}
|
||||
sector = sector_raw;
|
||||
break;
|
||||
}
|
||||
case Cue.ECueTrackType.Mode1_2048:
|
||||
//2048 bytes are present. ECM needs to be generated to create a full sector
|
||||
{
|
||||
var sector_2048 = new Sector_Mode1_2048(i + 150);
|
||||
sector_2048.Blob = new ECMCacheBlob(blob);
|
||||
sector_2048.Offset = curr_src_addr;
|
||||
curr_src_addr += 2048;
|
||||
sector = sector_2048;
|
||||
break;
|
||||
}
|
||||
default: throw new InvalidOperationException();
|
||||
}
|
||||
SectorEntry se = new SectorEntry();
|
||||
se.Sector = sector;
|
||||
Sectors.Add(se);
|
||||
}
|
||||
|
||||
curr_lba += numlba;
|
||||
|
||||
} //done analyzing cue datafiles
|
||||
|
||||
TOC.AnalyzeLengthsFromIndexLengths();
|
||||
//finally, analyze the length of the sessions and the entire disc by summing the lengths of the tracks
|
||||
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
|
||||
//but rather by the difference in lbas between start and end
|
||||
TOC.length_lba = 0;
|
||||
foreach (var toc_session in TOC.Sessions)
|
||||
{
|
||||
var firstTrack = toc_session.Tracks[0];
|
||||
var lastTrack = toc_session.Tracks[toc_session.Tracks.Count - 1];
|
||||
session.length_lba = lastTrack.Indexes[1].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
|
||||
TOC.length_lba += toc_session.length_lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,23 +252,69 @@ namespace BizHawk.Disc
|
|||
|
||||
public List<CueFile> Files = new List<CueFile>();
|
||||
|
||||
public enum ECueTrackType
|
||||
public static int BINSectorSizeForTrackType(ETrackType type)
|
||||
{
|
||||
Mode1_2352,
|
||||
Mode1_2048,
|
||||
Mode2_2352,
|
||||
Audio
|
||||
switch(type)
|
||||
{
|
||||
case ETrackType.Mode1_2352:
|
||||
case ETrackType.Mode2_2352:
|
||||
case ETrackType.Audio:
|
||||
return 2352;
|
||||
case ETrackType.Mode1_2048:
|
||||
return 2048;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static string TrackTypeStringForTrackType(ETrackType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ETrackType.Mode1_2352: return "MODE1/2352";
|
||||
case ETrackType.Mode2_2352: return "MODE2/2352";
|
||||
case ETrackType.Audio: return "AUDIO";
|
||||
case ETrackType.Mode1_2048: return "MODE1/2048";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public static string RedumpTypeStringForTrackType(ETrackType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ETrackType.Mode1_2352: return "Data/Mode 1";
|
||||
case ETrackType.Mode1_2048: throw new InvalidOperationException("guh dunno what to put here");
|
||||
case ETrackType.Mode2_2352: return "Data/Mode 2";
|
||||
case ETrackType.Audio: return "Audio";
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public class CueTrack
|
||||
{
|
||||
public ECueTrackType TrackType;
|
||||
public ETrackType TrackType;
|
||||
public int TrackNum;
|
||||
public CueTimestamp PreGap = new CueTimestamp();
|
||||
public CueTimestamp PostGap = new CueTimestamp();
|
||||
public Dictionary<int, CueTrackIndex> Indexes = new Dictionary<int, CueTrackIndex>();
|
||||
}
|
||||
|
||||
public class CueTimestamp
|
||||
{
|
||||
/// <summary>
|
||||
/// creates timestamp of 00:00:00
|
||||
/// </summary>
|
||||
public CueTimestamp()
|
||||
{
|
||||
Value = "00:00:00";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// creates a timestamp from a string in the form mm:ss:ff
|
||||
/// </summary>
|
||||
public CueTimestamp(string value) {
|
||||
this.Value = value;
|
||||
MIN = int.Parse(value.Substring(0, 2));
|
||||
|
@ -231,12 +324,26 @@ namespace BizHawk.Disc
|
|||
}
|
||||
public readonly string Value;
|
||||
public readonly int MIN, SEC, FRAC, LBA;
|
||||
|
||||
/// <summary>
|
||||
/// creates timestamp from supplied LBA
|
||||
/// </summary>
|
||||
public CueTimestamp(int LBA)
|
||||
{
|
||||
this.LBA = LBA;
|
||||
MIN = LBA / (60*75);
|
||||
SEC = (LBA / 75)%60;
|
||||
FRAC = LBA % 75;
|
||||
Value = string.Format("{0:D2}:{1:D2}:{2:D2}", MIN, SEC, FRAC);
|
||||
}
|
||||
}
|
||||
|
||||
public class CueTrackIndex
|
||||
{
|
||||
public CueTrackIndex(int num) { IndexNum = num; }
|
||||
public int IndexNum;
|
||||
public CueTimestamp Timestamp;
|
||||
public int ZeroLBA;
|
||||
}
|
||||
|
||||
public class CueBrokenException : Exception
|
||||
|
@ -254,6 +361,9 @@ namespace BizHawk.Disc
|
|||
File.ReadAllText(cuePath);
|
||||
TextReader tr = new StreamReader(cuePath);
|
||||
|
||||
bool track_has_pregap = false;
|
||||
bool track_has_postgap = false;
|
||||
int last_index_num = -1;
|
||||
CueFile currFile = null;
|
||||
CueTrack currTrack = null;
|
||||
int state = 0;
|
||||
|
@ -294,44 +404,60 @@ namespace BizHawk.Disc
|
|||
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 = ECueTrackType.Mode1_2352; break;
|
||||
case "MODE1/2048": currTrack.TrackType = ECueTrackType.Mode1_2048; break;
|
||||
case "MODE2/2352": currTrack.TrackType = ECueTrackType.Mode2_2352; break;
|
||||
case "AUDIO": currTrack.TrackType = ECueTrackType.Audio; break;
|
||||
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();
|
||||
CueTrackIndex cti = new CueTrackIndex();
|
||||
cti.Timestamp = new CueTimestamp(str_timestamp); ;
|
||||
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);
|
||||
cti.Timestamp = new CueTimestamp(str_timestamp);
|
||||
cti.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 CueTimestamp(clp.ReadToken());
|
||||
track_has_pregap = true;
|
||||
break;
|
||||
case "POSTGAP":
|
||||
throw new CueBrokenException("cue postgap/pregap command not supported yet");
|
||||
if (track_has_pregap) throw new CueBrokenException("`Only one POSTGAP command is allowed per track.`");
|
||||
track_has_postgap = true;
|
||||
currTrack.PostGap = new CueTimestamp(clp.ReadToken());
|
||||
break;
|
||||
default:
|
||||
throw new CueBrokenException("unsupported cue command: " + key);
|
||||
}
|
||||
}
|
||||
} //end cue parsing loop
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@ using System.Collections.Generic;
|
|||
//apparently cdrdao is the ultimate linux tool for doing this stuff but it doesnt support DAO96 (or other DAO modes) that would be necessary to extract P-Q subchannels
|
||||
//(cdrdao only supports R-W)
|
||||
|
||||
//here is a featureset list of windows cd burning programs (useful for cuesheet compatibility info)
|
||||
//http://www.dcsoft.com/cue_mastering_progs.htm
|
||||
|
||||
//good
|
||||
//http://linux-sxs.org/bedtime/cdapi.html
|
||||
//http://en.wikipedia.org/wiki/Track_%28CD%29
|
||||
|
@ -65,7 +68,6 @@ using System.Collections.Generic;
|
|||
|
||||
namespace BizHawk.Disc
|
||||
{
|
||||
|
||||
public partial class Disc
|
||||
{
|
||||
//TODO - separate these into Read_2352 and Read_2048 (optimizations can be made by ISector implementors depending on what is requested)
|
||||
|
@ -83,10 +85,20 @@ namespace BizHawk.Disc
|
|||
|
||||
class Blob_RawFile : IBlob
|
||||
{
|
||||
public string PhysicalPath;
|
||||
public string PhysicalPath {
|
||||
get { return physicalPath; }
|
||||
set
|
||||
{
|
||||
physicalPath = value;
|
||||
length = new FileInfo(physicalPath).Length;
|
||||
}
|
||||
}
|
||||
string physicalPath;
|
||||
long length;
|
||||
|
||||
public long Offset;
|
||||
|
||||
FileStream fs;
|
||||
BufferedStream fs;
|
||||
public void Dispose()
|
||||
{
|
||||
if (fs != null)
|
||||
|
@ -97,13 +109,22 @@ namespace BizHawk.Disc
|
|||
}
|
||||
public int Read(long byte_pos, byte[] buffer, int offset, int count)
|
||||
{
|
||||
//use quite a large buffer, because normally we will be reading these sequentially
|
||||
const int buffersize = 2352 * 75 * 2;
|
||||
if (fs == null)
|
||||
fs = new FileStream(PhysicalPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
fs = new BufferedStream(new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read), buffersize);
|
||||
long target = byte_pos + Offset;
|
||||
if(fs.Position != target)
|
||||
fs.Position = target;
|
||||
return fs.Read(buffer, offset, count);
|
||||
}
|
||||
public long Length
|
||||
{
|
||||
get
|
||||
{
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_RawSilence : ISector
|
||||
|
@ -125,6 +146,16 @@ namespace BizHawk.Disc
|
|||
}
|
||||
}
|
||||
|
||||
class Sector_Zero : ISector
|
||||
{
|
||||
public int Read(byte[] buffer, int offset)
|
||||
{
|
||||
for (int i = 0; i < 2352; i++)
|
||||
buffer[offset + i] = 0;
|
||||
return 2352;
|
||||
}
|
||||
}
|
||||
|
||||
class Sector_ZeroPad : ISector
|
||||
{
|
||||
public ISector BaseSector;
|
||||
|
@ -229,6 +260,7 @@ namespace BizHawk.Disc
|
|||
//this is a physical 2352 byte sector.
|
||||
public class SectorEntry
|
||||
{
|
||||
public SectorEntry(ISector sec) { this.Sector = sec; }
|
||||
public ISector Sector;
|
||||
}
|
||||
|
||||
|
@ -256,7 +288,7 @@ namespace BizHawk.Disc
|
|||
blob.PhysicalPath = fiIso.FullName;
|
||||
Blobs.Add(blob);
|
||||
int num_lba = (int)(fiIso.Length / 2048);
|
||||
index.length_lba = num_lba;
|
||||
//index.length_lba = num_lba;
|
||||
if (fiIso.Length % 2048 != 0)
|
||||
throw new InvalidOperationException("invalid iso file (size not multiple of 2048)");
|
||||
|
||||
|
@ -266,21 +298,76 @@ namespace BizHawk.Disc
|
|||
Sector_Mode1_2048 sector = new Sector_Mode1_2048(i+150);
|
||||
sector.Blob = ecmCacheBlob;
|
||||
sector.Offset = i * 2048;
|
||||
SectorEntry se = new SectorEntry();
|
||||
se.Sector = sector;
|
||||
Sectors.Add(se);
|
||||
Sectors.Add(new SectorEntry(sector));
|
||||
}
|
||||
|
||||
TOC.AnalyzeLengthsFromIndexLengths();
|
||||
}
|
||||
|
||||
|
||||
public CueBin DumpCueBin(string baseName, CueBinPrefs prefs)
|
||||
{
|
||||
if (TOC.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.OneBinPerTrack)
|
||||
{
|
||||
string cue = TOC.GenerateCUE(prefs);
|
||||
var bfd = new CueBin.BinFileDescriptor();
|
||||
bfd.name = baseName + ".bin";
|
||||
ret.cue = string.Format("FILE \"{0}\" BINARY\n", bfd.name) + cue;
|
||||
ret.bins.Add(bfd);
|
||||
for (int i = 0; i < TOC.length_lba; i++)
|
||||
{
|
||||
bfd.lbas.Add(i+150);
|
||||
bfd.lba_zeros.Add(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuilder sbCue = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < TOC.Sessions[0].Tracks.Count; i++)
|
||||
{
|
||||
var track = TOC.Sessions[0].Tracks[i];
|
||||
var bfd = new CueBin.BinFileDescriptor();
|
||||
bfd.name = baseName + string.Format(" (Track {0:D2}).bin", track.num);
|
||||
ret.bins.Add(bfd);
|
||||
int lba=0;
|
||||
|
||||
for (; lba < track.length_lba; lba++)
|
||||
{
|
||||
int thislba = track.Indexes[0].lba + lba;
|
||||
bfd.lbas.Add(thislba + 150);
|
||||
bfd.lba_zeros.Add(false);
|
||||
}
|
||||
sbCue.AppendFormat("FILE \"{0}\" BINARY\n", bfd.name);
|
||||
|
||||
sbCue.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
|
||||
foreach (var index in track.Indexes)
|
||||
{
|
||||
int x = index.lba - track.Indexes[0].lba;
|
||||
sbCue.AppendFormat(" INDEX {0:D2} {1}\n", index.num, new Cue.CueTimestamp(x).Value);
|
||||
}
|
||||
}
|
||||
|
||||
ret.cue = sbCue.ToString();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void DumpBin_2352(string binPath)
|
||||
{
|
||||
byte[] temp = new byte[2352];
|
||||
using(FileStream fs = new FileStream(binPath,FileMode.Create,FileAccess.Write,FileShare.None))
|
||||
for (int i = 0; i < Sectors.Count; i++)
|
||||
{
|
||||
ReadLBA_2352(i, temp, 0);
|
||||
ReadLBA_2352(150+i, temp, 0);
|
||||
fs.Write(temp, 0, 2352);
|
||||
}
|
||||
}
|
||||
|
@ -300,4 +387,129 @@ namespace BizHawk.Disc
|
|||
}
|
||||
}
|
||||
|
||||
public enum ETrackType
|
||||
{
|
||||
Mode1_2352,
|
||||
Mode1_2048,
|
||||
Mode2_2352,
|
||||
Audio
|
||||
}
|
||||
|
||||
|
||||
public class CueBinPrefs
|
||||
{
|
||||
/// <summary>
|
||||
/// Controls general operations: should the output be split into several bins, or just use one?
|
||||
/// </summary>
|
||||
public bool OneBinPerTrack;
|
||||
|
||||
/// <summary>
|
||||
/// turn this on to dump bins instead of just cues
|
||||
/// </summary>
|
||||
public bool ReallyDumpBin;
|
||||
|
||||
/// <summary>
|
||||
/// generate remarks and other annotations to help humans understand whats going on, but which will confuse many cue parsers
|
||||
/// </summary>
|
||||
public bool AnnotateCue;
|
||||
|
||||
/// <summary>
|
||||
/// you may find that some cue parsers are upset by index 00
|
||||
/// if thats the case, then we can emit pregaps instead.
|
||||
/// you might also want to use this to save disk space (without pregap commands, the pregap must be stored as empty sectors)
|
||||
/// </summary>
|
||||
public bool PreferPregapCommand = false;
|
||||
|
||||
/// <summary>
|
||||
/// some cue parsers cant handle sessions. better not emit a session command then. multi-session discs will then be broken
|
||||
/// </summary>
|
||||
public bool SingleSession;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates an in-memory cue+bin (complete cuesheet and a little registry of files)
|
||||
/// it will be based on a disc (fro mwhich it can read sectors to avoid burning through extra memory)
|
||||
/// TODO - we must merge this with whatever reads in cue+bin
|
||||
/// </summary>
|
||||
public class CueBin
|
||||
{
|
||||
public string cue;
|
||||
public string baseName;
|
||||
public Disc disc;
|
||||
|
||||
public class BinFileDescriptor
|
||||
{
|
||||
public string name;
|
||||
public List<int> lbas = new List<int>();
|
||||
public List<bool> lba_zeros = new List<bool>();
|
||||
}
|
||||
|
||||
public List<BinFileDescriptor> bins = new List<BinFileDescriptor>();
|
||||
|
||||
public string CreateRedumpReport()
|
||||
{
|
||||
if (disc.TOC.Sessions[0].Tracks.Count != bins.Count)
|
||||
throw new InvalidOperationException("Cannot generate redump report on CueBin lacking OneBinPerTrack property");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < disc.TOC.Sessions[0].Tracks.Count; i++)
|
||||
{
|
||||
var track = disc.TOC.Sessions[0].Tracks[i];
|
||||
var bfd = bins[i];
|
||||
|
||||
//dump the track
|
||||
byte[] dump = new byte[track.length_lba * 2352];
|
||||
for (int lba = 0; lba < track.length_lba; lba++)
|
||||
disc.ReadLBA_2352(bfd.lbas[lba],dump,lba*2352);
|
||||
string crc32 = string.Format("{0:X8}", CRC32.Calculate(dump));
|
||||
string md5 = Util.Hash_MD5(dump, 0, dump.Length);
|
||||
string sha1 = Util.Hash_SHA1(dump, 0, dump.Length);
|
||||
|
||||
int pregap = track.Indexes[1].lba - track.Indexes[0].lba;
|
||||
Cue.CueTimestamp pregap_ts = new Cue.CueTimestamp(pregap);
|
||||
Cue.CueTimestamp len_ts = new Cue.CueTimestamp(track.length_lba);
|
||||
sb.AppendFormat("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\n",
|
||||
i,
|
||||
Cue.RedumpTypeStringForTrackType(track.TrackType),
|
||||
pregap_ts.Value,
|
||||
len_ts.Value,
|
||||
track.length_lba,
|
||||
track.length_lba*Cue.BINSectorSizeForTrackType(track.TrackType),
|
||||
crc32,
|
||||
md5,
|
||||
sha1
|
||||
);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void Dump(string directory, CueBinPrefs prefs)
|
||||
{
|
||||
string cuePath = Path.Combine(directory, baseName + ".cue");
|
||||
File.WriteAllText(cuePath, cue);
|
||||
if(prefs.ReallyDumpBin)
|
||||
foreach (var bfd in bins)
|
||||
{
|
||||
byte[] temp = new byte[2352];
|
||||
byte[] empty = new byte[2352];
|
||||
string trackBinFile = bfd.name;
|
||||
string trackBinPath = Path.Combine(directory, trackBinFile);
|
||||
using (FileStream fs = new FileStream(trackBinPath, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||
{
|
||||
for(int i=0;i<bfd.lbas.Count;i++)
|
||||
{
|
||||
int lba = bfd.lbas[i];
|
||||
if (bfd.lba_zeros[i])
|
||||
{
|
||||
fs.Write(empty, 0, 2352);
|
||||
}
|
||||
else
|
||||
{
|
||||
disc.ReadLBA_2352(lba, temp, 0);
|
||||
fs.Write(temp, 0, 2352);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,15 +16,18 @@ namespace BizHawk.Disc
|
|||
|
||||
//the length of the track (should be the sum of all track lengths)
|
||||
public int length_lba;
|
||||
public Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(length_lba); } }
|
||||
}
|
||||
|
||||
public class Track
|
||||
{
|
||||
public ETrackType TrackType;
|
||||
public int num;
|
||||
public List<Index> Indexes = new List<Index>();
|
||||
|
||||
//the length of the track (should be the sum of all index lengths)
|
||||
public int length_lba;
|
||||
public Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(length_lba); } }
|
||||
}
|
||||
|
||||
public class Index
|
||||
|
@ -33,29 +36,33 @@ namespace BizHawk.Disc
|
|||
public int lba;
|
||||
|
||||
//the length of the section
|
||||
public int length_lba;
|
||||
//public int length_lba;
|
||||
//public Cue.CueTimestamp FriendlyLength { get { return new Cue.CueTimestamp(length_lba); } }
|
||||
}
|
||||
|
||||
public static string FormatLBA(int lba)
|
||||
{
|
||||
return string.Format("{0} ({1:D2}:{2:D2}:{3:D2})", lba, lba / 60 / 75, (lba / 75) % 60, lba % 75);
|
||||
}
|
||||
|
||||
public string DebugPrint()
|
||||
public string GenerateCUE(CueBinPrefs prefs)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (var session in Sessions)
|
||||
{
|
||||
sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
|
||||
if (!prefs.SingleSession)
|
||||
{
|
||||
//dont want to screw around with sessions for now
|
||||
if (prefs.AnnotateCue) sb.AppendFormat("SESSION {0:D2} (length={1})\n", session.num, session.length_lba);
|
||||
else sb.AppendFormat("SESSION {0:D2}\n", session.num);
|
||||
}
|
||||
foreach (var track in session.Tracks)
|
||||
{
|
||||
sb.AppendFormat(" TRACK {0:D2} (length={1})\n", track.num, track.length_lba);
|
||||
if (prefs.AnnotateCue) sb.AppendFormat(" TRACK {0:D2} {1} (length={2})\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType), track.length_lba);
|
||||
else sb.AppendFormat(" TRACK {0:D2} {1}\n", track.num, Cue.TrackTypeStringForTrackType(track.TrackType));
|
||||
foreach (var index in track.Indexes)
|
||||
{
|
||||
sb.AppendFormat(" INDEX {0:D2}: {1}\n", index.num, FormatLBA(index.lba));
|
||||
//if (prefs.PreferPregapCommand && index.num == 0)
|
||||
// sb.AppendFormat(" PREGAP {0}\n", new Cue.CueTimestamp(index.length_lba).Value);
|
||||
//else
|
||||
sb.AppendFormat(" INDEX {0:D2} {1}\n", index.num, new Cue.CueTimestamp(index.lba).Value);
|
||||
}
|
||||
}
|
||||
sb.AppendFormat("-EOF-\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
|
@ -66,17 +73,15 @@ namespace BizHawk.Disc
|
|||
|
||||
public void AnalyzeLengthsFromIndexLengths()
|
||||
{
|
||||
//this is a little more complex than it looks, because the length of a thing is not determined by summing it
|
||||
//but rather by the difference in lbas between start and end
|
||||
length_lba = 0;
|
||||
foreach (var session in Sessions)
|
||||
{
|
||||
foreach (var track in session.Tracks)
|
||||
{
|
||||
int track_size = 0;
|
||||
foreach (var index in track.Indexes)
|
||||
track_size += index.length_lba;
|
||||
track.length_lba += track_size;
|
||||
session.length_lba += track_size;
|
||||
length_lba += track_size;
|
||||
}
|
||||
var firstTrack = session.Tracks[0];
|
||||
var lastTrack = session.Tracks[session.Tracks.Count - 1];
|
||||
session.length_lba = lastTrack.Indexes[0].lba + lastTrack.length_lba - firstTrack.Indexes[0].lba;
|
||||
length_lba += session.length_lba;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
public unsafe static void ecc_generate(byte[] sector, int sector_offset, bool zeroaddress, byte[] dest, int dest_offset)
|
||||
{
|
||||
byte address0=0,address1=0,address2=0,address3=0;
|
||||
byte i;
|
||||
//byte i;
|
||||
/* Save the address and zero it out */
|
||||
if(zeroaddress)
|
||||
{
|
||||
|
|
|
@ -1,426 +1,373 @@
|
|||
////http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/
|
||||
//http://jasonjano.wordpress.com/2010/02/09/a-simple-c-wrapper-for-ffmpeg/
|
||||
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Web;
|
||||
//using System.IO;
|
||||
//using System.Diagnostics;
|
||||
//using System.Configuration;
|
||||
//using System.Text.RegularExpressions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.Configuration;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
//namespace ffMpeg
|
||||
//{
|
||||
// public class Converter
|
||||
// {
|
||||
// #region Properties
|
||||
// public string _ffExe;
|
||||
namespace ffMpeg
|
||||
{
|
||||
public class Converter
|
||||
{
|
||||
public static string _ffExe;
|
||||
public string WorkingPath; //i.e. temp
|
||||
|
||||
// //i.e. temp
|
||||
// public string WorkingPath;
|
||||
public Converter()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
#region Initialization
|
||||
private void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
// #region Constructors
|
||||
// public Converter()
|
||||
// {
|
||||
// Initialize();
|
||||
// }
|
||||
// public Converter(string ffmpegExePath)
|
||||
// {
|
||||
// _ffExe = ffmpegExePath;
|
||||
// Initialize();
|
||||
// }
|
||||
// #endregion
|
||||
private string GetWorkingFile()
|
||||
{
|
||||
//try the stated directory
|
||||
if (File.Exists(_ffExe))
|
||||
{
|
||||
return _ffExe;
|
||||
}
|
||||
|
||||
// #region Initialization
|
||||
// private void Initialize()
|
||||
// {
|
||||
// }
|
||||
//oops, that didn't work, try the base directory
|
||||
if (File.Exists(Path.GetFileName(_ffExe)))
|
||||
{
|
||||
return Path.GetFileName(_ffExe);
|
||||
}
|
||||
|
||||
// private string GetWorkingFile()
|
||||
// {
|
||||
// //try the stated directory
|
||||
// if (File.Exists(_ffExe))
|
||||
// {
|
||||
// return _ffExe;
|
||||
// }
|
||||
//well, now we are really unlucky, let's just return null
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// //oops, that didn't work, try the base directory
|
||||
// if (File.Exists(Path.GetFileName(_ffExe)))
|
||||
// {
|
||||
// return Path.GetFileName(_ffExe);
|
||||
// }
|
||||
#region Get the File without creating a file lock
|
||||
public static System.Drawing.Image LoadImageFromFile(string fileName)
|
||||
{
|
||||
System.Drawing.Image theImage = null;
|
||||
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
FileAccess.Read))
|
||||
{
|
||||
byte[] img;
|
||||
img = new byte[fileStream.Length];
|
||||
fileStream.Read(img, 0, img.Length);
|
||||
fileStream.Close();
|
||||
theImage = System.Drawing.Image.FromStream(new MemoryStream(img));
|
||||
img = null;
|
||||
}
|
||||
GC.Collect();
|
||||
return theImage;
|
||||
}
|
||||
|
||||
// //well, now we are really unlucky, let's just return null
|
||||
// return null;
|
||||
// }
|
||||
// #endregion
|
||||
public static MemoryStream LoadMemoryStreamFromFile(string fileName)
|
||||
{
|
||||
MemoryStream ms = null;
|
||||
using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
FileAccess.Read))
|
||||
{
|
||||
byte[] fil;
|
||||
fil = new byte[fileStream.Length];
|
||||
fileStream.Read(fil, 0, fil.Length);
|
||||
fileStream.Close();
|
||||
ms = new MemoryStream(fil);
|
||||
}
|
||||
GC.Collect();
|
||||
return ms;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// #region Get the File without creating a file lock
|
||||
// public static System.Drawing.Image LoadImageFromFile(string fileName)
|
||||
// {
|
||||
// System.Drawing.Image theImage = null;
|
||||
// using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
// FileAccess.Read))
|
||||
// {
|
||||
// byte[] img;
|
||||
// img = new byte[fileStream.Length];
|
||||
// fileStream.Read(img, 0, img.Length);
|
||||
// fileStream.Close();
|
||||
// theImage = System.Drawing.Image.FromStream(new MemoryStream(img));
|
||||
// img = null;
|
||||
// }
|
||||
// GC.Collect();
|
||||
// return theImage;
|
||||
// }
|
||||
#region Run the process
|
||||
private string RunProcess(string Parameters)
|
||||
{
|
||||
//create a process info
|
||||
ProcessStartInfo oInfo = new ProcessStartInfo(_ffExe, Parameters);
|
||||
oInfo.UseShellExecute = false;
|
||||
oInfo.CreateNoWindow = true;
|
||||
oInfo.RedirectStandardOutput = true;
|
||||
oInfo.RedirectStandardError = true;
|
||||
|
||||
// public static MemoryStream LoadMemoryStreamFromFile(string fileName)
|
||||
// {
|
||||
// MemoryStream ms = null;
|
||||
// using (FileStream fileStream = new FileStream(fileName, FileMode.Open,
|
||||
// FileAccess.Read))
|
||||
// {
|
||||
// byte[] fil;
|
||||
// fil = new byte[fileStream.Length];
|
||||
// fileStream.Read(fil, 0, fil.Length);
|
||||
// fileStream.Close();
|
||||
// ms = new MemoryStream(fil);
|
||||
// }
|
||||
// GC.Collect();
|
||||
// return ms;
|
||||
// }
|
||||
// #endregion
|
||||
//Create the output and streamreader to get the output
|
||||
string output = null; StreamReader srOutput = null;
|
||||
|
||||
// #region Run the process
|
||||
// private string RunProcess(string Parameters)
|
||||
// {
|
||||
// //create a process info
|
||||
// ProcessStartInfo oInfo = new ProcessStartInfo(this._ffExe, Parameters);
|
||||
// oInfo.UseShellExecute = false;
|
||||
// oInfo.CreateNoWindow = true;
|
||||
// oInfo.RedirectStandardOutput = true;
|
||||
// oInfo.RedirectStandardError = true;
|
||||
//try the process
|
||||
try
|
||||
{
|
||||
//run the process
|
||||
Process proc = System.Diagnostics.Process.Start(oInfo);
|
||||
|
||||
// //Create the output and streamreader to get the output
|
||||
// string output = null; StreamReader srOutput = null;
|
||||
proc.WaitForExit();
|
||||
|
||||
// //try the process
|
||||
// try
|
||||
// {
|
||||
// //run the process
|
||||
// Process proc = System.Diagnostics.Process.Start(oInfo);
|
||||
//get the output
|
||||
srOutput = proc.StandardError;
|
||||
|
||||
// proc.WaitForExit();
|
||||
//now put it in a string
|
||||
output = srOutput.ReadToEnd();
|
||||
|
||||
// //get the output
|
||||
// srOutput = proc.StandardError;
|
||||
proc.Close();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
output = string.Empty;
|
||||
}
|
||||
finally
|
||||
{
|
||||
//now, if we succeded, close out the streamreader
|
||||
if (srOutput != null)
|
||||
{
|
||||
srOutput.Close();
|
||||
srOutput.Dispose();
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// //now put it in a string
|
||||
// output = srOutput.ReadToEnd();
|
||||
#region GetVideoInfo
|
||||
public VideoFile GetVideoInfo(MemoryStream inputFile, string Filename)
|
||||
{
|
||||
string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
FileStream fs = File.Create(tempfile);
|
||||
inputFile.WriteTo(fs);
|
||||
fs.Flush();
|
||||
fs.Close();
|
||||
GC.Collect();
|
||||
|
||||
// proc.Close();
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
// output = string.Empty;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// //now, if we succeded, close out the streamreader
|
||||
// if (srOutput != null)
|
||||
// {
|
||||
// srOutput.Close();
|
||||
// srOutput.Dispose();
|
||||
// }
|
||||
// }
|
||||
// return output;
|
||||
// }
|
||||
// #endregion
|
||||
VideoFile vf = null;
|
||||
try
|
||||
{
|
||||
vf = new VideoFile(tempfile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// #region GetVideoInfo
|
||||
// public VideoFile GetVideoInfo(MemoryStream inputFile, string Filename)
|
||||
// {
|
||||
// string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
// FileStream fs = File.Create(tempfile);
|
||||
// inputFile.WriteTo(fs);
|
||||
// fs.Flush();
|
||||
// fs.Close();
|
||||
// GC.Collect();
|
||||
GetVideoInfo(vf);
|
||||
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(tempfile);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
try
|
||||
{
|
||||
File.Delete(tempfile);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
// GetVideoInfo(vf);
|
||||
}
|
||||
|
||||
// try
|
||||
// {
|
||||
// File.Delete(tempfile);
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
return vf;
|
||||
}
|
||||
public VideoFile GetVideoInfo(string inputPath)
|
||||
{
|
||||
VideoFile vf = null;
|
||||
try
|
||||
{
|
||||
vf = new VideoFile(inputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
GetVideoInfo(vf);
|
||||
return vf;
|
||||
}
|
||||
public void GetVideoInfo(VideoFile input)
|
||||
{
|
||||
//set up the parameters for video info
|
||||
string Params = string.Format("-i \"{0}\"", input.Path);
|
||||
string output = RunProcess(Params);
|
||||
input.RawInfo = output;
|
||||
|
||||
// }
|
||||
//get duration
|
||||
Regex re = new Regex("[D|d]uration:.((\\d|:|\\.)*)");
|
||||
Match m = re.Match(input.RawInfo);
|
||||
|
||||
// return vf;
|
||||
// }
|
||||
// public VideoFile GetVideoInfo(string inputPath)
|
||||
// {
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(inputPath);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
// GetVideoInfo(vf);
|
||||
// return vf;
|
||||
// }
|
||||
// public void GetVideoInfo(VideoFile input)
|
||||
// {
|
||||
// //set up the parameters for video info
|
||||
// string Params = string.Format("-i {0}", input.Path);
|
||||
// string output = RunProcess(Params);
|
||||
// input.RawInfo = output;
|
||||
if (m.Success)
|
||||
{
|
||||
string duration = m.Groups[1].Value;
|
||||
string[] timepieces = duration.Split(new char[] { ':', '.' });
|
||||
if (timepieces.Length == 4)
|
||||
{
|
||||
input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
|
||||
}
|
||||
}
|
||||
|
||||
// //get duration
|
||||
// Regex re = new Regex("[D|d]uration:.((\\d|:|\\.)*)");
|
||||
// Match m = re.Match(input.RawInfo);
|
||||
//get audio bit rate
|
||||
re = new Regex("[B|b]itrate:.((\\d|:)*)");
|
||||
m = re.Match(input.RawInfo);
|
||||
double kb = 0.0;
|
||||
if (m.Success)
|
||||
{
|
||||
Double.TryParse(m.Groups[1].Value, out kb);
|
||||
}
|
||||
input.BitRate = kb;
|
||||
|
||||
// if (m.Success)
|
||||
// {
|
||||
// string duration = m.Groups[1].Value;
|
||||
// string[] timepieces = duration.Split(new char[] { ':', '.' });
|
||||
// if (timepieces.Length == 4)
|
||||
// {
|
||||
// input.Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
|
||||
// }
|
||||
// }
|
||||
//get the audio format
|
||||
re = new Regex("[A|a]udio:.*");
|
||||
m = re.Match(input.RawInfo);
|
||||
if (m.Success)
|
||||
{
|
||||
input.AudioFormat = m.Value;
|
||||
}
|
||||
|
||||
// //get audio bit rate
|
||||
// re = new Regex("[B|b]itrate:.((\\d|:)*)");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// double kb = 0.0;
|
||||
// if (m.Success)
|
||||
// {
|
||||
// Double.TryParse(m.Groups[1].Value, out kb);
|
||||
// }
|
||||
// input.BitRate = kb;
|
||||
//get the video format
|
||||
re = new Regex("[V|v]ideo:.*");
|
||||
m = re.Match(input.RawInfo);
|
||||
if (m.Success)
|
||||
{
|
||||
input.VideoFormat = m.Value;
|
||||
}
|
||||
|
||||
// //get the audio format
|
||||
// re = new Regex("[A|a]udio:.*");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// input.AudioFormat = m.Value;
|
||||
// }
|
||||
//get the video format
|
||||
re = new Regex("(\\d{2,3})x(\\d{2,3})");
|
||||
m = re.Match(input.RawInfo);
|
||||
if (m.Success)
|
||||
{
|
||||
int width = 0; int height = 0;
|
||||
int.TryParse(m.Groups[1].Value, out width);
|
||||
int.TryParse(m.Groups[2].Value, out height);
|
||||
input.Width = width;
|
||||
input.Height = height;
|
||||
}
|
||||
input.infoGathered = true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
// //get the video format
|
||||
// re = new Regex("[V|v]ideo:.*");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// input.VideoFormat = m.Value;
|
||||
// }
|
||||
#region Convert to FLV
|
||||
public OutputPackage ConvertToFLV(MemoryStream inputFile, string Filename)
|
||||
{
|
||||
string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
FileStream fs = File.Create(tempfile);
|
||||
inputFile.WriteTo(fs);
|
||||
fs.Flush();
|
||||
fs.Close();
|
||||
GC.Collect();
|
||||
|
||||
// //get the video format
|
||||
// re = new Regex("(\\d{2,3})x(\\d{2,3})");
|
||||
// m = re.Match(input.RawInfo);
|
||||
// if (m.Success)
|
||||
// {
|
||||
// int width = 0; int height = 0;
|
||||
// int.TryParse(m.Groups[1].Value, out width);
|
||||
// int.TryParse(m.Groups[2].Value, out height);
|
||||
// input.Width = width;
|
||||
// input.Height = height;
|
||||
// }
|
||||
// input.infoGathered = true;
|
||||
// }
|
||||
// #endregion
|
||||
VideoFile vf = null;
|
||||
try
|
||||
{
|
||||
vf = new VideoFile(tempfile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// #region Convert to FLV
|
||||
// public OutputPackage ConvertToFLV(MemoryStream inputFile, string Filename)
|
||||
// {
|
||||
// string tempfile = Path.Combine(this.WorkingPath, System.Guid.NewGuid().ToString() + Path.GetExtension(Filename));
|
||||
// FileStream fs = File.Create(tempfile);
|
||||
// inputFile.WriteTo(fs);
|
||||
// fs.Flush();
|
||||
// fs.Close();
|
||||
// GC.Collect();
|
||||
OutputPackage oo = ConvertToFLV(vf);
|
||||
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(tempfile);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
try
|
||||
{
|
||||
File.Delete(tempfile);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
// OutputPackage oo = ConvertToFLV(vf);
|
||||
}
|
||||
|
||||
// try
|
||||
// {
|
||||
// File.Delete(tempfile);
|
||||
// }
|
||||
// catch (Exception)
|
||||
// {
|
||||
return oo;
|
||||
}
|
||||
public OutputPackage ConvertToFLV(string inputPath)
|
||||
{
|
||||
VideoFile vf = null;
|
||||
try
|
||||
{
|
||||
vf = new VideoFile(inputPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
// }
|
||||
OutputPackage oo = ConvertToFLV(vf);
|
||||
return oo;
|
||||
}
|
||||
public OutputPackage ConvertToFLV(VideoFile input)
|
||||
{
|
||||
if (!input.infoGathered)
|
||||
{
|
||||
GetVideoInfo(input);
|
||||
}
|
||||
OutputPackage ou = new OutputPackage();
|
||||
|
||||
// return oo;
|
||||
// }
|
||||
// public OutputPackage ConvertToFLV(string inputPath)
|
||||
// {
|
||||
// VideoFile vf = null;
|
||||
// try
|
||||
// {
|
||||
// vf = new VideoFile(inputPath);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw ex;
|
||||
// }
|
||||
string filename = System.Guid.NewGuid().ToString() + ".flv";
|
||||
string finalpath = Path.Combine(this.WorkingPath, filename);
|
||||
string Params = string.Format("-i \"{0}\" -y -ar 22050 -ab 64 -f flv \"{1}\"", input.Path, finalpath);
|
||||
string output = RunProcess(Params);
|
||||
|
||||
// OutputPackage oo = ConvertToFLV(vf);
|
||||
// return oo;
|
||||
// }
|
||||
// public OutputPackage ConvertToFLV(VideoFile input)
|
||||
// {
|
||||
// if (!input.infoGathered)
|
||||
// {
|
||||
// GetVideoInfo(input);
|
||||
// }
|
||||
// OutputPackage ou = new OutputPackage();
|
||||
if (File.Exists(finalpath))
|
||||
{
|
||||
ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
|
||||
try
|
||||
{
|
||||
File.Delete(finalpath);
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
return ou;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
// //set up the parameters for getting a previewimage
|
||||
// string filename = System.Guid.NewGuid().ToString() + ".jpg";
|
||||
// int secs;
|
||||
public class VideoFile
|
||||
{
|
||||
#region Properties
|
||||
private string _Path;
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Path;
|
||||
}
|
||||
set
|
||||
{
|
||||
_Path = value;
|
||||
}
|
||||
}
|
||||
|
||||
// //divide the duration in 3 to get a preview image in the middle of the clip
|
||||
// //instead of a black image from the beginning.
|
||||
// secs = (int)Math.Round(TimeSpan.FromTicks(input.Duration.Ticks / 3).TotalSeconds, 0);
|
||||
public TimeSpan Duration { get; set; }
|
||||
public double BitRate { get; set; }
|
||||
public string AudioFormat { get; set; }
|
||||
public string VideoFormat { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int Width { get; set; }
|
||||
public string RawInfo { get; set; }
|
||||
public bool infoGathered { get; set; }
|
||||
#endregion
|
||||
|
||||
// string finalpath = Path.Combine(this.WorkingPath, filename);
|
||||
// string Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, secs);
|
||||
// string output = RunProcess(Params);
|
||||
#region Constructors
|
||||
public VideoFile(string path)
|
||||
{
|
||||
_Path = path;
|
||||
Initialize();
|
||||
}
|
||||
#endregion
|
||||
|
||||
// ou.RawOutput = output;
|
||||
#region Initialization
|
||||
private void Initialize()
|
||||
{
|
||||
this.infoGathered = false;
|
||||
//first make sure we have a value for the video file setting
|
||||
if (string.IsNullOrEmpty(_Path))
|
||||
{
|
||||
throw new Exception("Could not find the location of the video file");
|
||||
}
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.PreviewImage = LoadImageFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// else
|
||||
// { //try running again at frame 1 to get something
|
||||
// Params = string.Format("-i {0} {1} -vcodec mjpeg -ss {2} -vframes 1 -an -f rawvideo", input.Path, finalpath, 1);
|
||||
// output = RunProcess(Params);
|
||||
//Now see if the video file exists
|
||||
if (!File.Exists(_Path))
|
||||
{
|
||||
throw new Exception("The video file " + _Path + " does not exist.");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
// ou.RawOutput = output;
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.PreviewImage = LoadImageFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// }
|
||||
|
||||
// finalpath = Path.Combine(this.WorkingPath, filename);
|
||||
// filename = System.Guid.NewGuid().ToString() + ".flv";
|
||||
// Params = string.Format("-i {0} -y -ar 22050 -ab 64 -f flv {1}", input.Path, finalpath);
|
||||
// output = RunProcess(Params);
|
||||
|
||||
// if (File.Exists(finalpath))
|
||||
// {
|
||||
// ou.VideoStream = LoadMemoryStreamFromFile(finalpath);
|
||||
// try
|
||||
// {
|
||||
// File.Delete(finalpath);
|
||||
// }
|
||||
// catch (Exception) { }
|
||||
// }
|
||||
// return ou;
|
||||
// }
|
||||
// #endregion
|
||||
// }
|
||||
|
||||
// public class VideoFile
|
||||
// {
|
||||
// #region Properties
|
||||
// private string _Path;
|
||||
// public string Path
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return _Path;
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// _Path = value;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public TimeSpan Duration { get; set; }
|
||||
// public double BitRate { get; set; }
|
||||
// public string AudioFormat { get; set; }
|
||||
// public string VideoFormat { get; set; }
|
||||
// public int Height { get; set; }
|
||||
// public int Width { get; set; }
|
||||
// public string RawInfo { get; set; }
|
||||
// public bool infoGathered { get; set; }
|
||||
// #endregion
|
||||
|
||||
// #region Constructors
|
||||
// public VideoFile(string path)
|
||||
// {
|
||||
// _Path = path;
|
||||
// Initialize();
|
||||
// }
|
||||
// #endregion
|
||||
|
||||
// #region Initialization
|
||||
// private void Initialize()
|
||||
// {
|
||||
// this.infoGathered = false;
|
||||
// //first make sure we have a value for the video file setting
|
||||
// if (string.IsNullOrEmpty(_Path))
|
||||
// {
|
||||
// throw new Exception("Could not find the location of the video file");
|
||||
// }
|
||||
|
||||
// //Now see if the video file exists
|
||||
// if (!File.Exists(_Path))
|
||||
// {
|
||||
// throw new Exception("The video file " + _Path + " does not exist.");
|
||||
// }
|
||||
// }
|
||||
// #endregion
|
||||
// }
|
||||
|
||||
// public class OutputPackage
|
||||
// {
|
||||
// public MemoryStream VideoStream { get; set; }
|
||||
// public System.Drawing.Image PreviewImage { get; set; }
|
||||
// public string RawOutput { get; set; }
|
||||
// public bool Success { get; set; }
|
||||
// }
|
||||
//}
|
||||
public class OutputPackage
|
||||
{
|
||||
public MemoryStream VideoStream { get; set; }
|
||||
public System.Drawing.Image PreviewImage { get; set; }
|
||||
public string RawOutput { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,14 +73,14 @@ namespace BizHawk.MultiClient
|
|||
//we could background thread this later instead if we wanted to be real clever
|
||||
NES.BootGodDB.GetDatabaseBytes = () =>
|
||||
{
|
||||
using (HawkFile NesCartFile = new HawkFile(PathManager.GetExePathAbsolute() + "\\NesCarts.7z").BindFirst())
|
||||
using (HawkFile NesCartFile = new HawkFile(PathManager.GetExeDirectoryAbsolute() + "\\NesCarts.7z").BindFirst())
|
||||
return Util.ReadAllBytes(NesCartFile.GetStream());
|
||||
};
|
||||
Global.MainForm = this;
|
||||
Global.CoreInputComm = new CoreInputComm();
|
||||
SyncCoreInputComm();
|
||||
|
||||
Database.LoadDatabase(PathManager.GetExePathAbsolute() + "\\gamedb.txt");
|
||||
Database.LoadDatabase(PathManager.GetExeDirectoryAbsolute() + "\\gamedb.txt");
|
||||
|
||||
SyncPresentationMode();
|
||||
|
||||
|
|
|
@ -2,6 +2,17 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
//cue format preferences notes
|
||||
|
||||
//pcejin -
|
||||
//does not like session commands
|
||||
//it can handle binpercue
|
||||
//it seems not to be able to handle binpertrack, or maybe i am doing something wrong (still havent ruled it out)
|
||||
|
||||
//isobuster -
|
||||
//does not like onebinpertrack images with index 00
|
||||
|
||||
|
||||
namespace BizHawk
|
||||
{
|
||||
class DiscoHawk
|
||||
|
@ -13,8 +24,41 @@ namespace BizHawk
|
|||
|
||||
void Run(string[] args)
|
||||
{
|
||||
//string testfile = @"d:\Radiant Silvergun (J)\Radiant Silvergun (J).cue";
|
||||
//var disc = Disc.Disc.FromCuePath(testfile);
|
||||
//string exedir = BizHawk.MultiClient.PathManager.GetExeDirectoryAbsolute();
|
||||
//ffMpeg.Converter._ffExe = Path.Combine(exedir, "ffmpeg.exe");
|
||||
|
||||
////cue+bin+mp3 tests
|
||||
//var conv = new ffMpeg.Converter();
|
||||
////conv.WorkingPath = Environment.GetEnvironmentVariable("TEMP");
|
||||
////var vf = conv.GetVideoInfo(@"D:\isos\scd\persia\Prince of Persia 01.mp3");
|
||||
//var o = conv.ConvertToFLV(@"D:\isos\scd\persia\Prince of Persia 01.mp3");
|
||||
|
||||
////-i mp3file.mp3 -f wav outfile.wav
|
||||
|
||||
|
||||
//Disc.CueBin munged;
|
||||
//Disc.CueBinPrefs prefs = new Disc.CueBinPrefs();
|
||||
//prefs.SingleSession = true;
|
||||
//Disc.Disc disc;
|
||||
|
||||
//string testfile = @"D:\isos\pcecd\cosmicfantasy2\Cosmic Fantasy II [U][CD][WTG990301][Telenet Japan][1992][PCE][thx-1138-darkwater].cue";
|
||||
//disc = Disc.Disc.FromCuePath(testfile);
|
||||
//prefs.ReallyDumpBin = true;
|
||||
//prefs.AnnotateCue = false;
|
||||
//prefs.OneBinPerTrack = true;
|
||||
//prefs.PreferPregapCommand = false;
|
||||
//munged = disc.DumpCueBin("test", prefs);
|
||||
//munged.Dump("d:\\test", prefs);
|
||||
//File.WriteAllText("d:\\test\\redump.txt", munged.CreateRedumpReport());
|
||||
|
||||
//try roundtripping back to one file
|
||||
//disc = Disc.Disc.FromCuePath("d:\\test\\test.cue");
|
||||
//prefs.ReallyDumpBin = false;
|
||||
//prefs.OneBinPerTrack = false;
|
||||
//prefs.PreferPregapCommand = true;
|
||||
//munged = disc.DumpCueBin("one", prefs);
|
||||
//munged.Dump("d:\\test", prefs);
|
||||
|
||||
|
||||
//string testfile = @"r:\isos\memtest86-3.2.iso";
|
||||
//var disc = Disc.Disc.FromIsoPath(testfile);
|
||||
|
@ -22,7 +66,7 @@ namespace BizHawk
|
|||
//Console.WriteLine(disc.ReadTOC().DebugPrint());
|
||||
//disc.DumpBin_2352("d:\\test.2352");
|
||||
|
||||
//test reading the subcode data. unfortunately we don't have lead-in subcode so we have no TOC
|
||||
////test reading the subcode data. unfortunately we don't have lead-in subcode so we have no TOC
|
||||
//using (FileStream fs = File.OpenRead("c:\\bof4.sub"))
|
||||
//{
|
||||
// Disc.SubcodeStream stream = new Disc.SubcodeStream(fs, 0);
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
<Project>{197D4314-8A9F-49BA-977D-54ACEFAEB6BA}</Project>
|
||||
<Name>BizHawk.Emulation</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BizHawk.MultiClient\BizHawk.MultiClient.csproj">
|
||||
<Project>{DD448B37-BA3F-4544-9754-5406E8094723}</Project>
|
||||
<Name>BizHawk.MultiClient</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\BizHawk.Util\BizHawk.Util.csproj">
|
||||
<Project>{EE135301-08B3-4EFC-A61C-1C53E1C65CB9}</Project>
|
||||
<Name>BizHawk.Util</Name>
|
||||
|
|
Loading…
Reference in New Issue