|
View:
New views
4 Messages
—
Rating Filter:
Alert me
|
|
|
C2 error support.Hi,
I'm looking into adding support for reading the C2 error information, and probably some other things like CD-TEXT, CD+MIDI, CD+G, ISRC, whatever info I can read from the disc. It looks like I need to extend the API for this. For instance, for the C2 error information you get 1 bit per read byte to indicate if there was an error reading that byte or not. I see several ways to do this: - Create new versions of exising functions with extra parameters (and different name) - Create functions that return the extra info from the last call. - Setting reading C2/subchannel info default to off, and return the data exactly like the drive returns it, so just after the main data. It looks like this atleast requires a new function to set the options. - Read the data by default, if supported by the drive, and instead of adding it after the main data of each sector, change it so that the main data of all sectors are still returned first, and then the other data. The R-W subchannels can contain interleaved/error corrected info like CD-TEXT, and not all drives support returning that data deinterleaved and error corrected, but most do support reading the RAW data. So we might need to implement that ourself. So I'm wondering what you think the best option is. I'm currently in favour of the second option. Kurt _______________________________________________ Paranoia-dev mailing list Paranoia-dev@... http://lists.xiph.org/mailman/listinfo/paranoia-dev |
|
|
Re: C2 error support.On Fri, May 22, 2009 at 02:57:24PM +0200, Kurt Roeckx wrote:
> Hi, > > I'm looking into adding support for reading the C2 error > information [...] Here is an initial patch. It would be nice if people could test this and give feedback. Some comments about the patch: - I've merged all the i_read_mmc() functions to 1 function so that not all of them need to be modified. - rs was set wrong in verify_read_command(). They all had the DAP bit inverted. - There are still a few TODOs in it. I've been testing this with a CD with lots of scratches. What I've seen: - My plextor reads this CD at full speed (40x) every time, always identical, never returns C2 errors. - The other drives have problems reading this, even at speed 1. Without this patch I got 20+ different files. With this patch they all either generate the same file as the plextor, or fail to read it / generate a skip. Once I got a total of 1.8 million C2 errors for 1 track, but the result was still good. - The current patch marks all samples belonging to 1 byte of c2 error information as having a problem while it should probably be possible to only mark the sample that is affected. For some reason that's currently unclear to me this always results in a good file and trying to mark only the bad one resulted in a bad file. (Maybe I should mark both left and right instead of only left or right?) Kurt Index: paranoia/paranoia.c =================================================================== --- paranoia/paranoia.c (revision 16022) +++ paranoia/paranoia.c (working copy) @@ -2329,7 +2329,9 @@ long sofar; long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; long anyflag=0; + unsigned char *c2_buffer=NULL; + c2_buffer=malloc(sectatonce * CD_C2BUFFERSIZE); /* Calculate the first sector to read. This calculation takes * into account the need to jitter the starting point of the read @@ -2444,6 +2446,7 @@ if(new)free_c_block(new); if(buffer)free(buffer); if(flags)free(flags); + if(c2_buffer)free(c2_buffer); return NULL; } thisread=0; @@ -2482,6 +2485,29 @@ flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE; } + if (cdda_read_c2_errors(p->d, c2_buffer, thisread) == 0) + { + int i; + for (i = 0; i < thisread * CD_C2BUFFERSIZE; i++) + { + int j; + /* The c2_buffer contains 1 bit for every byte from the + * buffer. The buffer is in 16 bit words. So 8 byte from + * the c2_buffer map to 4 values of the flags/buffer. + * It's not clear in which order the bits in the c2 buffer are, + * is the first byte in the MSB or LSB? Proably all firmware won't + * agree. We just mark all 4 values in the flags as invalid. + */ + if (c2_buffer[i] != '\0') + { + for (j = 0; j < 4; j++) + { + flags[sofar*CD_FRAMEWORDS+i*4+j]|=FLAGS_UNREAD; + } + } + } + } + if(adjread+secread-1==p->current_lastsector) new->lastsector=-1; @@ -2519,6 +2545,7 @@ free(flags); new=NULL; } + if(c2_buffer)free(c2_buffer); return(new); } Index: interface/cdda_interface.h =================================================================== --- interface/cdda_interface.h (revision 16022) +++ interface/cdda_interface.h (working copy) @@ -17,6 +17,7 @@ #define CD_FRAMESIZE_RAW 2352 #endif #define CD_FRAMESAMPLES (CD_FRAMESIZE_RAW / 4) +#define CD_C2BUFFERSIZE (CD_FRAMESIZE_RAW / 8) #include <sys/types.h> #include <signal.h> @@ -133,6 +134,7 @@ long beginsector, long sectors); extern long cdda_read_timed(cdrom_drive *d, void *buffer, long beginsector, long sectors, int *milliseconds); +extern int cdda_read_c2_errors(cdrom_drive *d, void *buffer, int sectors); extern long cdda_track_firstsector(cdrom_drive *d,int track); extern long cdda_track_lastsector(cdrom_drive *d,int track); Index: interface/scsi_interface.c =================================================================== --- interface/scsi_interface.c (revision 16022) +++ interface/scsi_interface.c (working copy) @@ -58,7 +58,7 @@ sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t" "table entry size: %d bytes\n\t" "maximum theoretical transfer: %d sectors\n", - table, reserved, table*(reserved/CD_FRAMESIZE_RAW)); + table, reserved, table*(reserved/d->private_data->data_size)); cdmessage(d,buffer); cur=reserved; /* only use one entry for now */ @@ -82,11 +82,11 @@ "\t\tforcing maximum possible sector size. This can break\n" "\t\tspectacularly; use with caution!\n"); } - d->nsectors=cur/CD_FRAMESIZE_RAW; + d->nsectors=cur/d->private_data->data_size; d->bigbuff=cur; sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n", - d->nsectors,d->nsectors*CD_FRAMESIZE_RAW); + d->nsectors,d->nsectors*d->private_data->data_size); if(cur==0) exit(1); @@ -912,90 +912,120 @@ return(0); } +/* READ CD command (0xBE) + * byte 1: bit 0: + * - mmc1-mmc4: RELADR: must be 0 + * - mmc5- : obsolete + * byte 1: bit 1: + * - mmc1-mmc3: Reserved + * - mmc4- : Digital Audio Play: When set to 1 the drive will do things + * like mute and interpolate on errors + * byte 1: bit 4-2: sector type + * - 000: All types (mandotary) + * - 001: CD-DA (mmc1-mmc3: optional, mmc4-: mandotary) + * - 002: Mode 1 (mandotary) + * - 003: Mode 2 formless (mmc1-mmc3: madotary, mmc4-: optional) + * - 004: Mode 2 form 1 (mandotary) + * - 005: Mode 2 form 2 (mandotary) + * byte 2-5: Start LBA + * byte 6-8: Length + * byte 9: bit 0: reserved + * byte 9: bit 2-1: C2 error info: + * - 00: No C2 info + * - 01: 1 bit for all 2352 bytes + * - 10: Bitwise or of C2 bytes + pad + 1 bit for all 2352 bytes. + * byte 9: bit 3: EDC & ECC + * byte 9: bit 4: User Data + * byte 9: bit 6-5: Header Codes + * - 00: No header info + * - 01: 4 byte sector header + * - 10: 8 byte sector sub-header (mode 2) + * - 11: both header and sub-header + * byte 9: bit 7: Sync + * byte 10: bit 2-0: sub channel selection: + * - 000: No sub channel + * - 001: RAW P-W channel (only mentioned in mmc1 - mmc4, but others still + * talk about it.) + * - 010: Q channel data + * - 100: Corrected and deinterleaved R-W subchannel + * + * Note: Setting any of the bits 7 - 3 from byte 9 for should act the same + * and only return the user data (0x10) for CDDA. + * + */ + static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ int ret; - unsigned char cmd[12]={0xbe, 0x2, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0}; + unsigned char cmd[12]={0xbe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - cmd[3] = (begin >> 16) & 0xFF; - cmd[4] = (begin >> 8) & 0xFF; - cmd[5] = begin & 0xFF; - cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) - return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); - return(0); -} + if(d->private_data->mmc_use_dap) + { + cmd[1] |= 0x02; + } -static int i_read_mmcB (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ - int ret; - unsigned char cmd[12]={0xbe, 0x0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0}; + if(d->private_data->mmc_use_sectortype_cdda) + { + cmd[1] |= 0x04; /* 001 in bit 4-2 */ + } - cmd[3] = (begin >> 16) & 0xFF; - cmd[4] = (begin >> 8) & 0xFF; - cmd[5] = begin & 0xFF; - cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) - return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); - return(0); -} + if(d->private_data->mmc_use_channel_selection_all) /* bit 7-3 */ + { + cmd[9] |= 0xF8; /* get sync, all headers, user data, EDC/ECC */ + } + else + { + cmd[9] |= 0x10; /* get user data */ + } -static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ - int ret; - unsigned char cmd[12]={0xbe, 0x2, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0}; + if (d->private_data->mmc_use_c2) + { + /* Git 1 bit error indication per byte after c2 error correction. */ + cmd[9] |= 0x02; + } cmd[3] = (begin >> 16) & 0xFF; cmd[4] = (begin >> 8) & 0xFF; cmd[5] = begin & 0xFF; cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) + if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * d->private_data->data_size,'\177',1,sense))) return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); + if(p) + { + int i; + for (i = 0; i < sectors; i++) + { + if (d->private_data->mmc_use_c2 && d->private_data->c2_buffer != NULL) + { + memcpy(d->private_data->c2_buffer+i*CD_C2BUFFERSIZE, + d->private_data->sg_buffer + i * (d->private_data->data_size) + + CD_FRAMESIZE_RAW, + CD_C2BUFFERSIZE); + } + memcpy(p+i*CD_FRAMESIZE_RAW, + d->private_data->sg_buffer + i * (d->private_data->data_size), + CD_FRAMESIZE_RAW); + } + } return(0); } -static int i_read_mmc2B (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ - int ret; - unsigned char cmd[12]={0xbe, 0x0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0}; - - cmd[3] = (begin >> 16) & 0xFF; - cmd[4] = (begin >> 8) & 0xFF; - cmd[5] = begin & 0xFF; - cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) - return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); - return(0); +/* TODO: Remove the sectors parameter? */ +extern int cdda_read_c2_errors(cdrom_drive *d, void *buffer, int sectors) +{ + if (!d->is_mmc) + { + /* TODO: Use different error number? */ + return -405; + } + if (!d->private_data->mmc_use_c2 || d->private_data->c2_buffer == NULL) + { + /* TODO: Is this a good error? Document it. */ + return -11; + } + memcpy(buffer, d->private_data->c2_buffer, CD_C2BUFFERSIZE*sectors); + return 0; } -static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ - int ret; - unsigned char cmd[12]={0xbe, 0x6, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0}; - - cmd[3] = (begin >> 16) & 0xFF; - cmd[4] = (begin >> 8) & 0xFF; - cmd[5] = begin & 0xFF; - cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) - return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); - return(0); -} - -static int i_read_mmc3B (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){ - int ret; - unsigned char cmd[12]={0xbe, 0x4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0}; - - cmd[3] = (begin >> 16) & 0xFF; - cmd[4] = (begin >> 8) & 0xFF; - cmd[5] = begin & 0xFF; - cmd[8] = sectors; - if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense))) - return(ret); - if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW); - return(0); -} - /* straight from the MMC3 spec */ static inline void LBA_to_MSF(long lba, unsigned char *M, @@ -1227,31 +1257,17 @@ return(scsi_read_map(d,p,begin,sectors,i_read_mmc)); } +/* This function gets called in the exception list. We probably just want to + * turn on DAP. */ long scsi_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors){ - return(scsi_read_map(d,p,begin,sectors,i_read_mmc2)); + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 1; + d->private_data->mmc_use_channel_selection_all = 1; + d->private_data->mmc_use_c2 = 0; + return(scsi_read_map(d,p,begin,sectors,i_read_mmc)); } -long scsi_read_mmc3 (cdrom_drive *d, void *p, long begin, - long sectors){ - return(scsi_read_map(d,p,begin,sectors,i_read_mmc3)); -} - -long scsi_read_mmcB (cdrom_drive *d, void *p, long begin, - long sectors){ - return(scsi_read_map(d,p,begin,sectors,i_read_mmcB)); -} - -long scsi_read_mmc2B (cdrom_drive *d, void *p, long begin, - long sectors){ - return(scsi_read_map(d,p,begin,sectors,i_read_mmc2B)); -} - -long scsi_read_mmc3B (cdrom_drive *d, void *p, long begin, - long sectors){ - return(scsi_read_map(d,p,begin,sectors,i_read_mmc3B)); -} - long scsi_read_msf (cdrom_drive *d, void *p, long begin, long sectors){ return(scsi_read_map(d,p,begin,sectors,i_read_msf)); @@ -1305,7 +1321,7 @@ long sectors); unsigned char density; - int16_t *buff=malloc(CD_FRAMESIZE_RAW); + int16_t *buff=malloc(d->private_data->data_size); cdmessage(d,"Verifying CDDA command set...\n"); @@ -1401,33 +1417,51 @@ /* 2 through 10 do not allow/require density */ case 2: - d->read_audio=scsi_read_mmcB; - rs="be 02,10"; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 0; + d->private_data->mmc_use_channel_selection_all = 0; + d->read_audio=scsi_read_mmc; + rs="be 00,10"; if(i==0)break; case 3: j=3; - d->read_audio=scsi_read_mmc2B; - rs="be 02,f8"; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 0; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio=scsi_read_mmc; + rs="be 00,f8"; if(i==0)break; case 4: j=4; - d->read_audio=scsi_read_mmc3B; - rs="be 06,f8"; + d->private_data->mmc_use_sectortype_cdda = 1; + d->private_data->mmc_use_dap = 0; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio=scsi_read_mmc; + rs="be 04,f8"; if(i==0)break; case 5: j=5; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 1; + d->private_data->mmc_use_channel_selection_all = 0; d->read_audio=scsi_read_mmc; - rs="be 00,10"; + rs="be 02,10"; if(i==0)break; case 6: j=6; - d->read_audio=scsi_read_mmc2; - rs="be 00,f8"; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 1; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio=scsi_read_mmc; + rs="be 02,f8"; if(i==0)break; case 7: j=7; - d->read_audio=scsi_read_mmc3; - rs="be 04,f8"; + d->private_data->mmc_use_sectortype_cdda = 1; + d->private_data->mmc_use_dap = 1; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio=scsi_read_mmc; + rs="be 06,f8"; if(i==0)break; case 8: j=8; @@ -1547,11 +1581,7 @@ long i; if(!(d->read_audio==scsi_read_mmc || - d->read_audio==scsi_read_mmc2 || - d->read_audio==scsi_read_mmc3 || - d->read_audio==scsi_read_mmcB || - d->read_audio==scsi_read_mmc2B || - d->read_audio==scsi_read_mmc3B)){ + d->read_audio==scsi_read_mmc2)){ cdmessage(d,"This command set may use a Force Unit Access bit."); cdmessage(d,"\nChecking drive for FUA bit support...\n"); @@ -1627,17 +1657,25 @@ if((b[0]&0x3F)==0x2A){ /* MMC style drive! */ d->is_mmc=1; + d->private_data->mmc_has_c2 = 0; + d->private_data->mmc_use_c2 = 0; if(b[1]>=4){ if(b[5]&0x1){ cdmessage(d,"\tDrive is MMC style\n"); - return(1); }else{ cdmessage(d,"\tDrive is MMC, but reports CDDA incapable.\n"); cdmessage(d,"\tIt will likely not be able to read audio data.\n"); - return(1); } + if (b[5]&0x10) + { + d->private_data->mmc_has_c2 = 1; + /* TODO: Make this optional? */ + d->private_data->mmc_use_c2 = 1; + cdmessage(d,"\tDrive supports reporting C2 errors\n"); + } } + return 1; } } @@ -1683,16 +1721,29 @@ d->enable_cdda = Dummy; d->read_audio = scsi_read_D8; d->fua=0x0; + d->private_data->data_size = CD_FRAMESIZE_RAW; + d->private_data->c2_buffer=NULL; if(d->is_atapi)d->lun=0; /* it should already be; just to make sure */ if(d->is_mmc){ - d->read_audio = scsi_read_mmc2B; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 0; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio = scsi_read_mmc; d->bigendianp=0; check_exceptions(d,mmc_list); + if (d->private_data->mmc_use_c2) + { + /* 1 bit for every byte */ + d->private_data->data_size += CD_C2BUFFERSIZE; + } }else{ if(d->is_atapi){ /* Not MMC maybe still uses 0xbe */ - d->read_audio = scsi_read_mmc2B; + d->private_data->mmc_use_sectortype_cdda = 0; + d->private_data->mmc_use_dap = 0; + d->private_data->mmc_use_channel_selection_all = 1; + d->read_audio = scsi_read_mmc; d->bigendianp=0; check_exceptions(d,atapi_list); }else{ @@ -1725,8 +1776,11 @@ check_cache(d); d->error_retry=1; - d->private_data->sg_hd=realloc(d->private_data->sg_hd,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128); + d->private_data->sg_hd=realloc(d->private_data->sg_hd,d->nsectors*d->private_data->data_size + SG_OFF + 128); d->private_data->sg_buffer=((unsigned char *)d->private_data->sg_hd)+SG_OFF; + /* TODO: Should get reallocated? But where should the initial allocation + * be in that case? Never gets free()d. */ + d->private_data->c2_buffer=malloc(d->nsectors*(CD_C2BUFFERSIZE)); d->report_all=1; return(0); } Index: interface/low_interface.h =================================================================== --- interface/low_interface.h (revision 16022) +++ interface/low_interface.h (working copy) @@ -100,8 +100,17 @@ struct cdda_private_data { struct sg_header *sg_hd; unsigned char *sg_buffer; /* points into sg_hd */ + unsigned char *c2_buffer; clockid_t clock; int last_milliseconds; + int data_size; + + int mmc_has_c2; + int mmc_use_c2; + + int mmc_use_sectortype_cdda; + int mmc_use_dap; + int mmc_use_channel_selection_all; }; #define MAX_RETRIES 8 _______________________________________________ Paranoia-dev mailing list Paranoia-dev@... http://lists.xiph.org/mailman/listinfo/paranoia-dev |
|
|
Re: C2 error support.> Here is an initial patch. It would be nice if people could test
> this and give feedback. C2 error information is on the short-term feature list (along with more sophisticated reconstruction than offered by the redbook spec), so allow me to try to bend this all into that direction :-) > Some comments about the patch: > - I've merged all the i_read_mmc() functions to 1 function > so that not all of them need to be modified. The dispatch design currently there is cute and badly out of date, and the next major release with new features (including C2) should ditch the old interface entirely. We need to make sure to probe for the capability carefully, pay attention to whether or not it is actually working, and not attempt to use it on dives that don't support it correctly. It's less common that newer drives will brick if you ask them for something they can't do, but it's a regular problem in old drives. > - rs was set wrong in verify_read_command(). They all had > the DAP bit inverted. Oh, ha, you're right. I had to look three times to see it even after you told me. "Functional testing does not necessarily find cosmetic/informational errors" > - There are still a few TODOs in it. Good to get it working, play with it, and submit for review before going too all out. > I've been testing this with a CD with lots of scratches. What > I've seen: > - My plextor reads this CD at full speed (40x) every time, always > identical, never returns C2 errors. That sounds problematic. Unless it's changed, the Plextors should be among the drives that return full corrected and uncorrected C2 information. Even a pristine disc has corrected errors. > - The other drives have problems reading this, even at speed 1. > Without this patch I got 20+ different files. I have not yet looked at what you're doing with the C2 information you collect-- how is the matching/verification algorithm modified? > Once I got a total of 1.8 million > C2 errors for 1 track, but the result was still good. That sounds about right :-) Are you leveraging any sort of your own reconstruction or relying on the drive to interpolate? > - The current patch marks all samples belonging to 1 byte of c2 > error information as having a problem while it should probably > be possible to only mark the sample that is affected. *yes*. Especially as, on a general purpose CPU, we have access to far more powerful audio reconstruction techniques than the drive can do in firmware. The better job we do seperating the good samples from the bad (even the good bits from the bad bits within samples!), the better. The physical structure of the CD is going to scatter adjacent samples to different parts of the surface such that runs of bad bytes are rare. usually you get interleaved errors, which naturally makes recovery earlier. We must not toss that advantage away. > For some > reason that's currently unclear to me this always results in a > good file and trying to mark only the bad one resulted in a bad > file. (Maybe I should mark both left and right instead of only > left or right?) Well, we'd need to figure that out :-) Probably has to do with exactly how the matching's been modified to deal with the flags. Monty _______________________________________________ Paranoia-dev mailing list Paranoia-dev@... http://lists.xiph.org/mailman/listinfo/paranoia-dev |
|
|
Re: C2 error support.On Wed, May 27, 2009 at 04:58:28PM -0400, xiphmont@... wrote:
> We need to make sure to probe for the capability carefully, pay > attention to whether or not it is actually working, and not attempt to > use it on dives that don't support it correctly. It's less common > that newer drives will brick if you ask them for something they can't > do, but it's a regular problem in old drives. The current code looks at the (legacy) 2A page to see if C2 is supported or not, and then always turns it on. There are a few things wrong with it: - If you look at the mmc1 spec it says that being able to request it is mandatory, but drives that don't support it should just return 0 bits, giving you the impression that there is no error. But it's not because that's what the spec says, that that is what all drives do. So we might need a test to see how much data we really receive when we requested it. - If your drive fully supports it, you might want to test the effect of having it turned on or off - We should probably not rely on the legacy code page to detect it for new drives. > > I've been testing this with a CD with lots of scratches. What > > I've seen: > > - My plextor reads this CD at full speed (40x) every time, always > > identical, never returns C2 errors. > > That sounds problematic. Unless it's changed, the Plextors should be > among the drives that return full corrected and uncorrected C2 > information. Even a pristine disc has corrected errors. C2 error information is only uncorrected errors, there is no indication of corrected errors. Looking at documentation of plextor software, it seems they can also read C1 and C2 error rates, but they probably get that using vendor specific commands. Also not that you do not get the C1/C2 error correcting bytes themself (8*98=784), just 1 bit for every byte, so 24/8*98=294 bytes. > > - The other drives have problems reading this, even at speed 1. > > Without this patch I got 20+ different files. > > I have not yet looked at what you're doing with the C2 information you > collect-- how is the matching/verification algorithm modified? The only thing it does it marking samples that had an error as unread. The code does the same thing if the whole read wasn't complete. I did not really look into how all the algorithmes work, but it seems this was enough for me to get it working. > > Once I got a total of 1.8 million > > C2 errors for 1 track, but the result was still good. > > That sounds about right :-) Are you leveraging any sort of your own > reconstruction or relying on the drive to interpolate? As far as I know, based on the debug info I added, cdparanoia just reads it multiple times until it got all samples (twice?) without an error. If it realy fails to read only some bytes, we could interpolate ourself. > > - The current patch marks all samples belonging to 1 byte of c2 > > error information as having a problem while it should probably > > be possible to only mark the sample that is affected. > > *yes*. Especially as, on a general purpose CPU, we have access to far > more powerful audio reconstruction techniques than the drive can do in > firmware. The better job we do seperating the good samples from the > bad (even the good bits from the bad bits within samples!), the > better. The C1/C2 error correction works on byte basis. Either the whole byte is good or bad. It's designed to handle burst errors and not single bit errors. > The physical structure of the CD is going to scatter adjacent samples > to different parts of the surface such that runs of bad bytes are > rare. usually you get interleaved errors, which naturally makes > recovery earlier. We must not toss that advantage away. If I remember correctly, they have sample 0, 2, 4, 6 in subframe 0 and 1, 3, 5, 7 in the next. If subframe 0 can't be recovered, you can interpolate the samples based on the other subframe. > > For some > > reason that's currently unclear to me this always results in a > > good file and trying to mark only the bad one resulted in a bad > > file. (Maybe I should mark both left and right instead of only > > left or right?) > > Well, we'd need to figure that out :-) Probably has to do with > exactly how the matching's been modified to deal with the flags. I was thinking that maybe the matching now only looks at the left channel and assumes that if you have a sample for left you also have the right sample. But I'll look into that. Kurt _______________________________________________ Paranoia-dev mailing list Paranoia-dev@... http://lists.xiph.org/mailman/listinfo/paranoia-dev |
| Free embeddable forum powered by Nabble | Forum Help |