diff --git a/include/cdio/cdda.h b/include/cdio/cdda.h index bf71784d..02c8f4d7 100644 --- a/include/cdio/cdda.h +++ b/include/cdio/cdda.h @@ -1,5 +1,5 @@ /* - $Id: cdda.h,v 1.8 2005/01/22 03:43:03 rocky Exp $ + $Id: cdda.h,v 1.9 2005/01/22 18:11:32 rocky Exp $ Copyright (C) 2004, 2005 Rocky Bernstein Copyright (C) 2001 Xiph.org @@ -111,26 +111,35 @@ struct cdrom_drive_s { }; -/**< under-run testing. The below bit is set for testing. */ -#define CDDA_TEST_UNDERRUN 16 -#if TESTING_IS_FINISHED -/** jitter testing. The first two bits are set to determine - how much jitter to simulate. +/**< jitter testing. The first two bits are set to determine + the byte-distance we will jitter the data; 0 is no shifting. */ #define CDDA_TEST_JITTER_SMALL 1 #define CDDA_TEST_JITTER_LARGE 2 #define CDDA_TEST_JITTER_MASSIVE 3 +/**< jitter testing. Set the below bit to always cause jittering on reads. + The below bit only has any effect if the first two (above) bits are + nonzero. If the above bits are set, but the below bit isn't we'll + jitter 90% of the time. + */ +#define CDDA_TEST_ALWAYS_JITTER 4 + /** fragment testing */ -#define CDDA_TEST_FRAG_SMALL (1<<2) -#define CDDA_TEST_FRAG_LARGE (2<<2) -#define CDDA_TEST_FRAG_MASSIVE (3<<2) +#define CDDA_TEST_FRAG_SMALL (1<<3) +#define CDDA_TEST_FRAG_LARGE (2<<3) +#define CDDA_TEST_FRAG_MASSIVE (3<<3) + +/**< under-run testing. The below bit is set for testing. */ +#define CDDA_TEST_UNDERRUN 64 + +#if TESTING_IS_FINISHED /** scratch testing */ -#define CDDA_TEST_SCRATCH 32 -#undef CDDA_TEST_BOGUS_BYTES 64 -#undef CDDA_TEST_DROPDUPE_BYTES 128 +#define CDDA_TEST_SCRATCH 128 +#undef CDDA_TEST_BOGUS_BYTES 256 +#undef CDDA_TEST_DROPDUPE_BYTES 512 #endif /* TESTING_IS_FINISHED */ /** autosense functions */ diff --git a/lib/cdda_interface/cooked_interface.c b/lib/cdda_interface/cooked_interface.c index 2b2b96d5..befcbe7b 100644 --- a/lib/cdda_interface/cooked_interface.c +++ b/lib/cdda_interface/cooked_interface.c @@ -1,5 +1,5 @@ /* - $Id: cooked_interface.c,v 1.12 2005/01/18 00:57:20 rocky Exp $ + $Id: cooked_interface.c,v 1.13 2005/01/22 18:11:32 rocky Exp $ Copyright (C) 2004, 2005 Rocky Bernstein Original interface.c Copyright (C) 1994-1997 @@ -69,33 +69,24 @@ cooked_setspeed(cdrom_drive_t *d, int i_speed) return cdio_set_speed(d->p_cdio, i_speed); } -/* read 'SectorBurst' adjacent sectors of audio sectors - * to Buffer '*p' beginning at sector 'lSector' +/* read 'i_sector' adjacent audio sectors + * into buffer '*p' beginning at sector 'begin' */ static long int -cooked_read (cdrom_drive_t *d, void *p, lsn_t begin, long sectors) +read_blocks (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors) { - int retry_count,err; + int retry_count = 0; + int err; char *buffer=(char *)p; - /* read d->nsectors at a time, max. */ - sectors=( sectors > d->nsectors && d->nsectors > 0 ? d->nsectors : sectors); - - /* If we are testing under-run correction, we will deliberately set - what we read a frame short. */ - if (d->i_test_flags & CDDA_TEST_UNDERRUN ) - sectors--; - - retry_count=0; - do { - err = cdio_read_audio_sectors( d->p_cdio, buffer, begin, sectors); + err = cdio_read_audio_sectors( d->p_cdio, buffer, begin, i_sectors); if ( 0 != err ) { if (!d->error_retry) return -7; - if (sectors==1) { + if (i_sectors==1) { /* *Could* be I/O or media error. I think. If we're at 30 retries, we better skip this unhappy little sector. */ @@ -111,8 +102,8 @@ cooked_read (cdrom_drive_t *d, void *p, lsn_t begin, long sectors) } if(retry_count>4) - if(sectors>1) - sectors=sectors*3/4; + if(i_sectors>1) + i_sectors=i_sectors*3/4; retry_count++; if (retry_count>MAX_RETRIES) { cderror(d,"007: Unknown, unrecoverable error reading data\n"); @@ -122,7 +113,115 @@ cooked_read (cdrom_drive_t *d, void *p, lsn_t begin, long sectors) break; } while (err); - return(sectors); + return(i_sectors); +} + +typedef enum { + JITTER_NONE = 0, + JITTER_SMALL= 1, + JITTER_LARGE= 2, + JITTER_MASSIVE=3 +} jitter_baddness_t; + +/* read 'i_sector' adjacent audio sectors + * into buffer '*p' beginning at sector 'begin' + */ + +static long int +jitter_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors, + jitter_baddness_t jitter_badness) +{ + static int i_jitter=0; + int jitter_flag; + long i_sectors_orig = i_sectors; + long i_jitter_offset = 0; + + char *p_buf=malloc(CDIO_CD_FRAMESIZE_RAW*(i_sectors+1)); + + if (d->i_test_flags & CDDA_TEST_ALWAYS_JITTER) + jitter_flag = 1; + else + jitter_flag = (drand48() > .9) ? 1 : 0; + + if (jitter_flag) { + int i_coeff = 0; + int i_jitter_sectors = 0; + switch(jitter_badness) { + case JITTER_SMALL : i_coeff = 4; break; + case JITTER_LARGE : i_coeff = 32; break; + case JITTER_MASSIVE: i_coeff = 128; break; + case JITTER_NONE : + default : ; + } + i_jitter = i_coeff * (int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8); + + /* We may need to add another sector to compensate for the bytes that + will be dropped off when jittering, and the begin location may + be a little different. + */ + i_jitter_sectors = i_jitter / CDIO_CD_FRAMESIZE_RAW; + + if (i_jitter >= 0) + i_jitter_offset = i_jitter % CDIO_CD_FRAMESIZE_RAW; + else { + i_jitter_offset = CDIO_CD_FRAMESIZE_RAW - + (-i_jitter % CDIO_CD_FRAMESIZE_RAW); + i_jitter_sectors--; + } + + + if (begin + i_jitter_sectors > 0) { + char buffer[256]; + sprintf(buffer, "jittering by %d, offset %ld\n", i_jitter, + i_jitter_offset); + cdmessage(d,buffer); + + begin += i_jitter_sectors; + i_sectors ++; + } else + i_jitter_offset = 0; + + } + + i_sectors = read_blocks(d, p_buf, begin, i_sectors); + + if (i_sectors < 0) return i_sectors; + + if (i_sectors < i_sectors_orig) + /* Had to reduce # of sectors due to read errors. So give full amount, + with no jittering. */ + memcpy(p, p_buf, i_sectors*CDIO_CD_FRAMESIZE_RAW); + else + /* Got full amount, but now adjust size for jittering. */ + memcpy(p, p_buf+i_jitter_offset, i_sectors_orig*CDIO_CD_FRAMESIZE_RAW); + + free(p_buf); + return(i_sectors); +} + +/* read 'i_sector' adjacent audio sectors + * into buffer '*p' beginning at sector 'begin' + */ + +static long int +cooked_read (cdrom_drive_t *d, void *p, lsn_t begin, long i_sectors) +{ + jitter_baddness_t jitter_badness = d->i_test_flags & 0x3; + + /* read d->nsectors at a time, max. */ + i_sectors = ( i_sectors > d->nsectors && d->nsectors > 0 ) + ? d->nsectors : i_sectors; + + /* If we are testing under-run correction, we will deliberately set + what we read a frame short. */ + if (d->i_test_flags & CDDA_TEST_UNDERRUN ) + i_sectors--; + + if (jitter_badness) { + return jitter_read(d, p, begin, i_sectors, jitter_badness); + } else + return read_blocks(d, p, begin, i_sectors); + } /* hook */ diff --git a/src/cd-paranoia/cd-paranoia.c b/src/cd-paranoia/cd-paranoia.c index 655dd1ce..fa4d2b55 100644 --- a/src/cd-paranoia/cd-paranoia.c +++ b/src/cd-paranoia/cd-paranoia.c @@ -847,7 +847,6 @@ main(int argc,char *argv[]) } } - d->i_test_flags = test_flags; switch( cdda_open(d) ) { case -2:case -3:case -4:case -5: report("\nUnable to open disc. Is there an audio CD in the drive?"); @@ -862,6 +861,8 @@ main(int argc,char *argv[]) exit(1); } + d->i_test_flags = test_flags; + /* Dump the TOC */ if (query_only || verbose ) display_toc(d); diff --git a/test/check_paranoia.sh.in b/test/check_paranoia.sh.in index ff72198e..19955d4e 100644 --- a/test/check_paranoia.sh.in +++ b/test/check_paranoia.sh.in @@ -1,5 +1,5 @@ #!/bin/sh -# $Id: check_paranoia.sh.in,v 1.3 2005/01/15 16:05:44 rocky Exp $ +# $Id: check_paranoia.sh.in,v 1.4 2005/01/22 18:11:32 rocky Exp $ # Compare our cd-paranoia with an installed cdparanoia if test "@CMP@" != no -a "@BUILD_CD_PARANOIA_TRUE@"X = X ; then @@ -12,15 +12,23 @@ if test "@CMP@" != no -a "@BUILD_CD_PARANOIA_TRUE@"X = X ; then echo "** Raw cdda.bin extraction differ" exit 3 fi - ../src/cd-paranoia/cd-paranoia -d ./cdda.cue -x 1 -v -r -- "1-" + mv cdda.raw cdda-good.raw + ../src/cd-paranoia/cd-paranoia -d ./cdda.cue -x 64 -v -r -- "1-" mv cdda.raw cdda-underrun.raw ../src/cd-paranoia/cd-paranoia -d ./cdda.cue -r -- "1-" - if @CMP@ ./cdda-underrun.raw ./cdda.raw ; then + if @CMP@ ./cdda-underrun.raw ./cdda-good.raw ; then echo "** Under-run correction okay" else echo "** Under-run correction problem" exit 3 fi + ../src/cd-paranoia/cd-paranoia -d ./cdda.cue -x 5 -v -r -- "1-" + if @CMP@ ./cdda-jitter.raw ./cdda-good.raw ; then + echo "** Jitter correction okay" + else + echo "** Jitter correction problem" + exit 3 + fi exit 0 else echo "Don't see libcdio cd-paranoia program. Test skipped."