コード例 #1
0
ファイル: SectorSynth.cs プロジェクト: TechnoTaff/BizHawk
        public void Synth(SectorSynthJob job)
        {
            //be lazy, just generate the whole sector unconditionally
            //this is mostly based on mednafen's approach, which was probably finely tailored for PSX
            //heres the comments on the subject:
            //  I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
            //  and the leadout entry together before extracting the D2 bit.  Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
            //  data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).

            var ses          = job.Disc.Structure.Sessions[SessionNumber];
            int lba_relative = job.LBA - ses.LeadoutTrack.LBA;

            //data is zero

            int ts  = lba_relative;
            int ats = job.LBA;

            const int ADR     = 0x1;         // Q channel data encodes position
            EControlQ control = ses.LeadoutTrack.Control;

            //ehhh? CDI?
            //if(toc.tracks[toc.last_track].valid)
            // control |= toc.tracks[toc.last_track].control & 0x4;
            //else if(toc.disc_type == DISC_TYPE_CD_I)
            // control |= 0x4;
            control |= (EControlQ)(((int)ses.LastInformationTrack.Control) & 4);

            SubchannelQ sq = new SubchannelQ();

            sq.SetStatus(ADR, control);
            sq.q_tno.BCDValue   = 0xAA;
            sq.q_index.BCDValue = 0x01;
            sq.Timestamp        = ts;
            sq.AP_Timestamp     = ats;
            sq.zero             = 0;

            //finally, rely on a gap sector to do the heavy lifting to synthesize this
            CUE.CueTrackType TrackType = CUE.CueTrackType.Audio;
            if (ses.LeadoutTrack.IsData)
            {
                if (job.Disc.TOC.Session1Format == SessionFormat.Type20_CDXA || job.Disc.TOC.Session1Format == SessionFormat.Type10_CDI)
                {
                    TrackType = CUE.CueTrackType.Mode2_2352;
                }
                else
                {
                    TrackType = CUE.CueTrackType.Mode1_2352;
                }
            }

            CUE.SS_Gap ss_gap = new CUE.SS_Gap()
            {
                Policy    = Policy,
                sq        = sq,
                TrackType = TrackType,
                Pause     = true             //?
            };

            ss_gap.Synth(job);
        }
コード例 #2
0
        /// <summary>
        /// Fills this subcode buffer with subchannel Q data. calculates the required CRC, as well.
        /// Returns the crc, calculated or otherwise.
        /// </summary>
        public ushort Synthesize_SubchannelQ(ref SubchannelQ sq, bool calculateCRC)
        {
            int offset = 12;             //Q subchannel begins after P, 12 bytes in

            SubcodeDeinterleaved[offset + 0] = sq.q_status;
            SubcodeDeinterleaved[offset + 1] = sq.q_tno;
            SubcodeDeinterleaved[offset + 2] = sq.q_index;
            SubcodeDeinterleaved[offset + 3] = sq.min.BCDValue;
            SubcodeDeinterleaved[offset + 4] = sq.sec.BCDValue;
            SubcodeDeinterleaved[offset + 5] = sq.frame.BCDValue;
            SubcodeDeinterleaved[offset + 6] = sq.zero;
            SubcodeDeinterleaved[offset + 7] = sq.ap_min.BCDValue;
            SubcodeDeinterleaved[offset + 8] = sq.ap_sec.BCDValue;
            SubcodeDeinterleaved[offset + 9] = sq.ap_frame.BCDValue;

            ushort crc16;

            if (calculateCRC)
            {
                crc16 = CRC16_CCITT.Calculate(SubcodeDeinterleaved, offset, 10);
            }
            else
            {
                crc16 = sq.q_crc;
            }

            //CRC is stored inverted and big endian
            SubcodeDeinterleaved[offset + 10] = (byte)(~(crc16 >> 8));
            SubcodeDeinterleaved[offset + 11] = (byte)(~(crc16));

            return(crc16);
        }
コード例 #3
0
        /// <summary>appends the new entries to the provided list</summary>
        /// <exception cref="InvalidOperationException"><see cref="IN_Session1Format"/> is <see cref="SessionFormat.None"/> or a non-member</exception>
        public void Run(List <RawTOCEntry> entries)
        {
            //NOTE: entries are inserted at the beginning due to observations of CCD indicating they might need to be that way
            //Since I'm being asked to synthesize them here, I guess I can put them in whatever order I want, can't I?

            SubchannelQ sq = new SubchannelQ();

            //ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
            const int kADR            = 1;
            const int kUnknownControl = 0;

            sq.SetStatus(kADR, (EControlQ)kUnknownControl);

            //first recorded track number:
            sq.q_index.BCDValue    = 0xA0;
            sq.ap_min.DecimalValue = IN_FirstRecordedTrackNumber;
            switch (IN_Session1Format)
            {
            //TODO these probably shouldn't be decimal values
            case SessionFormat.Type00_CDROM_CDDA: sq.ap_sec.DecimalValue = 0x00; break;

            case SessionFormat.Type10_CDI: sq.ap_sec.DecimalValue = 0x10; break;

            case SessionFormat.Type20_CDXA: sq.ap_sec.DecimalValue = 0x20; break;

            default: throw new InvalidOperationException("Invalid Session1Format");
            }
            sq.ap_frame.DecimalValue = 0;

            entries.Insert(0, new RawTOCEntry {
                QData = sq
            });

            //last recorded track number:
            sq.q_index.BCDValue      = 0xA1;
            sq.ap_min.DecimalValue   = IN_LastRecordedTrackNumber;
            sq.ap_sec.DecimalValue   = 0;
            sq.ap_frame.DecimalValue = 0;

            entries.Insert(1, new RawTOCEntry {
                QData = sq
            });

            //leadout:
            sq.q_index.BCDValue = 0xA2;
            sq.AP_Timestamp     = IN_LeadoutTimestamp;

            entries.Insert(2, new RawTOCEntry {
                QData = sq
            });
        }
コード例 #4
0
        private RawTOCEntry EmitRawTOCEntry(ATOCEntry entry)
        {
            BCD2 tno, ino;

            //this should actually be zero. im not sure if this is stored as BCD2 or not
            tno = BCD2.FromDecimal(entry.TrackNo);

            //these are special values.. I think, taken from this:
            //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
            //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
            //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
            ino = BCD2.FromDecimal(entry.Point);
            if (entry.Point == 0xA0)
            {
                ino.BCDValue = 0xA0;
            }
            else if (entry.Point == 0xA1)
            {
                ino.BCDValue = 0xA1;
            }
            else if (entry.Point == 0xA2)
            {
                ino.BCDValue = 0xA2;
            }

            // get ADR & Control from ADR_Control byte
            byte adrc    = Convert.ToByte(entry.ADR_Control);
            var  Control = adrc & 0x0F;
            var  ADR     = adrc >> 4;

            var q = new SubchannelQ
            {
                q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)),
                q_tno    = tno,
                q_index  = ino,
                min      = BCD2.FromDecimal(entry.AMin),
                sec      = BCD2.FromDecimal(entry.ASec),
                frame    = BCD2.FromDecimal(entry.AFrame),
                zero     = (byte)entry.Zero,
                ap_min   = BCD2.FromDecimal(entry.PMin),
                ap_sec   = BCD2.FromDecimal(entry.PSec),
                ap_frame = BCD2.FromDecimal(entry.PFrame),
                q_crc    = 0,              //meaningless
            };

            return(new RawTOCEntry {
                QData = q
            });
        }
