1 #ifndef __MDFN_CDROM_CDUTILITY_H 2 #define __MDFN_CDROM_CDUTILITY_H 3 4 #include <stdint.h> 5 #include <string.h> 6 7 // Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions. 8 // It will also be called automatically if needed for the first time a function in this namespace that requires 9 // the initialization function to be called is called, for potential 10 // usage in constructors of statically-declared objects. 11 void CDUtility_Init(void); 12 13 // Quick definitions here: 14 // 15 // ABA - Absolute block address, synonymous to absolute MSF 16 // aba = (m_a * 60 * 75) + (s_a * 75) + f_a 17 // 18 // LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors) 19 // lba = aba - 150 20 21 22 enum 23 { 24 ADR_NOQINFO = 0x00, 25 ADR_CURPOS = 0x01, 26 ADR_MCN = 0x02, 27 ADR_ISRC = 0x03 28 }; 29 30 31 struct TOC_Track 32 { 33 uint8_t adr; 34 uint8_t control; 35 uint32_t lba; 36 bool valid; // valid/present; oh CD-i... 37 }; 38 39 // SubQ control field flags. 40 enum 41 { 42 SUBQ_CTRLF_PRE = 0x01, /* With 50/15us pre-emphasis. */ 43 SUBQ_CTRLF_DCP = 0x02, /* Digital copy permitted. */ 44 SUBQ_CTRLF_DATA = 0x04, /* Data track. */ 45 SUBQ_CTRLF_4CH = 0x08 /* 4-channel CD-DA. */ 46 }; 47 48 enum 49 { 50 DISC_TYPE_CDDA_OR_M1 = 0x00, 51 DISC_TYPE_CD_I = 0x10, 52 DISC_TYPE_CD_XA = 0x20 53 }; 54 55 struct TOC 56 { TOCTOC57 INLINE TOC() 58 { 59 Clear(); 60 } 61 ClearTOC62 INLINE void Clear(void) 63 { 64 first_track = last_track = 0; 65 disc_type = 0; 66 67 memset(tracks, 0, sizeof(tracks)); // FIXME if we change TOC_Track to non-POD type. 68 } 69 FindTrackByLBATOC70 INLINE int FindTrackByLBA(uint32_t LBA) const 71 { 72 int32_t track; 73 int32_t lvt = 0; 74 75 for(track = 1; track <= 100; track++) 76 { 77 if(!tracks[track].valid) 78 continue; 79 80 if(LBA < tracks[track].lba) 81 break; 82 83 lvt = track; 84 } 85 86 return(lvt); 87 } 88 89 uint8_t first_track; 90 uint8_t last_track; 91 uint8_t disc_type; 92 TOC_Track tracks[100 + 1]; // [0] is unused, [100] is for the leadout track. 93 }; 94 95 // 96 // Address conversion functions. 97 // AMSF_to_ABA(int32_t m_a,int32_t s_a,int32_t f_a)98 static INLINE uint32_t AMSF_to_ABA(int32_t m_a, int32_t s_a, int32_t f_a) 99 { 100 return(f_a + 75 * s_a + 75 * 60 * m_a); 101 } 102 ABA_to_AMSF(uint32_t aba,uint8_t * m_a,uint8_t * s_a,uint8_t * f_a)103 static INLINE void ABA_to_AMSF(uint32_t aba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a) 104 { 105 *m_a = aba / 75 / 60; 106 *s_a = (aba - *m_a * 75 * 60) / 75; 107 *f_a = aba - (*m_a * 75 * 60) - (*s_a * 75); 108 } 109 ABA_to_LBA(uint32_t aba)110 static INLINE int32_t ABA_to_LBA(uint32_t aba) 111 { 112 return(aba - 150); 113 } 114 LBA_to_ABA(int32_t lba)115 static INLINE uint32_t LBA_to_ABA(int32_t lba) 116 { 117 return(lba + 150); 118 } 119 AMSF_to_LBA(uint8_t m_a,uint8_t s_a,uint8_t f_a)120 static INLINE int32_t AMSF_to_LBA(uint8_t m_a, uint8_t s_a, uint8_t f_a) 121 { 122 return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a))); 123 } 124 LBA_to_AMSF(int32_t lba,uint8_t * m_a,uint8_t * s_a,uint8_t * f_a)125 static INLINE void LBA_to_AMSF(int32_t lba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a) 126 { 127 ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a); 128 } 129 130 /* BCD conversion functions */ BCD_is_valid(uint8_t bcd_number)131 static INLINE bool BCD_is_valid(uint8_t bcd_number) 132 { 133 if((bcd_number & 0xF0) >= 0xA0) 134 return(false); 135 136 if((bcd_number & 0x0F) >= 0x0A) 137 return(false); 138 139 return(true); 140 } 141 BCD_to_U8(uint8_t bcd_number)142 static INLINE uint8_t BCD_to_U8(uint8_t bcd_number) 143 { 144 return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) ); 145 } 146 U8_to_BCD(uint8_t num)147 static INLINE uint8_t U8_to_BCD(uint8_t num) 148 { 149 return( ((num / 10) << 4) + (num % 10) ); 150 } 151 152 // should always perform the conversion, even if the bcd number is invalid. BCD_to_U8_check(uint8_t bcd_number,uint8_t * out_number)153 static INLINE bool BCD_to_U8_check(uint8_t bcd_number, uint8_t *out_number) 154 { 155 *out_number = BCD_to_U8(bcd_number); 156 157 if(!BCD_is_valid(bcd_number)) 158 return(false); 159 160 return(true); 161 } 162 163 // 164 // Sector data encoding functions(to full 2352 bytes raw sector). 165 // 166 // sector_data must be able to contain at least 2352 bytes. 167 void encode_mode0_sector(uint32_t aba, uint8_t *sector_data); 168 void encode_mode1_sector(uint32_t aba, uint8_t *sector_data); // 2048 bytes of user data at offset 16 169 void encode_mode2_sector(uint32_t aba, uint8_t *sector_data); // 2336 bytes of user data at offset 16 170 void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data); // 2048+8 bytes of user data at offset 16 171 void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data); // 2324+8 bytes of user data at offset 16 172 173 174 // User data area pre-pause(MSF 00:00:00 through 00:01:74), lba -150 through -1 175 // out_buf must be able to contain 2352+96 bytes. 176 // "mode" is not used if the area is to be encoded as audio. 177 // pass 0xFF for "mode" for "don't know", and to make guess based on the TOC. 178 void synth_udapp_sector_lba(uint8_t mode, const TOC& toc, const int32_t lba, int32_t lba_subq_relative_offs, uint8_t* out_buf); 179 void subpw_synth_udapp_lba(const TOC& toc, const int32_t lba, const int32_t lba_subq_relative_offs, uint8_t* SubPWBuf); 180 181 // out_buf must be able to contain 2352+96 bytes. 182 // "mode" is not used if the area is to be encoded as audio. 183 // pass 0xFF for "mode" for "don't know", and to make guess based on the TOC. 184 void synth_leadout_sector_lba(uint8_t mode, const TOC& toc, const int32_t lba, uint8_t* out_buf); 185 void subpw_synth_leadout_lba(const TOC& toc, const int32_t lba, uint8_t* SubPWBuf); 186 187 188 // 189 // User data error detection and correction 190 // 191 192 // Check EDC of a mode 1 or mode 2 form 1 sector. 193 // Returns "true" if checksum is ok(matches). 194 // Returns "false" if checksum mismatch. 195 // sector_data should contain 2352 bytes of raw sector data. 196 bool edc_check(const uint8_t *sector_data, bool xa); 197 198 // Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist. 199 // Returns "true" if errors weren't detected, or they were corrected succesfully. 200 // Returns "false" if errors couldn't be corrected. 201 // sector_data should contain 2352 bytes of raw sector data. 202 // 203 // Note: mode 2 form 1 L-EC data can't correct errors in the 4-byte sector header(address + mode), 204 // but the error(s) will still be detected by EDC. 205 bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa); 206 207 // 208 // Subchannel(Q in particular) functions 209 // 210 211 // Returns false on checksum mismatch, true on match. 212 bool subq_check_checksum(const uint8_t *subq_buf); 213 214 // Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position 215 // in subq_buf. 216 void subq_generate_checksum(uint8_t *subq_buf); 217 218 // Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data. 219 void subq_deinterleave(const uint8_t *subpw_buf, uint8_t *subq_buf); 220 221 // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data. 222 void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf); 223 224 // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data. 225 void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf); 226 227 // Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output. 228 // Only valid for ADR_CURPOS. 229 // subq_input must pass subq_check_checksum(). 230 // TODO 231 //void subq_extrapolate(const uint8_t *subq_input, int32_t position_delta, uint8_t *subq_output); 232 233 // (De)Scrambles data sector. 234 void scrambleize_data_sector(uint8_t *sector_data); 235 236 #endif 237