2015-06-28 08:51:45 +00:00
|
|
|
using System;
|
|
|
|
using System.IO;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
namespace BizHawk.Emulation.DiscSystem
|
|
|
|
{
|
|
|
|
partial class CUE_Format2
|
|
|
|
{
|
2015-07-01 10:26:10 +00:00
|
|
|
|
2015-06-28 08:51:45 +00:00
|
|
|
abstract class SS_Base : ISectorSynthJob2448
|
|
|
|
{
|
2015-06-28 10:33:10 +00:00
|
|
|
public IBlob Blob;
|
|
|
|
public long BlobOffset;
|
2015-06-28 08:51:45 +00:00
|
|
|
public SubchannelQ sq;
|
2015-07-02 01:28:02 +00:00
|
|
|
public bool Pause, Gap;
|
|
|
|
public CueFile.TrackType TrackType;
|
|
|
|
public DiscMountPolicy Policy;
|
2015-06-28 08:51:45 +00:00
|
|
|
|
|
|
|
public abstract void Synth(SectorSynthJob job);
|
|
|
|
|
2015-07-02 01:28:02 +00:00
|
|
|
//"as needed"
|
2015-07-01 09:18:48 +00:00
|
|
|
protected void SynthSubcode(SectorSynthJob job)
|
2015-06-28 08:51:45 +00:00
|
|
|
{
|
2015-07-01 10:26:10 +00:00
|
|
|
//synth P if needed
|
2015-07-01 09:18:48 +00:00
|
|
|
if ((job.Parts & ESectorSynthPart.SubchannelP) != 0)
|
|
|
|
{
|
2015-07-01 09:44:03 +00:00
|
|
|
SynthUtils.SubP(job.DestBuffer2448, job.DestOffset + 2352, Pause);
|
2015-07-01 09:18:48 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 10:26:10 +00:00
|
|
|
//synth Q if needed
|
2015-07-01 09:18:48 +00:00
|
|
|
if ((job.Parts & ESectorSynthPart.SubchannelQ) != 0)
|
|
|
|
{
|
|
|
|
var subcode = new BufferedSubcodeSector();
|
|
|
|
subcode.Synthesize_SubchannelQ(ref sq, true);
|
|
|
|
Buffer.BlockCopy(subcode.SubcodeDeinterleaved, 12, job.DestBuffer2448, job.DestOffset + 2352 + 12, 12);
|
|
|
|
}
|
2015-07-01 10:26:10 +00:00
|
|
|
|
|
|
|
//clear R-W if needed
|
|
|
|
if ((job.Parts & ESectorSynthPart.Subchannel_RSTUVW) != 0)
|
|
|
|
{
|
|
|
|
Array.Clear(job.DestBuffer2448, job.DestOffset + 2352 + 12 + 12, (12 * 6));
|
|
|
|
}
|
|
|
|
|
|
|
|
//subcode has been generated deinterleaved; we may still need to interleave it
|
|
|
|
if ((job.Parts & (ESectorSynthPart.SubcodeDeinterleave)) == 0)
|
|
|
|
{
|
|
|
|
SubcodeUtils.InterleaveInplace(job.DestBuffer2448, job.DestOffset + 2352);
|
|
|
|
}
|
2015-06-28 08:51:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-01 09:18:48 +00:00
|
|
|
static class SynthUtils
|
2015-06-28 08:51:45 +00:00
|
|
|
{
|
2015-07-01 09:44:03 +00:00
|
|
|
public static void SubP(byte[] buffer, int offset, bool pause)
|
2015-06-28 08:51:45 +00:00
|
|
|
{
|
|
|
|
byte val = (byte)(pause?0xFF:0x00);
|
|
|
|
for (int i = 0; i < 12; i++)
|
|
|
|
buffer[offset + i] = val;
|
|
|
|
}
|
2015-07-01 09:18:48 +00:00
|
|
|
|
2015-07-01 09:44:03 +00:00
|
|
|
public static void SectorHeader(byte[] buffer, int offset, int LBA, byte mode)
|
2015-07-01 09:18:48 +00:00
|
|
|
{
|
|
|
|
buffer[offset + 0] = 0x00;
|
|
|
|
for (int i = 1; i < 11; i++) buffer[offset + i] = 0xFF;
|
|
|
|
buffer[offset + 11] = 0x00;
|
|
|
|
Timestamp ts = new Timestamp(LBA + 150);
|
2015-07-01 10:26:10 +00:00
|
|
|
buffer[offset + 12] = BCD2.IntToBCD(ts.MIN);
|
|
|
|
buffer[offset + 13] = BCD2.IntToBCD(ts.SEC);
|
|
|
|
buffer[offset + 14] = BCD2.IntToBCD(ts.FRAC);
|
2015-07-01 09:18:48 +00:00
|
|
|
buffer[offset + 15] = mode;
|
|
|
|
}
|
2015-06-28 08:51:45 +00:00
|
|
|
|
2015-07-02 01:28:02 +00:00
|
|
|
public static void EDC_Mode2_Form1(byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
uint edc = ECM.EDC_Calc(buffer, offset + 16, 2048 + 8);
|
|
|
|
ECM.PokeUint(buffer, offset + 2072, edc);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void EDC_Mode2_Form2(byte[] buffer, int offset)
|
|
|
|
{
|
|
|
|
uint edc = ECM.EDC_Calc(buffer, offset + 16, 2324+8);
|
|
|
|
ECM.PokeUint(buffer, offset + 2348, edc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-01 09:44:03 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Make sure everything else in the sector userdata is done before calling this
|
|
|
|
/// </summary>
|
|
|
|
public static void ECM_Mode1(byte[] buffer, int offset, int LBA)
|
2015-06-28 08:51:45 +00:00
|
|
|
{
|
2015-07-01 09:44:03 +00:00
|
|
|
//EDC
|
|
|
|
uint edc = ECM.EDC_Calc(buffer, offset, 2064);
|
2015-07-02 01:28:02 +00:00
|
|
|
ECM.PokeUint(buffer, offset + 2064, edc);
|
2015-07-01 09:44:03 +00:00
|
|
|
|
|
|
|
//reserved, zero
|
|
|
|
for (int i = 0; i < 8; i++) buffer[offset + 2068 + i] = 0;
|
2015-07-01 09:18:48 +00:00
|
|
|
|
2015-07-01 09:44:03 +00:00
|
|
|
//ECC
|
|
|
|
ECM.ECC_Populate(buffer, offset, buffer, offset, false);
|
2015-07-01 09:18:48 +00:00
|
|
|
}
|
|
|
|
}
|
2015-06-28 08:51:45 +00:00
|
|
|
|
2015-07-01 09:18:48 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Represents a Mode1 2048-byte sector
|
|
|
|
/// </summary>
|
|
|
|
class SS_Mode1_2048 : SS_Base
|
|
|
|
{
|
|
|
|
public override void Synth(SectorSynthJob job)
|
|
|
|
{
|
|
|
|
//read the sector user data
|
|
|
|
if((job.Parts & ESectorSynthPart.User2048) != 0)
|
|
|
|
Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset + 16, 2048);
|
|
|
|
|
|
|
|
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
2015-07-02 01:28:02 +00:00
|
|
|
SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, 1);
|
2015-07-01 09:44:03 +00:00
|
|
|
|
|
|
|
if ((job.Parts & ESectorSynthPart.ECMAny) != 0)
|
|
|
|
SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA);
|
2015-07-01 09:18:48 +00:00
|
|
|
|
|
|
|
SynthSubcode(job);
|
2015-06-28 08:51:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-01 09:44:03 +00:00
|
|
|
/// <summary>
|
2015-07-01 11:00:38 +00:00
|
|
|
/// Represents a data pregap or postgap sector.
|
|
|
|
/// The Pause flag isn't set in here because it might need special logic varying between sectors and so that's setup by the cue loader
|
2015-07-01 09:44:03 +00:00
|
|
|
/// Implemented as another sector type with a blob reading all zeros
|
|
|
|
/// </summary>
|
2015-07-01 11:00:38 +00:00
|
|
|
class SS_DataGap : SS_Mode1_2048
|
2015-07-01 09:44:03 +00:00
|
|
|
{
|
2015-07-01 11:00:38 +00:00
|
|
|
public SS_DataGap()
|
|
|
|
{
|
|
|
|
Blob = new Disc.Blob_Zeros();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Represents an audio pregap or postgap sector.
|
|
|
|
/// The Pause flag isn't set in here because it might need special logic varying between sectors and so that's setup by the cue loader
|
|
|
|
/// Implemented as another sector type with a blob reading all zeros
|
|
|
|
/// </summary>
|
|
|
|
class SS_AudioGap : SS_2352
|
|
|
|
{
|
|
|
|
public SS_AudioGap()
|
2015-07-01 09:44:03 +00:00
|
|
|
{
|
|
|
|
Blob = new Disc.Blob_Zeros();
|
|
|
|
}
|
|
|
|
}
|
2015-07-01 09:18:48 +00:00
|
|
|
|
2015-07-02 01:28:02 +00:00
|
|
|
class SS_Gap : SS_Base
|
|
|
|
{
|
|
|
|
//public CueFile.TrackType TrackType; //shouldnt be in base class...
|
|
|
|
public override void Synth(SectorSynthJob job)
|
|
|
|
{
|
|
|
|
//this isn't fully analyzed/optimized
|
|
|
|
Array.Clear(job.DestBuffer2448, job.DestOffset, 2352);
|
|
|
|
|
|
|
|
byte mode = 255;
|
|
|
|
int form = -1;
|
|
|
|
switch (TrackType)
|
|
|
|
{
|
|
|
|
case CueFile.TrackType.Audio:
|
|
|
|
mode = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CueFile.TrackType.CDI_2352:
|
|
|
|
case CueFile.TrackType.Mode1_2352:
|
|
|
|
mode = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CueFile.TrackType.Mode2_2352:
|
|
|
|
mode = 2;
|
|
|
|
if (Policy.CUE_PregapMode2_As_XA_Form2)
|
|
|
|
{
|
|
|
|
job.DestBuffer2448[job.DestOffset + 12 + 6] = 0x20;
|
|
|
|
job.DestBuffer2448[job.DestOffset + 12 + 10] = 0x20;
|
|
|
|
}
|
|
|
|
form = 2; //no other choice right now really
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CueFile.TrackType.Mode1_2048:
|
|
|
|
mode = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CueFile.TrackType.Mode2_2336:
|
|
|
|
default:
|
|
|
|
throw new InvalidOperationException("Not supported: " + TrackType);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((job.Parts & ESectorSynthPart.Header16) != 0)
|
|
|
|
SynthUtils.SectorHeader(job.DestBuffer2448, job.DestOffset + 0, job.LBA, mode);
|
|
|
|
|
|
|
|
if (mode == 1)
|
|
|
|
{
|
|
|
|
if ((job.Parts & ESectorSynthPart.ECMAny) != 0)
|
|
|
|
SynthUtils.ECM_Mode1(job.DestBuffer2448, job.DestOffset + 0, job.LBA);
|
|
|
|
}
|
|
|
|
if (mode == 2 && form == 2)
|
|
|
|
{
|
|
|
|
SynthUtils.EDC_Mode2_Form2(job.DestBuffer2448, job.DestOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
SynthSubcode(job);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-28 08:51:45 +00:00
|
|
|
/// <summary>
|
2015-07-02 01:28:02 +00:00
|
|
|
/// Represents a 2352-byte sector of any sort
|
2015-06-28 08:51:45 +00:00
|
|
|
/// </summary>
|
|
|
|
class SS_2352 : SS_Base
|
|
|
|
{
|
|
|
|
public override void Synth(SectorSynthJob job)
|
|
|
|
{
|
|
|
|
//read the sector user data
|
|
|
|
Blob.Read(BlobOffset, job.DestBuffer2448, job.DestOffset, 2352);
|
|
|
|
|
|
|
|
//if subcode is needed, synthesize it
|
2015-07-01 09:18:48 +00:00
|
|
|
SynthSubcode(job);
|
2015-06-28 08:51:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|