コード例 #5
0
ファイル: SynthUtils.cs プロジェクト: tustin2121/tpp-BizHawk2
        /// <summary>
        /// Serializes the provided SubchannelQ structure into a buffer
        /// Returns the crc, calculated or otherwise.
        /// </summary>
        public static ushort SubQ_Serialize(byte[] buf12, int offset, ref SubchannelQ sq)
        {
            buf12[offset + 0] = sq.q_status;
            buf12[offset + 1] = sq.q_tno.BCDValue;
            buf12[offset + 2] = sq.q_index.BCDValue;
            buf12[offset + 3] = sq.min.BCDValue;
            buf12[offset + 4] = sq.sec.BCDValue;
            buf12[offset + 5] = sq.frame.BCDValue;
            buf12[offset + 6] = sq.zero;
            buf12[offset + 7] = sq.ap_min.BCDValue;
            buf12[offset + 8] = sq.ap_sec.BCDValue;
            buf12[offset + 9] = sq.ap_frame.BCDValue;

            return(SubQ_SynthChecksum(buf12, offset));
        }
コード例 #6
0
ファイル: SynthUtils.cs プロジェクト: CadeLaRen/BizHawk
		/// <summary>
		/// Serializes the provided SubchannelQ structure into a buffer
		/// Returns the crc, calculated or otherwise.
		/// </summary>
		public static ushort SubQ_Serialize(byte[] buf12, int offset, ref SubchannelQ sq)
		{
			buf12[offset + 0] = sq.q_status;
			buf12[offset + 1] = sq.q_tno.BCDValue;
			buf12[offset + 2] = sq.q_index.BCDValue;
			buf12[offset + 3] = sq.min.BCDValue;
			buf12[offset + 4] = sq.sec.BCDValue;
			buf12[offset + 5] = sq.frame.BCDValue;
			buf12[offset + 6] = sq.zero;
			buf12[offset + 7] = sq.ap_min.BCDValue;
			buf12[offset + 8] = sq.ap_sec.BCDValue;
			buf12[offset + 9] = sq.ap_frame.BCDValue;

			return SubQ_SynthChecksum(buf12, offset);
		}
コード例 #7
0
		/// <summary>
		/// Appends the new entries to the provided list
		/// </summary>
		public void Run(List<RawTOCEntry> entries)
		{
			//NOTE: entries are inserted at the beginning due to observations of CCD indicating they might need to be that way
			//Since I'm being asked to synthesize them here, I guess I can put them in whatever order I want, can't I?

			SubchannelQ sq = new SubchannelQ();

			//ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
			const int kADR = 1;
			const int kUnknownControl = 0;

			sq.SetStatus(kADR, (EControlQ)kUnknownControl);

			//first recorded track number:
			sq.q_index.BCDValue = 0xA0;
			sq.ap_min.DecimalValue = IN_FirstRecordedTrackNumber;
			switch(IN_Session1Format)
			{
				//TODO these probably shouldn't be decimal values
				case SessionFormat.Type00_CDROM_CDDA: sq.ap_sec.DecimalValue = 0x00; break;
				case SessionFormat.Type10_CDI: sq.ap_sec.DecimalValue = 0x10; break;
				case SessionFormat.Type20_CDXA: sq.ap_sec.DecimalValue = 0x20; break;
				default: throw new InvalidOperationException("Invalid Session1Format");
			}
			sq.ap_frame.DecimalValue = 0;

			entries.Insert(0, new RawTOCEntry { QData = sq });

			//last recorded track number:
			sq.q_index.BCDValue = 0xA1;
			sq.ap_min.DecimalValue = IN_LastRecordedTrackNumber;
			sq.ap_sec.DecimalValue = 0;
			sq.ap_frame.DecimalValue = 0;

			entries.Insert(1, new RawTOCEntry { QData = sq });

			//leadout:
			sq.q_index.BCDValue = 0xA2;
			sq.AP_Timestamp = IN_LeadoutTimestamp;

			entries.Insert(2, new RawTOCEntry { QData = sq });
		}
コード例 #8
0
ファイル: DiscSectorReader.cs プロジェクト: zcatt/BizHawk
        /// <summary>
        /// Reads 12 bytes of subQ data from a sector and stores it unpacked into the provided struct
        /// TODO - make use of deserialize code elsewhere
        /// </summary>
        public void ReadLBA_SubQ(int lba, out SubchannelQ sq)
        {
            ReadLBA_SubQ(lba, buf12, 0);

            sq.q_status          = buf12[0];
            sq.q_tno.BCDValue    = buf12[1];
            sq.q_index.BCDValue  = buf12[2];
            sq.min.BCDValue      = buf12[3];
            sq.sec.BCDValue      = buf12[4];
            sq.frame.BCDValue    = buf12[5];
            sq.zero              = buf12[6];
            sq.ap_min.BCDValue   = buf12[7];
            sq.ap_sec.BCDValue   = buf12[8];
            sq.ap_frame.BCDValue = buf12[9];

            //CRC is stored inverted and big endian.. so... do the opposite
            byte hibyte = (byte)(~buf12[10]);
            byte lobyte = (byte)(~buf12[11]);

            sq.q_crc = (ushort)((hibyte << 8) | lobyte);
        }
コード例 #9
0
        public void Run()
        {
            //TODO: encode_mode2_form2_sector

            var leadoutTs = Disc.TOC.LeadoutLBA;
            var lastTrackTOCItem = Disc.TOC.TOCItems[Disc.TOC.LastRecordedTrackNumber]; //NOTE: in case LastRecordedTrackNumber is al ie, this will malfunction

            //leadout flags.. let's set them the same as the last track.
            //THIS IS NOT EXACTLY THE SAME WAY MEDNAFEN DOES IT
            EControlQ leadoutFlags = lastTrackTOCItem.Control;

            //TODO - needs to be encoded as a certain mode (mode 2 form 2 for psx... i guess...)

            for (int i = 0; i < Length; i++)
            {
                //var se = new SectorEntry(sz);
                //Disc.Sectors.Add(se);
                SubchannelQ sq = new SubchannelQ();

                int track_relative_msf = i;
                sq.min = BCD2.FromDecimal(new Timestamp(track_relative_msf).MIN);
                sq.sec = BCD2.FromDecimal(new Timestamp(track_relative_msf).SEC);
                sq.frame = BCD2.FromDecimal(new Timestamp(track_relative_msf).FRAC);

                int absolute_msf = i + leadoutTs.Sector;
                sq.ap_min = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).MIN);
                sq.ap_sec = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).SEC);
                sq.ap_frame = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).FRAC);

                sq.q_tno.DecimalValue = 0xAA; //special value for leadout
                sq.q_index.DecimalValue = 1;

                byte ADR = 1;
                sq.SetStatus(ADR, leadoutFlags);

                //TODO - actually stash the subQ
            }
        }
