コード例 #1
0
static int
verify_read_command(cdrom_drive_t *d)
{
  int i;
  int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW);
  int audioflag=0;
  int i_test_flags = d->i_test_flags;

  d->i_test_flags = 0;

  cdmessage(d,"Verifying drive can read CDDA...\n");

  d->enable_cdda(d,1);

  for(i=1;i<=d->tracks;i++){
    if(cdda_track_audiop(d,i)==1){
      long firstsector=cdda_track_firstsector(d,i);
      long lastsector=cdda_track_lastsector(d,i);
      long sector=(firstsector+lastsector)>>1;
      audioflag=1;

      if(d->read_audio(d,buff,sector,1)>0){
	cdmessage(d,"\tExpected command set reads OK.\n");
	d->enable_cdda(d,0);
	free(buff);
	d->i_test_flags = i_test_flags;
	return(0);
      }
    }
  }
コード例 #2
0
/*! Determine Endian-ness of the CD-drive based on reading data from
  it. Some drives return audio data Big Endian while some (most)
  return data Little Endian. Drives known to return data bigendian are
  SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig
  CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian.

  rocky: As someone who didn't write the code, I have to say this is
  nothing less than brilliant. An FFT is done both ways and the the
  transform is looked at to see which has data in the FFT (or audible)
  portion. (Or so that's how I understand it.)

  @return 1 if big-endian, 0 if little-endian, -1 if we couldn't
  figure things out or some error.
 */
