BizHawk/BizHawk.Emulation.DiscSystem/CUE/CUE_Synths.cs

223 lines
6.2 KiB
C#
Raw Normal View History

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-06-28 08:51:45 +00:00
abstract class SS_Base : ISectorSynthJob2448
{
public IBlob Blob;
public long BlobOffset;
2015-06-28 08:51:45 +00:00
public SubchannelQ sq;
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);
//"as needed"
2015-07-01 09:18:48 +00:00
protected void SynthSubcode(SectorSynthJob job)
2015-06-28 08:51:45 +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
}
//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);
}
//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);
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
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);
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)
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>
/// 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>
class SS_DataGap : SS_Mode1_2048
2015-07-01 09:44:03 +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
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>
/// 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
}
}
}
}