コード例 #10
0
        public void Run()
        {
            //TODO: encode_mode2_form2_sector

            var leadoutTs        = Disc.TOC.LeadoutLBA;
            var lastTrackTOCItem = Disc.TOC.TOCItems[Disc.TOC.LastRecordedTrackNumber];             //NOTE: in case LastRecordedTrackNumber is al ie, this will malfunction

            //leadout flags.. let's set them the same as the last track.
            //THIS IS NOT EXACTLY THE SAME WAY MEDNAFEN DOES IT
            EControlQ leadoutFlags = lastTrackTOCItem.Control;

            //TODO - needs to be encoded as a certain mode (mode 2 form 2 for psx... i guess...)

            for (int i = 0; i < Length; i++)
            {
                //var se = new SectorEntry(sz);
                //Disc.Sectors.Add(se);
                SubchannelQ sq = new SubchannelQ();

                int track_relative_msf = i;
                sq.min   = BCD2.FromDecimal(new Timestamp(track_relative_msf).MIN);
                sq.sec   = BCD2.FromDecimal(new Timestamp(track_relative_msf).SEC);
                sq.frame = BCD2.FromDecimal(new Timestamp(track_relative_msf).FRAC);

                int absolute_msf = i + leadoutTs;
                sq.ap_min   = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).MIN);
                sq.ap_sec   = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).SEC);
                sq.ap_frame = BCD2.FromDecimal(new Timestamp(absolute_msf + 150).FRAC);

                sq.q_tno.DecimalValue   = 0xAA;               //special value for leadout
                sq.q_index.DecimalValue = 1;

                byte ADR = 1;
                sq.SetStatus(ADR, leadoutFlags);

                //TODO - actually stash the subQ
            }
        }
コード例 #11
0
        public void ReadLBA_SubchannelQ(int lba, ref SubchannelQ sq)
        {
            var se = disc.ReadLBA_SectorEntry(lba);

            se.SubcodeSector.ReadSubcodeChannel(1, buffer, 0);
            int offset = 0;

            sq.q_status       = buffer[offset + 0];
            sq.q_tno          = buffer[offset + 1];
            sq.q_index        = buffer[offset + 2];
            sq.min.BCDValue   = buffer[offset + 3];
            sq.sec.BCDValue   = buffer[offset + 4];
            sq.frame.BCDValue = buffer[offset + 5];
            //nothing in byte[6]
            sq.ap_min.BCDValue   = buffer[offset + 7];
            sq.ap_sec.BCDValue   = buffer[offset + 8];
            sq.ap_frame.BCDValue = buffer[offset + 9];

            //CRC is stored inverted and big endian.. so... do the opposite
            byte hibyte = (byte)(~buffer[offset + 10]);
            byte lobyte = (byte)(~buffer[offset + 11]);

            sq.q_crc = (ushort)((hibyte << 8) | lobyte);
        }
コード例 #12
0
ファイル: Disc.cs プロジェクト: metalloidSmashes/BizHawk
        /// <summary>
        /// Creates the subcode (really, just subchannel Q) for this disc from its current TOC.
        /// Depends on the TOCPoints existing in the structure
        /// TODO - do we need a fully 0xFF P-subchannel for PSX?
        /// </summary>
        void Synthesize_SubcodeFromStructure()
        {
            int aba     = 0;
            int dpIndex = 0;

            //TODO - from mednafen (on PC-FX chip chan kick)
            //If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track,
            //and the preceding track is an audio track, encode it as audio(by taking the SubQ control field from the preceding

            //NOTE: discs may have subcode which is nonsense or possibly not recoverable from a sensible disc structure.
            //but this function does what it says.

            //SO: heres the main idea of how this works.
            //we have the Structure.Points (whose name we dont like) which is a list of sectors where the tno/index changes.
            //So for each sector, we see if we've advanced to the next point.
            //TODO - check if this is synthesized correctly when producing a structure from a TOCRaw
            while (aba < Sectors.Count)
            {
                if (dpIndex < Structure.Points.Count - 1)
                {
                    while (aba >= Structure.Points[dpIndex + 1].ABA)
                    {
                        dpIndex++;
                    }
                }
                var dp = Structure.Points[dpIndex];


                var se = Sectors[aba];

                EControlQ control = dp.Control;
                bool      pause   = true;
                if (dp.Num != 0)                 //TODO - shouldnt this be IndexNum?
                {
                    pause = false;
                }
                if ((dp.Control & EControlQ.DataUninterrupted) != 0)
                {
                    pause = false;
                }

                int adr = dp.ADR;

                SubchannelQ sq = new SubchannelQ();
                sq.q_status = SubchannelQ.ComputeStatus(adr, control);
                sq.q_tno    = BCD2.FromDecimal(dp.TrackNum).BCDValue;
                sq.q_index  = BCD2.FromDecimal(dp.IndexNum).BCDValue;

                int track_relative_aba = aba - dp.Track.Indexes[1].aba;
                track_relative_aba = Math.Abs(track_relative_aba);
                Timestamp track_relative_timestamp = new Timestamp(track_relative_aba);
                sq.min   = BCD2.FromDecimal(track_relative_timestamp.MIN);
                sq.sec   = BCD2.FromDecimal(track_relative_timestamp.SEC);
                sq.frame = BCD2.FromDecimal(track_relative_timestamp.FRAC);
                sq.zero  = 0;
                Timestamp absolute_timestamp = new Timestamp(aba);
                sq.ap_min   = BCD2.FromDecimal(absolute_timestamp.MIN);
                sq.ap_sec   = BCD2.FromDecimal(absolute_timestamp.SEC);
                sq.ap_frame = BCD2.FromDecimal(absolute_timestamp.FRAC);

                var bss = new BufferedSubcodeSector();
                bss.Synthesize_SubchannelQ(ref sq, true);

                //TEST: need this for psx?
                if (pause)
                {
                    bss.Synthesize_SubchannelP(true);
                }

                se.SubcodeSector = bss;

                aba++;
            }
        }
コード例 #13
0
ファイル: Disc.cs プロジェクト: cas1993per/bizhawk
        /// <summary>
        /// Creates the subcode (really, just subchannel Q) for this disc from its current TOC.
        /// Depends on the TOCPoints existing in the structure
        /// TODO - do we need a fully 0xFF P-subchannel for PSX?
        /// </summary>
        void Synthesize_SubcodeFromStructure()
        {
            int aba = 0;
            int dpIndex = 0;

            //TODO - from mednafen (on PC-FX chip chan kick)
            //If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track,
            //and the preceding track is an audio track, encode it as audio(by taking the SubQ control field from the preceding

            //NOTE: discs may have subcode which is nonsense or possibly not recoverable from a sensible disc structure.
            //but this function does what it says.

            //SO: heres the main idea of how this works.
            //we have the Structure.Points (whose name we dont like) which is a list of sectors where the tno/index changes.
            //So for each sector, we see if we've advanced to the next point.
            //TODO - check if this is synthesized correctly when producing a structure from a TOCRaw
            while (aba < Sectors.Count)
            {
                if (dpIndex < Structure.Points.Count - 1)
                {
                    while (aba >= Structure.Points[dpIndex + 1].ABA)
                    {
                        dpIndex++;
                    }
                }
                var dp = Structure.Points[dpIndex];

                var se = Sectors[aba];

                EControlQ control = dp.Control;
                bool pause = true;
                if (dp.Num != 0) //TODO - shouldnt this be IndexNum?
                    pause = false;
                if ((dp.Control & EControlQ.DataUninterrupted)!=0)
                    pause = false;

                int adr = dp.ADR;

                SubchannelQ sq = new SubchannelQ();
                sq.q_status = SubchannelQ.ComputeStatus(adr, control);
                sq.q_tno = BCD2.FromDecimal(dp.TrackNum).BCDValue;
                sq.q_index = BCD2.FromDecimal(dp.IndexNum).BCDValue;

                int track_relative_aba = aba - dp.Track.Indexes[1].aba;
                track_relative_aba = Math.Abs(track_relative_aba);
                Timestamp track_relative_timestamp = new Timestamp(track_relative_aba);
                sq.min = BCD2.FromDecimal(track_relative_timestamp.MIN);
                sq.sec = BCD2.FromDecimal(track_relative_timestamp.SEC);
                sq.frame = BCD2.FromDecimal(track_relative_timestamp.FRAC);
                sq.zero = 0;
                Timestamp absolute_timestamp = new Timestamp(aba);
                sq.ap_min = BCD2.FromDecimal(absolute_timestamp.MIN);
                sq.ap_sec = BCD2.FromDecimal(absolute_timestamp.SEC);
                sq.ap_frame = BCD2.FromDecimal(absolute_timestamp.FRAC);

                var bss = new BufferedSubcodeSector();
                bss.Synthesize_SubchannelQ(ref sq, true);

                //TEST: need this for psx?
                if(pause) bss.Synthesize_SubchannelP(true);

                se.SubcodeSector = bss;

                aba++;
            }
        }