int 
data_bigendianp(cdrom_drive_t *d)
{
  float lsb_votes=0;
  float msb_votes=0;
  int i,checked;
  int endiancache=d->bigendianp;
  float *a=calloc(1024,sizeof(float));
  float *b=calloc(1024,sizeof(float));
  long readsectors=5;
  int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t));
  memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW*sizeof(int16_t));

  /* look at the starts of the audio tracks */
  /* if real silence, tool in until some static is found */

  /* Force no swap for now */
  d->bigendianp=-1;
  
  cdmessage(d,"\nAttempting to determine drive endianness from data...");
  d->enable_cdda(d,1);
  for(i=0,checked=0;i<d->tracks;i++){
    float lsb_energy=0;
    float msb_energy=0;
    if(cdda_track_audiop(d,i+1)==1){
      long firstsector=cdda_track_firstsector(d,i+1);
      long lastsector=cdda_track_lastsector(d,i+1);
      int zeroflag=-1;
      long beginsec=0;
      
      /* find a block with nonzero data */
      
      while(firstsector+readsectors<=lastsector){
	int j;
	
	if(d->read_audio(d,buff,firstsector,readsectors)>0){
	  
	  /* Avoid scanning through jitter at the edges */
	  for(beginsec=0;beginsec<readsectors;beginsec++){
	    int offset=beginsec*CDIO_CD_FRAMESIZE_RAW/2;
	    /* Search *half* */
	    for(j=460;j<128+460;j++)
	      if(buff[offset+j]!=0){
		zeroflag=0;
		break;
	      }
	    if(!zeroflag)break;
	  }
	  if(!zeroflag)break;
	  firstsector+=readsectors;
	}else{
	  d->enable_cdda(d,0);
	  free(a);
	  free(b);
	  free(buff);
	  return(-1);
	}
      }

      beginsec*=CDIO_CD_FRAMESIZE_RAW/2;
      
      /* un-interleave for an FFT */
      if(!zeroflag){
	int j;
	
	for(j=0;j<128;j++)
	  a[j] = le16_to_cpu(buff[j*2+beginsec+460]);
	for(j=0;j<128;j++)
	  b[j] = le16_to_cpu(buff[j*2+beginsec+461]);

	fft_forward(128,a,NULL,NULL);
	fft_forward(128,b,NULL,NULL);

	for(j=0;j<128;j++)
	  lsb_energy+=fabs(a[j])+fabs(b[j]);
	
	for(j=0;j<128;j++)
	  a[j] = be16_to_cpu(buff[j*2+beginsec+460]);

	for(j=0;j<128;j++)
	  b[j] = be16_to_cpu(buff[j*2+beginsec+461]);

	fft_forward(128,a,NULL,NULL);
	fft_forward(128,b,NULL,NULL);

	for(j=0;j<128;j++)
	  msb_energy+=fabs(a[j])+fabs(b[j]);
      }
    }
    if(lsb_energy<msb_energy){
      lsb_votes+=msb_energy/lsb_energy;
      checked++;
    }else
      if(lsb_energy>msb_energy){
	msb_votes+=lsb_energy/msb_energy;
	checked++;
      }

    if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
    cdmessage(d,".");
  }

  free(buff);
  free(a);
  free(b);
  d->bigendianp=endiancache;
  d->enable_cdda(d,0);

  /* How did we vote?  Be potentially noisy */
  if (lsb_votes>msb_votes) {
    char buffer[256];
    cdmessage(d,"\n\tData appears to be coming back Little Endian.\n");
    sprintf(buffer,"\tcertainty: %d%%\n",(int)
	    (100.*lsb_votes/(lsb_votes+msb_votes)+.5));
    cdmessage(d,buffer);
    return(0);
  } else {
    if(msb_votes>lsb_votes){
      char buffer[256];
      cdmessage(d,"\n\tData appears to be coming back Big Endian.\n");
      sprintf(buffer,"\tcertainty: %d%%\n",(int)
	      (100.*msb_votes/(lsb_votes+msb_votes)+.5));
      cdmessage(d,buffer);
      return(1);
    }

    cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
    return(bigendianp());
  }
}
コード例 #3
0
/*! Here we fix up a couple of things that will never happen.  yeah,
   right.  

   The multisession stuff is from Hannu code; it assumes it knows the
   leadout/leadin size.  [I think Hannu refers to Hannu Savolainen
   from GNU/Linux Kernel code.]

   @return -1 if we can't get multisession info, 0 if there is one
   session only or the last session LBA is the same as the first audio
   track and 1 if the multi-session lba is higher than first audio track
*/
int 
FixupTOC(cdrom_drive_t *d, track_t i_tracks)
{
  int j;
  
  /* First off, make sure the 'starting sector' is >=0 */
  
  for( j=0; j<i_tracks; j++){
    if (d->disc_toc[j].dwStartSector<0 ) {
      cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
		".\n");
      d->disc_toc[j].dwStartSector=0;
    }
    if( j<i_tracks-1 && d->disc_toc[j].dwStartSector>
       d->disc_toc[j+1].dwStartSector ) {
      cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
		".\n");
      d->disc_toc[j].dwStartSector=0;
    }

  }
  /* Make sure the listed 'starting sectors' are actually increasing.
     Flag things that are blatant/stupid/wrong */
  {
    lsn_t last=d->disc_toc[0].dwStartSector;
    for ( j=1; j<i_tracks; j++){
      if ( d->disc_toc[j].dwStartSector<last ) {
	cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
		  ".\n");
	 d->disc_toc[j].dwStartSector=last;
	
      }
      last=d->disc_toc[j].dwStartSector;
    }
  }

  d->audio_last_sector = CDIO_INVALID_LSN;
  
  {
    lsn_t last_ses_lsn;
    if (cdio_get_last_session (d->p_cdio, &last_ses_lsn) < 0)
      return -1;
    
    /* A Red Book Disc must have only one session, otherwise this is a 
     * CD Extra */
    if (last_ses_lsn > d->disc_toc[0].dwStartSector) {
      /* CD Extra discs have two session, the first one ending after 
       * the last audio track 
       * Thus the need to fix the length of the the audio data portion to 
       * not cross the lead-out of this session */
      for (j = i_tracks-1; j > 1; j--) {
	if (cdio_get_track_format(d->p_cdio, j+1) != TRACK_FORMAT_AUDIO && 
	    cdio_get_track_format(d->p_cdio, j) == TRACK_FORMAT_AUDIO) {
	  /* First session lead-out is 1:30
	   * Lead-ins are 1:00
	   * Every session's first track have a 0:02 pregap
	   *
	   * That makes a control data section of (90+60+2)*75 sectors in the 
	   * last audio track */
	  const int gap = ((90+60+2) * CDIO_CD_FRAMES_PER_SEC);
	  
	  if ((last_ses_lsn - gap >= d->disc_toc[j-1].dwStartSector) &&
	      (last_ses_lsn - gap < d->disc_toc[j].dwStartSector)) {
	    d->audio_last_sector = last_ses_lsn - gap - 1;
	    break;
	  }
	}
      }
      return 1;
    }
  }
    
  return 0;
}
コード例 #4
0
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
#ifdef HAVE_DRAND48
    jitter_flag = (drand48() > .9) ? 1 : 0;
#else
    jitter_flag = (((float)rand()/RAND_MAX) > .9) ? 1 : 0;
#endif

  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            : ;
    }
#ifdef HAVE_DRAND48
    i_jitter = i_coeff * (int)((drand48()-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#else
    i_jitter = i_coeff * (int)((((float)rand()/RAND_MAX)-.5)*CDIO_CD_FRAMESIZE_RAW/8);
#endif

    /* 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) {
#if TRACE_PARANOIA
      char buffer[256];
      sprintf(buffer, "jittering by %d, offset %ld\n", i_jitter,
	      i_jitter_offset);
      cdmessage(d,buffer);
#endif

      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. */
    if (p) memcpy(p, p_buf, i_sectors*CDIO_CD_FRAMESIZE_RAW);
  } else {
    /* Got full amount, but now adjust size for jittering. */
    if (p) memcpy(p, p_buf+i_jitter_offset, i_sectors_orig*CDIO_CD_FRAMESIZE_RAW);
    i_sectors = i_sectors_orig;
  }

  free(p_buf);
  return(i_sectors);
}