~ubuntu-branches/ubuntu/edgy/libcdio/edgy-updates

« back to all changes in this revision

Viewing changes to lib/cdda_interface/common_interface.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2005-11-15 16:53:23 UTC
  • mfrom: (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20051115165323-peroku75syl2j36u
Tags: 0.76-1ubuntu1
* Sync to new Debian version, manually apply Ubuntu patches:
  - debian/control: Remove dpkg-awk build dependency.
  - debian/rules: hardcode $LIBCDEV. This keeps the diff small (compared to
    the original patch of changing every ${libcdev} occurence).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  $Id: common_interface.c,v 1.13 2005/02/05 12:37:35 rocky Exp $
 
3
 
 
4
  Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
 
5
  Copyright (C) 1998, 2002 Monty monty@xiph.org
 
6
  
 
7
  This program is free software; you can redistribute it and/or modify
 
8
  it under the terms of the GNU General Public License as published by
 
9
  the Free Software Foundation; either version 2 of the License, or
 
10
  (at your option) any later version.
 
11
  
 
12
  This program is distributed in the hope that it will be useful,
 
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
  GNU General Public License for more details.
 
16
  
 
17
  You should have received a copy of the GNU General Public License
 
18
  along with this program; if not, write to the Free Software
 
19
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
*/
 
21
/******************************************************************
 
22
 *
 
23
 * CDROM communication common to all interface methods is done here 
 
24
 * (mostly ioctl stuff, but not ioctls specific to the 'cooked'
 
25
 * interface) 
 
26
 *
 
27
 ******************************************************************/
 
28
 
 
29
#include <math.h>
 
30
#include "common_interface.h"
 
31
#include "utils.h"
 
32
#include "smallft.h"
 
33
 
 
34
/* Variables to hold debugger-helping enumerations */
 
35
enum paranoia_cdda_enums;
 
36
enum paranoia_jitter_enums;
 
37
 
 
38
/*! Determine Endian-ness of the CD-drive based on reading data from
 
39
  it. Some drives return audio data Big Endian while some (most)
 
40
  return data Little Endian. Drives known to return data bigendian are
 
41
  SCSI drives from Kodak, Ricoh, HP, Philips, Plasmon, Grundig
 
42
  CDR100IPW, and Mitsumi CD-R. ATAPI and MMC drives are little endian.
 
43
 
 
44
  rocky: As someone who didn't write the code, I have to say this is
 
45
  nothing less than brilliant. An FFT is done both ways and the the
 
46
  transform is looked at to see which has data in the FFT (or audible)
 
47
  portion. (Or so that's how I understand it.)
 
48
 
 
49
  @return 1 if big-endian, 0 if little-endian, -1 if we couldn't
 
50
  figure things out or some error.
 
51
 */
 
52
int 
 
53
data_bigendianp(cdrom_drive_t *d)
 
54
{
 
55
  float lsb_votes=0;
 
56
  float msb_votes=0;
 
57
  int i,checked;
 
58
  int endiancache=d->bigendianp;
 
59
  float *a=calloc(1024,sizeof(float));
 
60
  float *b=calloc(1024,sizeof(float));
 
61
  long readsectors=5;
 
62
  int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW);
 
63
  memset(buff, 0, readsectors*CDIO_CD_FRAMESIZE_RAW);
 
64
 
 
65
  /* look at the starts of the audio tracks */
 
66
  /* if real silence, tool in until some static is found */
 
67
 
 
68
  /* Force no swap for now */
 
69
  d->bigendianp=-1;
 
70
  
 
71
  cdmessage(d,"\nAttempting to determine drive endianness from data...");
 
72
  d->enable_cdda(d,1);
 
73
  for(i=0,checked=0;i<d->tracks;i++){
 
74
    float lsb_energy=0;
 
75
    float msb_energy=0;
 
76
    if(cdda_track_audiop(d,i+1)==1){
 
77
      long firstsector=cdda_track_firstsector(d,i+1);
 
78
      long lastsector=cdda_track_lastsector(d,i+1);
 
79
      int zeroflag=-1;
 
80
      long beginsec=0;
 
81
      
 
82
      /* find a block with nonzero data */
 
83
      
 
84
      while(firstsector+readsectors<=lastsector){
 
85
        int j;
 
86
        
 
87
        if(d->read_audio(d,buff,firstsector,readsectors)>0){
 
88
          
 
89
          /* Avoid scanning through jitter at the edges */
 
90
          for(beginsec=0;beginsec<readsectors;beginsec++){
 
91
            int offset=beginsec*CDIO_CD_FRAMESIZE_RAW/2;
 
92
            /* Search *half* */
 
93
            for(j=460;j<128+460;j++)
 
94
              if(buff[offset+j]!=0){
 
95
                zeroflag=0;
 
96
                break;
 
97
              }
 
98
            if(!zeroflag)break;
 
99
          }
 
100
          if(!zeroflag)break;
 
101
          firstsector+=readsectors;
 
102
        }else{
 
103
          d->enable_cdda(d,0);
 
104
          free(a);
 
105
          free(b);
 
106
          free(buff);
 
107
          return(-1);
 
108
        }
 
109
      }
 
110
 
 
111
      beginsec*=CDIO_CD_FRAMESIZE_RAW/2;
 
112
      
 
113
      /* un-interleave for an FFT */
 
114
      if(!zeroflag){
 
115
        int j;
 
116
        
 
117
        for(j=0;j<128;j++)
 
118
          a[j] = le16_to_cpu(buff[j*2+beginsec+460]);
 
119
        for(j=0;j<128;j++)
 
120
          b[j] = le16_to_cpu(buff[j*2+beginsec+461]);
 
121
 
 
122
        fft_forward(128,a,NULL,NULL);
 
123
        fft_forward(128,b,NULL,NULL);
 
124
 
 
125
        for(j=0;j<128;j++)
 
126
          lsb_energy+=fabs(a[j])+fabs(b[j]);
 
127
        
 
128
        for(j=0;j<128;j++)
 
129
          a[j] = be16_to_cpu(buff[j*2+beginsec+460]);
 
130
 
 
131
        for(j=0;j<128;j++)
 
132
          b[j] = be16_to_cpu(buff[j*2+beginsec+461]);
 
133
 
 
134
        fft_forward(128,a,NULL,NULL);
 
135
        fft_forward(128,b,NULL,NULL);
 
136
 
 
137
        for(j=0;j<128;j++)
 
138
          msb_energy+=fabs(a[j])+fabs(b[j]);
 
139
      }
 
140
    }
 
141
    if(lsb_energy<msb_energy){
 
142
      lsb_votes+=msb_energy/lsb_energy;
 
143
      checked++;
 
144
    }else
 
145
      if(lsb_energy>msb_energy){
 
146
        msb_votes+=lsb_energy/msb_energy;
 
147
        checked++;
 
148
      }
 
149
 
 
150
    if(checked==5 && (lsb_votes==0 || msb_votes==0))break;
 
151
    cdmessage(d,".");
 
152
  }
 
153
 
 
154
  free(buff);
 
155
  free(a);
 
156
  free(b);
 
157
  d->bigendianp=endiancache;
 
158
  d->enable_cdda(d,0);
 
159
 
 
160
  /* How did we vote?  Be potentially noisy */
 
161
  if (lsb_votes>msb_votes) {
 
162
    char buffer[256];
 
163
    cdmessage(d,"\n\tData appears to be coming back Little Endian.\n");
 
164
    sprintf(buffer,"\tcertainty: %d%%\n",(int)
 
165
            (100.*lsb_votes/(lsb_votes+msb_votes)+.5));
 
166
    cdmessage(d,buffer);
 
167
    return(0);
 
168
  } else {
 
169
    if(msb_votes>lsb_votes){
 
170
      char buffer[256];
 
171
      cdmessage(d,"\n\tData appears to be coming back Big Endian.\n");
 
172
      sprintf(buffer,"\tcertainty: %d%%\n",(int)
 
173
              (100.*msb_votes/(lsb_votes+msb_votes)+.5));
 
174
      cdmessage(d,buffer);
 
175
      return(1);
 
176
    }
 
177
 
 
178
    cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n");
 
179
    return(bigendianp());
 
180
    return(-1);
 
181
  }
 
182
}
 