コード例 #14
0
ファイル: Subcode.cs プロジェクト: cas1993per/bizhawk
        /// <summary>
        /// Fills this subcode buffer with subchannel Q data. calculates the required CRC, as well.
        /// Returns the crc, calculated or otherwise.
        /// </summary>
        public ushort Synthesize_SubchannelQ(ref SubchannelQ sq, bool calculateCRC)
        {
            int offset = 12; //Q subchannel begins after P, 12 bytes in
            SubcodeDeinterleaved[offset + 0] = sq.q_status;
            SubcodeDeinterleaved[offset + 1] = sq.q_tno;
            SubcodeDeinterleaved[offset + 2] = sq.q_index;
            SubcodeDeinterleaved[offset + 3] = sq.min.BCDValue;
            SubcodeDeinterleaved[offset + 4] = sq.sec.BCDValue;
            SubcodeDeinterleaved[offset + 5] = sq.frame.BCDValue;
            SubcodeDeinterleaved[offset + 6] = sq.zero;
            SubcodeDeinterleaved[offset + 7] = sq.ap_min.BCDValue;
            SubcodeDeinterleaved[offset + 8] = sq.ap_sec.BCDValue;
            SubcodeDeinterleaved[offset + 9] = sq.ap_frame.BCDValue;

            ushort crc16;
            if (calculateCRC)
                crc16 = CRC16_CCITT.Calculate(SubcodeDeinterleaved, offset, 10);
            else crc16 = sq.q_crc;

            //CRC is stored inverted and big endian
            SubcodeDeinterleaved[offset + 10] = (byte)(~(crc16 >> 8));
            SubcodeDeinterleaved[offset + 11] = (byte)(~(crc16));

            return crc16;
        }
コード例 #15
0
        /// <summary>
        /// Loads a CCD at the specified path to a Disc object
        /// </summary>
        public Disc LoadCCDToDisc(string ccdPath)
        {
            var loadResults = LoadCCDPath(ccdPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            var ccdf    = loadResults.ParsedCCDFile;
            var imgBlob = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.ImgPath
            };
            var subBlob = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.SubPath
            };

            disc.Blobs.Add(imgBlob);
            disc.Blobs.Add(subBlob);

            //generate DiscTOCRaw items from the ones specified in the CCD file
            //TODO - range validate these (too many truncations to byte)
            disc.RawTOCEntries = new List <RawTOCEntry>();
            BufferedSubcodeSector bss = new BufferedSubcodeSector();

            foreach (var entry in ccdf.TOCEntries)
            {
                var q = new SubchannelQ
                {
                    q_status = SubchannelQ.ComputeStatus(entry.ADR, (EControlQ)(entry.Control & 0xF)),
                    q_tno    = (byte)entry.TrackNo,
                    q_index  = (byte)entry.Point,
                    min      = BCD2.FromDecimal(entry.AMin),
                    sec      = BCD2.FromDecimal(entry.ASec),
                    frame    = BCD2.FromDecimal(entry.AFrame),
                    zero     = (byte)entry.Zero,
                    ap_min   = BCD2.FromDecimal(entry.PMin),
                    ap_sec   = BCD2.FromDecimal(entry.PSec),
                    ap_frame = BCD2.FromDecimal(entry.PFrame),
                };

                //CRC cant be calculated til we've got all the fields setup
                q.q_crc = bss.Synthesize_SubchannelQ(ref q, true);

                disc.RawTOCEntries.Add(new RawTOCEntry {
                    QData = q
                });
            }

            //generate the toc from the entries
            var tocSynth = new DiscTOCRaw.SynthesizeFromRawTOCEntriesJob()
            {
                Entries = disc.RawTOCEntries
            };

            tocSynth.Run();
            disc.TOCRaw = tocSynth.Result;

            //synthesize DiscStructure
            var structureSynth = new DiscStructure.SynthesizeFromDiscTOCRawJob()
            {
                TOCRaw = disc.TOCRaw
            };

            structureSynth.Run();
            disc.Structure = structureSynth.Result;

            //I *think* implicitly there is an index 0.. at.. i dunno, 0 maybe, for track 1
            {
                var dsi0 = new DiscStructure.Index();
                dsi0.LBA    = 0;
                dsi0.Number = 0;
                disc.Structure.Sessions[0].Tracks[0].Indexes.Add(dsi0);
            }

            //now, how to get the track types for the DiscStructure?
            //1. the CCD tells us (somehow the reader has judged)
            //2. scan it out of the Q subchannel
            //lets choose1.
            //TODO - better consider how to handle the situation where we have havent received all the [TRACK] items we need
            foreach (var st in disc.Structure.Sessions[0].Tracks)
            {
                var ccdt = ccdf.TracksByNumber[st.Number];
                switch (ccdt.Mode)
                {
                case 0:
                    st.TrackType = ETrackType.Audio;                             //for CCD, this means audio, apparently.
                    break;

                case 1:
                    st.TrackType = ETrackType.Mode1_2352;
                    break;

                case 2:
                    st.TrackType = ETrackType.Mode2_2352;
                    break;

                default:
                    throw new InvalidOperationException("Unsupported CCD mode");
                }

                //add indexes for this track
                foreach (var ccdi in ccdt.Indexes)
                {
                    var dsi = new DiscStructure.Index();
                    //if (ccdi.Key == 0) continue;
                    dsi.LBA    = ccdi.Value;
                    dsi.Number = ccdi.Key;
                    st.Indexes.Add(dsi);
                }
            }

            //add sectors for the lead-in, which isn't stored in the CCD file, I think
            //TODO - synthesize lead-in sectors from TOC, if the lead-in isn't available.
            //need a test case for that though.
            var leadin_sector_zero  = new Sector_Zero();
            var leadin_subcode_zero = new ZeroSubcodeSector();

            for (int i = 0; i < 150; i++)
            {
                var se = new SectorEntry(leadin_sector_zero);
                disc.Sectors.Add(se);
                se.SubcodeSector = leadin_subcode_zero;
            }

            //build the sectors:
            //set up as many sectors as we have img/sub for, even if the TOC doesnt reference them (TOC is unreliable, although the tracks should have covered it all)
            for (int i = 0; i < loadResults.NumImgSectors; i++)
            {
                var isec = new Sector_RawBlob();
                isec.Offset = ((long)i) * 2352;
                isec.Blob   = imgBlob;

                var se = new SectorEntry(isec);
                disc.Sectors.Add(se);

                var scsec = new BlobSubcodeSectorPreDeinterleaved();
                scsec.Offset     = ((long)i) * 96;
                scsec.Blob       = subBlob;
                se.SubcodeSector = scsec;
            }

            return(disc);
        }
