#ifndef __MDFN_CDROM_CDUTILITY_H1#define __MDFN_CDROM_CDUTILITY_H23namespace CDUtility4{5// Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.6// It will also be called automatically if needed for the first time a function in this namespace that requires7// the initialization function to be called is called, for potential8// usage in constructors of statically-declared objects.9void CDUtility_Init(void);1011// Quick definitions here:12//13// ABA - Absolute block address, synonymous to absolute MSF14// aba = (m_a * 60 * 75) + (s_a * 75) + f_a15//16// LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)17// lba = aba - 150181920enum21{22ADR_NOQINFO = 0x00,23ADR_CURPOS = 0x01,24ADR_MCN = 0x02,25ADR_ISRC = 0x0326};272829struct TOC_Track30{31uint8 adr;32uint8 control;33uint32 lba;34bool valid; // valid/present; oh CD-i...35};3637// SubQ control field flags.38enum39{40SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.41SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.42SUBQ_CTRLF_DATA = 0x04, // Data track.43SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.44};4546enum47{48DISC_TYPE_CDDA_OR_M1 = 0x00,49DISC_TYPE_CD_I = 0x10,50DISC_TYPE_CD_XA = 0x2051};5253struct TOC54{55INLINE TOC()56{57Clear();58}5960INLINE void Clear(void)61{62first_track = last_track = 0;63disc_type = 0;6465memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type.66}6768INLINE int FindTrackByLBA(uint32 LBA) const69{70int32 lvt = 0;7172for(int32 track = 1; track <= 100; track++)73{74if(!tracks[track].valid)75continue;7677if(LBA < tracks[track].lba)78break;7980lvt = track;81}8283return(lvt);84}8586uint8 first_track;87uint8 last_track;88uint8 disc_type;89TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track.90};9192//93// Address conversion functions.94//95static INLINE uint32 AMSF_to_ABA(int32 m_a, int32 s_a, int32 f_a)96{97return(f_a + 75 * s_a + 75 * 60 * m_a);98}99100static INLINE void ABA_to_AMSF(uint32 aba, uint8 *m_a, uint8 *s_a, uint8 *f_a)101{102*m_a = aba / 75 / 60;103*s_a = (aba - *m_a * 75 * 60) / 75;104*f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);105}106107static INLINE int32 ABA_to_LBA(uint32 aba)108{109return(aba - 150);110}111112static INLINE uint32 LBA_to_ABA(int32 lba)113{114return(lba + 150);115}116117static INLINE int32 AMSF_to_LBA(uint8 m_a, uint8 s_a, uint8 f_a)118{119return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));120}121122static INLINE void LBA_to_AMSF(int32 lba, uint8 *m_a, uint8 *s_a, uint8 *f_a)123{124ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);125}126127//128// BCD conversion functions129//130static INLINE bool BCD_is_valid(uint8 bcd_number)131{132if((bcd_number & 0xF0) >= 0xA0)133return(false);134135if((bcd_number & 0x0F) >= 0x0A)136return(false);137138return(true);139}140141static INLINE uint8 BCD_to_U8(uint8 bcd_number)142{143return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );144}145146static INLINE uint8 U8_to_BCD(uint8 num)147{148return( ((num / 10) << 4) + (num % 10) );149}150151// should always perform the conversion, even if the bcd number is invalid.152static INLINE bool BCD_to_U8_check(uint8 bcd_number, uint8 *out_number)153{154*out_number = BCD_to_U8(bcd_number);155156if(!BCD_is_valid(bcd_number))157return(false);158159return(true);160}161162//163// Sector data encoding functions(to full 2352 bytes raw sector).164//165// sector_data must be able to contain at least 2352 bytes.166void encode_mode0_sector(uint32 aba, uint8 *sector_data);167void encode_mode1_sector(uint32 aba, uint8 *sector_data); // 2048 bytes of user data at offset 16168void encode_mode2_sector(uint32 aba, uint8 *sector_data); // 2336 bytes of user data at offset 16169void encode_mode2_form1_sector(uint32 aba, uint8 *sector_data); // 2048+8 bytes of user data at offset 16170void encode_mode2_form2_sector(uint32 aba, uint8 *sector_data); // 2324+8 bytes of user data at offset 16171172173// User data area pre-pause(MSF 00:00:00 through 00:01:74), lba -150 through -1174// out_buf must be able to contain 2352+96 bytes.175// "mode" is not used if the area is to be encoded as audio.176// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.177void synth_udapp_sector_lba(uint8 mode, const TOC& toc, const int32 lba, int32 lba_subq_relative_offs, uint8* out_buf);178void subpw_synth_udapp_lba(const TOC& toc, const int32 lba, const int32 lba_subq_relative_offs, uint8* SubPWBuf);179180// out_buf must be able to contain 2352+96 bytes.181// "mode" is not used if the area is to be encoded as audio.182// pass 0xFF for "mode" for "don't know", and to make guess based on the TOC.183void synth_leadout_sector_lba(uint8 mode, const TOC& toc, const int32 lba, uint8* out_buf);184void subpw_synth_leadout_lba(const TOC& toc, const int32 lba, uint8* SubPWBuf);185186187//188// User data error detection and correction189//190191// Check EDC of a mode 1 or mode 2 form 1 sector.192// Returns "true" if checksum is ok(matches).193// Returns "false" if checksum mismatch.194// sector_data should contain 2352 bytes of raw sector data.195bool edc_check(const uint8 *sector_data, bool xa);196197// Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.198// Returns "true" if errors weren't detected, or they were corrected succesfully.199// Returns "false" if errors couldn't be corrected.200// sector_data should contain 2352 bytes of raw sector data.201bool edc_lec_check_and_correct(uint8 *sector_data, bool xa);202203//204// Subchannel(Q in particular) functions205//206207// Returns false on checksum mismatch, true on match.208bool subq_check_checksum(const uint8 *subq_buf);209210// Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position211// in subq_buf.212void subq_generate_checksum(uint8 *subq_buf);213214// Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.215void subq_deinterleave(const uint8 *subpw_buf, uint8 *subq_buf);216217// Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.218void subpw_deinterleave(const uint8 *in_buf, uint8 *out_buf);219220// Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.221void subpw_interleave(const uint8 *in_buf, uint8 *out_buf);222223// Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.224// Only valid for ADR_CURPOS.225// subq_input must pass subq_check_checksum().226// TODO227//void subq_extrapolate(const uint8 *subq_input, int32 position_delta, uint8 *subq_output);228229// (De)Scrambles data sector.230void scrambleize_data_sector(uint8 *sector_data);231}232233#endif234235236