183
 
 
184
/************************************************************************/
 
185
 
 
186
/*! Here we fix up a couple of things that will never happen.  yeah,
 
187
   right.  
 
188
 
 
189
   rocky OMITTED FOR NOW:
 
190
   The multisession stuff is from Hannu's code; it assumes it knows
 
191
   the leadout/leadin size.
 
192
 
 
193
   @return -1 if we can't get multisession info, 0 if there is one
 
194
   session only or the multi-session LBA is less than or 100 (don't
 
195
   ask me why -- I don't know), and 1 if the multi-session lba is
 
196
   greater than 100.
 
197
*/
 
198
int 
 
199
FixupTOC(cdrom_drive_t *d, track_t i_tracks)
 
200
{
 
201
  int j;
 
202
  
 
203
  /* First off, make sure the 'starting sector' is >=0 */
 
204
  
 
205
  for( j=0; j<i_tracks; j++){
 
206
    if (d->disc_toc[j].dwStartSector<0 ) {
 
207
      cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging"
 
208
                ".\n");
 
209
      d->disc_toc[j].dwStartSector=0;
 
210
    }
 
211
    if( j<i_tracks-1 && d->disc_toc[j].dwStartSector>
 
212
       d->disc_toc[j+1].dwStartSector ) {
 
213
      cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging"
 
214
                ".\n");
 
215
      d->disc_toc[j].dwStartSector=0;
 
216
    }
 