コード例 #16
0
ファイル: DiscSectorReader.cs プロジェクト: raiscan/BizHawk
        /// <summary>
        /// Reads 12 bytes of subQ data from a sector and stores it unpacked into the provided struct
        /// TODO - make use of deserialize code elsewhere
        /// </summary>
        public void ReadLBA_SubQ(int lba, out SubchannelQ sq)
        {
            ReadLBA_SubQ(lba, buf12, 0);

            sq.q_status = buf12[0];
            sq.q_tno.BCDValue = buf12[1];
            sq.q_index.BCDValue = buf12[2];
            sq.min.BCDValue = buf12[3];
            sq.sec.BCDValue = buf12[4];
            sq.frame.BCDValue = buf12[5];
            sq.zero = buf12[6];
            sq.ap_min.BCDValue = buf12[7];
            sq.ap_sec.BCDValue = buf12[8];
            sq.ap_frame.BCDValue = buf12[9];

            //CRC is stored inverted and big endian.. so... do the opposite
            byte hibyte = (byte)(~buf12[10]);
            byte lobyte = (byte)(~buf12[11]);
            sq.q_crc = (ushort)((hibyte << 8) | lobyte);
        }
コード例 #17
0
ファイル: SectorSynth.cs プロジェクト: raiscan/BizHawk
        public void Synth(SectorSynthJob job)
        {
            //be lazy, just generate the whole sector unconditionally
            //this is mostly based on mednafen's approach, which was probably finely tailored for PSX
            //heres the comments on the subject:
            //  I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
            //  and the leadout entry together before extracting the D2 bit.  Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
            //  data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).

            var ses = job.Disc.Structure.Sessions[SessionNumber];
            int lba_relative = job.LBA - ses.LeadoutTrack.LBA;

            //data is zero

            int ts = lba_relative;
            int ats = job.LBA;

            const int ADR = 0x1; // Q channel data encodes position
            EControlQ control = ses.LeadoutTrack.Control;

            //ehhh? CDI?
             //if(toc.tracks[toc.last_track].valid)
             // control |= toc.tracks[toc.last_track].control & 0x4;
             //else if(toc.disc_type == DISC_TYPE_CD_I)
             // control |= 0x4;
            control |= (EControlQ)(((int)ses.LastInformationTrack.Control) & 4);

            SubchannelQ sq = new SubchannelQ();
            sq.SetStatus(ADR, control);
            sq.q_tno.BCDValue = 0xAA;
            sq.q_index.BCDValue = 0x01;
            sq.Timestamp = ts;
            sq.AP_Timestamp = ats;
            sq.zero = 0;

            //finally, rely on a gap sector to do the heavy lifting to synthesize this
            CUE.CueTrackType TrackType = CUE.CueTrackType.Audio;
            if (ses.LeadoutTrack.IsData)
            {
                if (job.Disc.TOC.Session1Format == SessionFormat.Type20_CDXA || job.Disc.TOC.Session1Format == SessionFormat.Type10_CDI)
                    TrackType = CUE.CueTrackType.Mode2_2352;
                else
                    TrackType = CUE.CueTrackType.Mode1_2352;
            }

            CUE.SS_Gap ss_gap = new CUE.SS_Gap()
            {
                Policy = Policy,
                sq = sq,
                TrackType = TrackType,
                Pause = true //?
            };

            ss_gap.Synth(job);
        }
コード例 #18
0
        void RunMednaDisc()
        {
            var disc = new Disc();

            OUT_Disc = disc;

            //create a MednaDisc and give it to the disc for ownership
            var md = new MednaDisc(IN_FromPath);

            disc.DisposableResources.Add(md);

            //"length of disc" for bizhawk's purposes (NOT a robust concept!) is determined by beginning of leadout track
            var m_leadoutTrack = md.TOCTracks[100];
            int nSectors       = (int)m_leadoutTrack.lba;

            //make synth param memos
            disc.SynthParams.MednaDisc = md;

            //this is the sole sector synthesizer we'll need
            var synth = new SS_MednaDisc();

            OUT_Disc.SynthProvider = new SimpleSectorSynthProvider()
            {
                SS = synth
            };

            //ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
            const int kADR            = 1;
            const int kUnknownControl = 0;

            //mednafen delivers us what is essentially but not exactly (or completely) a TOCRaw.
            //we need to synth RawTOCEntries from this and then turn it into a proper TOCRaw
            //when coming from mednafen, there are 101 entries.
            //entry[0] is placeholder junk, not to be used
            //entry[100] is the leadout track (A0)
            //A1 and A2 are in the form of FirstRecordedTrackNumber and LastRecordedTrackNumber
            for (int i = 1; i < 101; i++)
            {
                var m_te = md.TOCTracks[i];

                //dont add invalid (absent) items
                if (!m_te.Valid)
                {
                    continue;
                }

                var m_ts = new Timestamp((int)m_te.lba + 150);                 //these are supposed to be absolute timestamps

                var q = new SubchannelQ
                {
                    q_status = SubchannelQ.ComputeStatus(kADR, (EControlQ)m_te.control),
                    q_tno    = BCD2.FromDecimal(0), //unknown with mednadisc
                    q_index  = BCD2.FromDecimal(i),
                    min      = BCD2.FromDecimal(0), //unknown with mednadisc
                    sec      = BCD2.FromDecimal(0), //unknown with mednadisc
                    frame    = BCD2.FromDecimal(0), //unknown with mednadisc
                    zero     = 0,                   //unknown with mednadisc
                    ap_min   = BCD2.FromDecimal(m_ts.MIN),
                    ap_sec   = BCD2.FromDecimal(m_ts.SEC),
                    ap_frame = BCD2.FromDecimal(m_ts.FRAC),
                    q_crc    = 0                  //meaningless
                };

                //a special fixup: mednafen's entry 100 is the lead-out track, so change it into the A2 raw toc entry
                if (i == 100)
                {
                    q.q_index.BCDValue = 0xA2;
                }

                disc.RawTOCEntries.Add(new RawTOCEntry {
                    QData = q
                });
            }

            //synth A0 and A1 entries (indicating first and last recorded tracks and also session type)
            var qA0 = new SubchannelQ
            {
                q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
                q_tno    = BCD2.FromDecimal(0), //unknown with mednadisc
                q_index  = BCD2.FromBCD(0xA0),
                min      = BCD2.FromDecimal(0), //unknown with mednadisc
                sec      = BCD2.FromDecimal(0), //unknown with mednadisc
                frame    = BCD2.FromDecimal(0), //unknown with mednadisc
                zero     = 0,                   //unknown with mednadisc
                ap_min   = BCD2.FromDecimal(md.TOC.first_track),
                ap_sec   = BCD2.FromDecimal(md.TOC.disc_type),
                ap_frame = BCD2.FromDecimal(0),
                q_crc    = 0,              //meaningless
            };

            disc.RawTOCEntries.Add(new RawTOCEntry {
                QData = qA0
            });
            var qA1 = new SubchannelQ
            {
                q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
                q_tno    = BCD2.FromDecimal(0), //unknown with mednadisc
                q_index  = BCD2.FromBCD(0xA1),
                min      = BCD2.FromDecimal(0), //unknown with mednadisc
                sec      = BCD2.FromDecimal(0), //unknown with mednadisc
                frame    = BCD2.FromDecimal(0), //unknown with mednadisc
                zero     = 0,                   //unknown with mednadisc
                ap_min   = BCD2.FromDecimal(md.TOC.last_track),
                ap_sec   = BCD2.FromDecimal(0),
                ap_frame = BCD2.FromDecimal(0),
                q_crc    = 0,              //meaningless
            };

            disc.RawTOCEntries.Add(new RawTOCEntry {
                QData = qA1
            });
        }
コード例 #19
0
        /// <exception cref="CCDParseException">file <paramref name="ccdPath"/> not found, nonexistent IMG file, nonexistent SUB file, IMG or SUB file not multiple of <c>2352 B</c>, or IMG and SUB files differ in length</exception>
        public Disc LoadCCDToDisc(string ccdPath, DiscMountPolicy IN_DiscMountPolicy)
        {
            var loadResults = LoadCCDPath(ccdPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            IBlob imgBlob = null, subBlob = null;
            long  imgLen = -1, subLen;

            //mount the IMG file
            //first check for a .ecm in place of the img
            var imgPath = loadResults.ImgPath;

            if (!File.Exists(imgPath))
            {
                var ecmPath = Path.ChangeExtension(imgPath, ".img.ecm");
                if (File.Exists(ecmPath))
                {
                    if (Disc.Blob_ECM.IsECM(ecmPath))
                    {
                        var ecm = new Disc.Blob_ECM();
                        ecm.Load(ecmPath);
                        imgBlob = ecm;
                        imgLen  = ecm.Length;
                    }
                }
            }
            if (imgBlob == null)
            {
                if (!File.Exists(loadResults.ImgPath))
                {
                    throw new CCDParseException("Malformed CCD format: nonexistent IMG file!");
                }
                var imgFile = new Disc.Blob_RawFile()
                {
                    PhysicalPath = loadResults.ImgPath
                };
                imgLen  = imgFile.Length;
                imgBlob = imgFile;
            }
            disc.DisposableResources.Add(imgBlob);

            //mount the SUB file
            if (!File.Exists(loadResults.SubPath))
            {
                throw new CCDParseException("Malformed CCD format: nonexistent SUB file!");
            }
            var subFile = new Disc.Blob_RawFile()
            {
                PhysicalPath = loadResults.SubPath
            };

            subBlob = subFile;
            disc.DisposableResources.Add(subBlob);
            subLen = subFile.Length;

            //quick integrity check of file sizes
            if (imgLen % 2352 != 0)
            {
                throw new CCDParseException("Malformed CCD format: IMG file length not multiple of 2352");
            }
            int NumImgSectors = (int)(imgLen / 2352);

            if (subLen != NumImgSectors * 96)
            {
                throw new CCDParseException("Malformed CCD format: SUB file length not matching IMG");
            }

            var ccdf = loadResults.ParsedCCDFile;

            //the only instance of a sector synthesizer we'll need
            SS_CCD synth = new SS_CCD();

            //generate DiscTOCRaw items from the ones specified in the CCD file
            //TODO - range validate these (too many truncations to byte)
            disc.RawTOCEntries = new List <RawTOCEntry>();
            foreach (var entry in ccdf.TOCEntries)
            {
                BCD2 tno, ino;

                //this should actually be zero. im not sure if this is stored as BCD2 or not
                tno = BCD2.FromDecimal(entry.TrackNo);

                //these are special values.. I think, taken from this:
                //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
                //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
                //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
                ino = BCD2.FromDecimal(entry.Point);
                if (entry.Point == 0xA0)
                {
                    ino.BCDValue = 0xA0;
                }
                else if (entry.Point == 0xA1)
                {
                    ino.BCDValue = 0xA1;
                }
                else if (entry.Point == 0xA2)
                {
                    ino.BCDValue = 0xA2;
                }

                var q = new SubchannelQ
                {
                    q_status = SubchannelQ.ComputeStatus(entry.ADR, (EControlQ)(entry.Control & 0xF)),
                    q_tno    = tno,
                    q_index  = ino,
                    min      = BCD2.FromDecimal(entry.AMin),
                    sec      = BCD2.FromDecimal(entry.ASec),
                    frame    = BCD2.FromDecimal(entry.AFrame),
                    zero     = (byte)entry.Zero,
                    ap_min   = BCD2.FromDecimal(entry.PMin),
                    ap_sec   = BCD2.FromDecimal(entry.PSec),
                    ap_frame = BCD2.FromDecimal(entry.PFrame),
                    q_crc    = 0,                  //meaningless
                };

                disc.RawTOCEntries.Add(new RawTOCEntry {
                    QData = q
                });
            }

            //analyze the RAWTocEntries to figure out what type of track track 1 is
            var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job()
            {
                Entries = disc.RawTOCEntries
            };

            tocSynth.Run();

            //Add sectors for the mandatory track 1 pregap, which isn't stored in the CCD file
            //We reuse some CUE code for this.
            //If we load other formats later we might should abstract this even further (to a synthesizer job)
            //It can't really be abstracted from cue files though due to the necessity of merging this with other track 1 pregaps
            CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio;
            if (tocSynth.Result.TOCItems[1].IsData)
            {
                if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA)
                {
                    pregapTrackType = CUE.CueTrackType.Mode2_2352;
                }
                else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI)
                {
                    pregapTrackType = CUE.CueTrackType.CDI_2352;
                }
                else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA)
                {
                    pregapTrackType = CUE.CueTrackType.Mode1_2352;
                }
            }
            for (int i = 0; i < 150; i++)
            {
                var ss_gap = new CUE.SS_Gap()
                {
                    Policy    = IN_DiscMountPolicy,
                    TrackType = pregapTrackType
                };
                disc._Sectors.Add(ss_gap);

                int qRelMSF = i - 150;

                //tweak relMSF due to ambiguity/contradiction in yellowbook docs
                if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA)
                {
                    qRelMSF++;
                }

                //setup subQ
                byte ADR = 1;                 //absent some kind of policy for how to set it, this is a safe assumption:
                ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control);
                ss_gap.sq.q_tno        = BCD2.FromDecimal(1);
                ss_gap.sq.q_index      = BCD2.FromDecimal(0);
                ss_gap.sq.AP_Timestamp = i;
                ss_gap.sq.Timestamp    = qRelMSF;

                //setup subP
                ss_gap.Pause = true;
            }

            //build the sectors:
            //set up as many sectors as we have img/sub for, even if the TOC doesnt reference them
            //(the TOC is unreliable, and the Track records are redundant)
            for (int i = 0; i < NumImgSectors; i++)
            {
                disc._Sectors.Add(synth);
            }

            return(disc);
        }
コード例 #20
0
ファイル: MednadiscTester.cs プロジェクト: cas1993per/bizhawk
        public void ReadLBA_SubchannelQ(int offset, ref SubchannelQ sq)
        {
            sq.q_status = buffer[offset + 0];
            sq.q_tno = buffer[offset + 1];
            sq.q_index = buffer[offset + 2];
            sq.min.BCDValue = buffer[offset + 3];
            sq.sec.BCDValue = buffer[offset + 4];
            sq.frame.BCDValue = buffer[offset + 5];
            //nothing in byte[6]
            sq.ap_min.BCDValue = buffer[offset + 7];
            sq.ap_sec.BCDValue = buffer[offset + 8];
            sq.ap_frame.BCDValue = buffer[offset + 9];

            //CRC is stored inverted and big endian.. so... do the opposite
            byte hibyte = (byte)(~buffer[offset + 10]);
            byte lobyte = (byte)(~buffer[offset + 11]);
            sq.q_crc = (ushort)((hibyte << 8) | lobyte);
        }