217
 
 
218
  }
 
219
  /* Make sure the listed 'starting sectors' are actually increasing.
 
220
     Flag things that are blatant/stupid/wrong */
 
221
  {
 
222
    lsn_t last=d->disc_toc[0].dwStartSector;
 
223
    for ( j=1; j<i_tracks; j++){
 
224
      if ( d->disc_toc[j].dwStartSector<last ) {
 
225
        cdmessage(d,"\n\tTOC entries claim non-increasing offsets: massaging"
 
226
                  ".\n");
 
227
         d->disc_toc[j].dwStartSector=last;
 
228
        
 
229
      }
 
230
      last=d->disc_toc[j].dwStartSector;
 
231
    }
 
232
  }
 
233
 
 
234
#if LOOKED_OVER
 
235
  /* For a scsi device, the ioctl must go to the specialized SCSI
 
236
     CDROM device, not the generic device. */
 
237
 
 
238
  if (d->ioctl_fd != -1) {
 
239
    struct cdrom_multisession ms_str;
 
240
    int result;
 
241
 
 
242
    ms_str.addr_format = CDROM_LBA;
 
243
    result = ioctl(d->ioctl_fd, CDROMMULTISESSION, &ms_str);
 
244
    if (result == -1) return -1;
 
245
 
 
246
    if (ms_str.addr.lba > 100) {
 
247
 
 
248
      /* This is an odd little piece of code --Monty */
 
249
 
 
250
      /* believe the multisession offset :-) */
 
251
      /* adjust end of last audio track to be in the first session */
 
252
      for (j = i_tracks-1; j >= 0; j--) {
 
253
        if (j > 0 && !IS_AUDIO(d,j) && IS_AUDIO(d,j-1)) {
 
254
          if ((d->disc_toc[j].dwStartSector > ms_str.addr.lba - 11400) &&
 
255
              (ms_str.addr.lba - 11400 > d->disc_toc[j-1].dwStartSector))
 
256
            d->disc_toc[j].dwStartSector = ms_str.addr.lba - 11400;
 
257
          break;
 
258
        }
 
259
      }
 
260
      return 1;
 
261
    }
 
262
  }
 
263
#endif
 
264
 
 
265
  return 0;
 
266
}
 
267
 
 
268