コード例 #21
0
        /// <exception cref="MDSParseException">no file found at <paramref name="mdsPath"/> or BLOB error</exception>
        public Disc LoadMDSToDisc(string mdsPath, DiscMountPolicy IN_DiscMountPolicy)
        {
            var loadResults = LoadMDSPath(mdsPath);

            if (!loadResults.Valid)
            {
                throw loadResults.FailureException;
            }

            Disc disc = new Disc();

            // load all blobs
            Dictionary <int, IBlob> BlobIndex = MountBlobs(loadResults.ParsedMDSFile, disc);

            var mdsf = loadResults.ParsedMDSFile;

            //generate DiscTOCRaw items from the ones specified in the MDS file
            disc.RawTOCEntries = new List <RawTOCEntry>();
            foreach (var entry in mdsf.TOCEntries)
            {
                disc.RawTOCEntries.Add(EmitRawTOCEntry(entry));
            }

            //analyze the RAWTocEntries to figure out what type of track track 1 is
            var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job(disc.RawTOCEntries);

            tocSynth.Run();

            // now build the sectors
            int currBlobIndex = 0;

            foreach (var session in mdsf.ParsedSession)
            {
                for (int i = session.StartTrack; i <= session.EndTrack; i++)
                {
                    int relMSF = -1;

                    var track = mdsf.TOCEntries.FirstOrDefault(t => t.Point == i);
                    if (track == null)
                    {
                        break;
                    }

                    // ignore the info entries
                    if (track.Point == 0xA0 ||
                        track.Point == 0xA1 ||
                        track.Point == 0xA2)
                    {
                        continue;
                    }

                    // get the blob(s) for this track
                    // it's probably a safe assumption that there will be only one blob per track, but I'm still not 100% sure on this
                    var tr = mdsf.TOCEntries.FirstOrDefault(a => a.Point == i) ?? throw new MDSParseException("BLOB Error!");

#if true
                    if (tr.ImageFileNamePaths.Count == 0)
                    {
                        throw new MDSParseException("BLOB Error!");
                    }
#else // this is the worst use of lists and LINQ I've seen in this god-forsaken codebase, I hope for all our sakes that it's not a workaround for some race condition --yoshi
                    List <string> blobstrings = new List <string>();
                    foreach (var t in tr.ImageFileNamePaths)
                    {
                        if (!blobstrings.Contains(t))
                        {
                            blobstrings.Add(t);
                        }
                    }

                    var tBlobs = (from a in tr.ImageFileNamePaths
                                  select a).ToList();

                    if (tBlobs.Count < 1)
                    {
                        throw new MDSParseException("BLOB Error!");
                    }

                    // is the currBlob valid for this track, or do we need to increment?
                    string bString = tBlobs.First();
#endif

                    IBlob mdfBlob = null;

                    // check for track pregap and create if necessary
                    // this is specified in the track extras block
                    if (track.ExtraBlock.Pregap > 0)
                    {
                        CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio;
                        if (tocSynth.Result.TOCItems[1].IsData)
                        {
                            if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA)
                            {
                                pregapTrackType = CUE.CueTrackType.Mode2_2352;
                            }
                            else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI)
                            {
                                pregapTrackType = CUE.CueTrackType.CDI_2352;
                            }
                            else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA)
                            {
                                pregapTrackType = CUE.CueTrackType.Mode1_2352;
                            }
                        }
                        for (int pre = 0; pre < track.ExtraBlock.Pregap; pre++)
                        {
                            relMSF++;

                            var ss_gap = new CUE.SS_Gap()
                            {
                                Policy    = IN_DiscMountPolicy,
                                TrackType = pregapTrackType
                            };
                            disc._Sectors.Add(ss_gap);

                            int qRelMSF = pre - Convert.ToInt32(track.ExtraBlock.Pregap);

                            //tweak relMSF due to ambiguity/contradiction in yellowbook docs
                            if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA)
                            {
                                qRelMSF++;
                            }

                            //setup subQ
                            byte ADR = 1;                             //absent some kind of policy for how to set it, this is a safe assumption:
                            ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control);
                            ss_gap.sq.q_tno        = BCD2.FromDecimal(1);
                            ss_gap.sq.q_index      = BCD2.FromDecimal(0);
                            ss_gap.sq.AP_Timestamp = pre;
                            ss_gap.sq.Timestamp    = qRelMSF;

                            //setup subP
                            ss_gap.Pause = true;
                        }
                        // pregap processing completed
                    }



                    // create track sectors
                    long currBlobOffset = track.TrackOffset;
                    for (long sector = session.StartSector; sector <= session.EndSector; sector++)
                    {
                        CUE.SS_Base sBase = null;

                        // get the current blob from the BlobIndex
                        Blob_RawFile currBlob         = (Blob_RawFile)BlobIndex[currBlobIndex];
                        long         currBlobLength   = currBlob.Length;
                        long         currBlobPosition = sector;
                        if (currBlobPosition == currBlobLength)
                        {
                            currBlobIndex++;
                        }
                        mdfBlob = disc.DisposableResources[currBlobIndex] as Blob_RawFile;

                        //int userSector = 2048;
                        switch (track.SectorSize)
                        {
                        case 2448:
                            sBase = new CUE.SS_2352()
                            {
                                Policy = IN_DiscMountPolicy
                            };
                            //userSector = 2352;
                            break;

                        case 2048:
                        default:
                            sBase = new CUE.SS_Mode1_2048()
                            {
                                Policy = IN_DiscMountPolicy
                            };
                            //userSector = 2048;
                            break;

                            //throw new Exception($"Not supported: Sector Size {track.SectorSize}");
                        }

                        // configure blob
                        sBase.Blob       = mdfBlob;
                        sBase.BlobOffset = currBlobOffset;

                        currBlobOffset += track.SectorSize;                         // userSector;

                        // add subchannel data
                        relMSF++;
                        BCD2 tno, ino;

                        //this should actually be zero. im not sure if this is stored as BCD2 or not
                        tno = BCD2.FromDecimal(track.TrackNo);

                        //these are special values.. I think, taken from this:
                        //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html
                        //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD.
                        //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing.
                        ino = BCD2.FromDecimal(track.Point);
                        if (track.Point == 0xA0)
                        {
                            ino.BCDValue = 0xA0;
                        }
                        else if (track.Point == 0xA1)
                        {
                            ino.BCDValue = 0xA1;
                        }
                        else if (track.Point == 0xA2)
                        {
                            ino.BCDValue = 0xA2;
                        }

                        // get ADR & Control from ADR_Control byte
                        byte adrc    = Convert.ToByte(track.ADR_Control);
                        var  Control = adrc & 0x0F;
                        var  ADR     = adrc >> 4;

                        var q = new SubchannelQ
                        {
                            q_status     = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)),
                            q_tno        = BCD2.FromDecimal(track.Point),
                            q_index      = ino,
                            AP_Timestamp = disc._Sectors.Count,
                            Timestamp    = relMSF - Convert.ToInt32(track.ExtraBlock.Pregap)
                        };

                        sBase.sq = q;

                        disc._Sectors.Add(sBase);
                    }
                }
            }

            return(disc);
        }
コード例 #22
0
ファイル: MednadiscTester.cs プロジェクト: cas1993per/bizhawk
    static bool NewTest(string path)
    {
        bool ret = false;

        Disc disc;
        if (Path.GetExtension(path).ToLower() == ".cue") disc = Disc.FromCuePath(path, new CueBinPrefs());
        else disc = Disc.FromCCDPath(path);
        IntPtr mednadisc = mednadisc_LoadCD(path);

        //TODO - test leadout a bit, or determine length some superior way
        //TODO - check length against mednadisc

        int nSectors = (int)(disc.Structure.BinarySize / 2352) - 150;
        var subbuf = new byte[96];
        var discbuf = new byte[2352 + 96];
        var monkeybuf = new byte[2352 + 96];
        var disc_qbuf = new byte[96];
        var monkey_qbuf = new byte[96];

        for (int i = 0; i < nSectors; i++)
        {
            mednadisc_ReadSector(mednadisc, i, monkeybuf);
            disc.ReadLBA_2352(i, discbuf, 0);
            disc.ReadLBA_SectorEntry(i).SubcodeSector.ReadSubcodeDeinterleaved(subbuf, 0);
            SubcodeUtils.Interleave(subbuf, 0, discbuf, 2352);
            //remove P
            for (int q = 2352; q < 2352 + 96; q++)
            {
                discbuf[q] &= 0x7F;
                monkeybuf[q] &= 0x7F;
            }
            for (int q = 0; q < 2352 + 96; q++)
            {
                if (discbuf[q] != monkeybuf[q])
                {
                    Console.WriteLine("MISMATCH: " + Path.GetFileName(path));

                    //decode Q subchannels for manual investigation
                    SubcodeUtils.Deinterleave(discbuf, 2352, disc_qbuf, 0);
                    var asr = new QuickSubcodeReader(disc_qbuf);
                    SubchannelQ disc_q = new SubchannelQ();
                    asr.ReadLBA_SubchannelQ(12, ref disc_q);

                    SubcodeUtils.Deinterleave(monkeybuf, 2352, monkey_qbuf, 0);
                    asr = new QuickSubcodeReader(monkey_qbuf);
                    SubchannelQ monkey_q = new SubchannelQ();
                    asr.ReadLBA_SubchannelQ(12, ref monkey_q);

                    goto END;
                }
            }
        }

        ret = true;

        END:
        disc.Dispose();
        mednadisc_CloseCD(mednadisc);

        return ret;
    }
コード例 #23
0
ファイル: Disc.API.cs プロジェクト: cas1993per/bizhawk
        public void ReadLBA_SubchannelQ(int lba, ref SubchannelQ sq)
        {
            var se = disc.ReadLBA_SectorEntry(lba);
            se.SubcodeSector.ReadSubcodeChannel(1, buffer, 0);
            int offset = 0;

            sq.q_status = buffer[offset + 0];
            sq.q_tno = buffer[offset + 1];
            sq.q_index = buffer[offset + 2];
            sq.min.BCDValue = buffer[offset + 3];
            sq.sec.BCDValue = buffer[offset + 4];
            sq.frame.BCDValue = buffer[offset + 5];
            //nothing in byte[6]
            sq.ap_min.BCDValue = buffer[offset + 7];
            sq.ap_sec.BCDValue = buffer[offset + 8];
            sq.ap_frame.BCDValue = buffer[offset + 9];

            //CRC is stored inverted and big endian.. so... do the opposite
            byte hibyte = (byte)(~buffer[offset + 10]);
            byte lobyte = (byte)(~buffer[offset + 11]);
            sq.q_crc = (ushort)((hibyte << 8) | lobyte);
        }
コード例 #24
0
		void RunMednaDisc()
		{
			var disc = new Disc();
			OUT_Disc = disc;

			//create a MednaDisc and give it to the disc for ownership
			var md = new MednaDisc(IN_FromPath);
			disc.DisposableResources.Add(md);

			//"length of disc" for bizhawk's purposes (NOT a robust concept!) is determined by beginning of leadout track
			var m_leadoutTrack = md.TOCTracks[100];
			int nSectors = (int)m_leadoutTrack.lba;

			//make synth param memos
			disc.SynthParams.MednaDisc = md;

			//this is the sole sector synthesizer we'll need
			var synth = new SS_MednaDisc();
			OUT_Disc.SynthProvider = new SimpleSectorSynthProvider() { SS = synth };

			//ADR (q-Mode) is necessarily 0x01 for a RawTOCEntry
			const int kADR = 1;
			const int kUnknownControl = 0;

			//mednafen delivers us what is essentially but not exactly (or completely) a TOCRaw.
			//we need to synth RawTOCEntries from this and then turn it into a proper TOCRaw
			//when coming from mednafen, there are 101 entries.
			//entry[0] is placeholder junk, not to be used
			//entry[100] is the leadout track (A0)
			//A1 and A2 are in the form of FirstRecordedTrackNumber and LastRecordedTrackNumber
			for (int i = 1; i < 101; i++)
			{
				var m_te = md.TOCTracks[i];

				//dont add invalid (absent) items
				if (!m_te.Valid)
					continue;

				var m_ts = new Timestamp((int)m_te.lba + 150); //these are supposed to be absolute timestamps

				var q = new SubchannelQ
				{
					q_status = SubchannelQ.ComputeStatus(kADR, (EControlQ)m_te.control), 
					q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
					q_index = BCD2.FromDecimal(i),
					min = BCD2.FromDecimal(0), //unknown with mednadisc
					sec = BCD2.FromDecimal(0), //unknown with mednadisc
					frame = BCD2.FromDecimal(0), //unknown with mednadisc
					zero = 0, //unknown with mednadisc
					ap_min = BCD2.FromDecimal(m_ts.MIN),
					ap_sec = BCD2.FromDecimal(m_ts.SEC),
					ap_frame = BCD2.FromDecimal(m_ts.FRAC),
					q_crc = 0 //meaningless
				};

				//a special fixup: mednafen's entry 100 is the lead-out track, so change it into the A2 raw toc entry
				if (i == 100)
				{
					q.q_index.BCDValue = 0xA2;
				}

				disc.RawTOCEntries.Add(new RawTOCEntry { QData = q });
			}

			//synth A0 and A1 entries (indicating first and last recorded tracks and also session type)
			var qA0 = new SubchannelQ
			{
				q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
				q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
				q_index = BCD2.FromBCD(0xA0),
				min = BCD2.FromDecimal(0), //unknown with mednadisc
				sec = BCD2.FromDecimal(0), //unknown with mednadisc
				frame = BCD2.FromDecimal(0), //unknown with mednadisc
				zero = 0, //unknown with mednadisc
				ap_min = BCD2.FromDecimal(md.TOC.first_track),
				ap_sec = BCD2.FromDecimal(md.TOC.disc_type),
				ap_frame = BCD2.FromDecimal(0),
				q_crc = 0, //meaningless
			};
			disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA0 });
			var qA1 = new SubchannelQ
			{
				q_status = SubchannelQ.ComputeStatus(kADR, kUnknownControl),
				q_tno = BCD2.FromDecimal(0), //unknown with mednadisc
				q_index = BCD2.FromBCD(0xA1),
				min = BCD2.FromDecimal(0), //unknown with mednadisc
				sec = BCD2.FromDecimal(0), //unknown with mednadisc
				frame = BCD2.FromDecimal(0), //unknown with mednadisc
				zero = 0, //unknown with mednadisc
				ap_min = BCD2.FromDecimal(md.TOC.last_track),
				ap_sec = BCD2.FromDecimal(0),
				ap_frame = BCD2.FromDecimal(0),
				q_crc = 0, //meaningless
			};
			disc.RawTOCEntries.Add(new RawTOCEntry { QData = qA1 });

		}