2 * Copyright: GNU Public License 2 applies
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * cdparanoia (C) 2008 Monty <monty@xiph.org>
34 #include "interface/cdda_interface.h"
35 #include "paranoia/cdda_paranoia.h"
40 #include "cachetest.h"
42 static long parse_offset(cdrom_drive
*d
, char *offset
, int begin
){
48 char *time
=NULL
,*temp
=NULL
;
51 if(offset
==NULL
)return(-1);
53 /* seperate track from time offset */
54 temp
=strchr(offset
,']');
57 temp
=strchr(offset
,'[');
59 report("Error parsing span argument");
68 int chars
=strspn(offset
,"0123456789");
72 if(track
<0 || track
>d
->tracks
){ /*take track 0 as pre-gap of 1st track*/
74 sprintf(buffer
,"Track #%ld does not exist.",track
);
83 char *sec
=strrchr(time
,'.');
84 if(!sec
)sec
=strrchr(time
,':');
87 chars
=strspn(sec
+1,"0123456789");
96 report("Error parsing span argument");
111 report("Error parsing span argument");
122 if(seconds
==-1 && sectors
==-1)return(-1);
124 ret
=cdda_disc_firstsector(d
);
128 if(seconds
==-1 && sectors
==-1){
129 if(begin
==-1){ /* first half of a span */
130 return(cdda_track_firstsector(d
,track
));
132 return(cdda_track_lastsector(d
,track
));
135 /* relative offset into a track */
136 ret
=cdda_track_firstsector(d
,track
);
140 /* OK, we had some sort of offset into a track */
142 if(sectors
!=-1)ret
+=sectors
;
143 if(seconds
!=-1)ret
+=seconds
*75;
144 if(minutes
!=-1)ret
+=minutes
*60*75;
145 if(hours
!=-1)ret
+=hours
*60*60*75;
147 /* We don't want to outside of the track; if it's relative, that's OK... */
149 if(cdda_sector_gettrack(d
,ret
)!=track
){
150 report("Time/sector offset goes beyond end of specified track.");
155 /* Don't pass up end of session */
157 if(ret
>cdda_disc_lastsector(d
)){
158 report("Time/sector offset goes beyond end of disc.");
167 static void display_toc(cdrom_drive
*d
){
170 report("\nTable of contents (audio tracks only):\n"
171 "track length begin copy pre ch\n"
172 "===========================================================");
174 for(i
=1;i
<=d
->tracks
;i
++)
175 if(cdda_track_audiop(d
,i
)>0){
178 long sec
=cdda_track_firstsector(d
,i
);
179 long off
=cdda_track_lastsector(d
,i
)-sec
+1;
182 "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d] %s %s %s",
184 off
,(int)(off
/(60*75)),(int)((off
/75)%60),(int)(off
%75),
185 sec
,(int)(sec
/(60*75)),(int)((sec
/75)%60),(int)(sec
%75),
186 cdda_track_copyp(d
,i
)?" OK":" no",
187 cdda_track_preemp(d
,i
)?" yes":" no",
188 cdda_track_channels(d
,i
)==2?" 2":" 4");
194 sprintf(buffer
, "TOTAL %7ld [%02d:%02d.%02d] (audio only)",
195 audiolen
,(int)(audiolen
/(60*75)),(int)((audiolen
/75)%60),
202 static void usage(FILE *f
){
207 "(C) 2008 Monty <monty@xiph.org> and Xiph.Org\n\n" \
208 "Report bugs to paranoia@xiph.org\n"\
209 "http://www.xiph.org/paranoia/\n"
212 " cdparanoia [options] <span> [outfile]\n\n"
215 " -v --verbose : extra verbose operation\n"
216 " -q --quiet : quiet operation\n"
217 " -e --stderr-progress : force output of progress information to\n"
218 " stderr (for wrapper scripts)\n"
219 " -l --log-summary <file> : save result summary to file\n"
220 " -V --version : print version info and quit\n"
221 " -Q --query : autosense drive, query disc and quit\n"
222 " -B --batch : 'batch' mode (saves each track to a\n"
224 " -s --search-for-drive : do an exhaustive search for drive\n"
225 " -h --help : print help\n\n"
227 " -p --output-raw : output raw 16 bit PCM in host byte \n"
229 " -r --output-raw-little-endian : output raw 16 bit little-endian PCM\n"
230 " -R --output-raw-big-endian : output raw 16 bit big-endian PCM\n"
231 " -w --output-wav : output as WAV file (default)\n"
232 " -f --output-aiff : output as AIFF file\n"
233 " -a --output-aifc : output as AIFF-C file\n\n"
235 " -c --force-cdrom-little-endian : force treating drive as little endian\n"
236 " -C --force-cdrom-big-endian : force treating drive as big endian\n"
237 " -n --force-default-sectors <n> : force default number of sectors in read\n"
239 " -o --force-search-overlap <n> : force minimum overlap search during\n"
240 " verification to n sectors\n"
241 " -d --force-cdrom-device <dev> : use specified device; disallow \n"
243 " -k --force-cooked-device <dev> : use specified cdrom device and force\n"
244 " use of the old 'cooked ioctl' kernel\n"
245 " interface. -k cannot be used with -d\n"
247 " -g --force-generic-device <dev> : use specified generic scsi device and\n"
248 " force use of the old SG kernel\n"
249 " interface. -g cannot be used with -k.\n"
250 " -S --force-read-speed <n> : read from device at specified speed\n"
251 " -t --toc-offset <n> : Add <n> sectors to the values reported\n"
252 " when addressing tracks. May be negative\n"
253 " -T --toc-bias : Assume that the beginning offset of \n"
254 " track 1 as reported in the TOC will be\n"
255 " addressed as LBA 0. Necessary for some\n"
256 " Toshiba drives to get track boundaries\n"
258 " -O --sample-offset <n> : Add <n> samples to the offset when\n"
259 " reading data. May be negative.\n"
260 " -z --never-skip[=n] : never accept any less than perfect\n"
261 " data reconstruction (don't allow 'V's)\n"
262 " but if [n] is given, skip after [n]\n"
263 " retries without progress.\n"
264 " -Z --disable-paranoia : disable all paranoia checking\n"
265 " -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n"
266 " -X --abort-on-skip : abort on imperfect reads/skips\n"
267 " -U --cache-test : run a complete analysis of drive caching\n"
268 " behavior; verifies that cdparanoia is\n"
269 " correctly modelling a sprcific drive's\n"
270 " cache behavior.\n\n"
273 " :-) Normal operation, low/no jitter\n"
274 " :-| Normal operation, considerable jitter\n"
276 " :-P Unreported loss of streaming in atomic read operation\n"
277 " 8-| Finding read problems at same point during reread; hard to correct\n"
278 " :-0 SCSI/ATAPI transport error\n"
279 " :-( Scratch detected\n"
280 " ;-( Gave up trying to perform a correction\n"
281 " 8-X Aborted (as per -X) due to a scratch/skip\n"
282 " :^D Finished extracting\n\n"
284 "PROGRESS BAR SYMBOLS:\n"
285 "<space> No corrections needed\n"
286 " - Jitter correction required\n"
287 " + Unreported loss of streaming/other error in read\n"
288 " ! Errors are getting through stage 1 but corrected in stage2\n"
289 " e SCSI/ATAPI transport error (corrected)\n"
290 " V Uncorrected error/skip\n\n"
293 "The span argument may be a simple track number or a offset/span\n"
294 "specification. The syntax of an offset/span takes the rough form:\n\n"
296 " 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] \n\n"
298 "Here, 1 and 2 are track numbers; the numbers in brackets provide a\n"
299 "finer grained offset within a particular track. [aa:bb:cc.dd] is in\n"
300 "hours/minutes/seconds/sectors format. Zero fields need not be\n"
301 "specified: [::20], [:20], [20], [20.], etc, would be interpreted as\n"
302 "twenty seconds, [10:] would be ten minutes, [.30] would be thirty\n"
303 "sectors (75 sectors per second).\n\n"
305 "When only a single offset is supplied, it is interpreted as a starting\n"
306 "offset and ripping will continue to the end of he track. If a single\n"
307 "offset is preceeded or followed by a hyphen, the implicit missing\n"
308 "offset is taken to be the start or end of the disc, respectively. Thus:\n\n"
310 " 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to \n"
311 " the end of track 1.\n\n"
313 " 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc\n\n"
315 " -2 Specifies ripping from the beginning of the disc up to\n"
316 " (and including) track 2\n\n"
318 " -2:[30.35] Specifies ripping from the beginning of the disc up to\n"
321 " 2-4 Specifies ripping from the beginning of track two to the\n"
322 " end of track 4.\n\n"
324 "Don't forget to protect square brackets and preceeding hyphens from\n"
326 "A few examples, protected from the shell:\n"
327 " A) query only with exhaustive search for a drive and full reporting\n"
329 " cdparanoia -vsQ\n\n"
330 " B) extract up to and including track 3, putting each track in a seperate\n"
332 " cdparanoia -B -- \"-3\"\n\n"
333 " C) extract from track 1, time 0:30.12 to 1:10.00:\n"
334 " cdparanoia \"1[:30.12]-1[1:10]\"\n\n"
336 "Submit bug reports to paranoia@xiph.org\n\n");
343 static char *callback_strings
[15]={"wrote",
359 static int skipped_flag
=0;
360 static int abort_on_skip
=0;
361 FILE *logfile
= NULL
;
362 static void callback(long inpos
, int function
){
365 (== PROGRESS == [--+!---x--------------> | 007218 01 ] == :-) . ==)
371 static long c_sector
=0,v_sector
=0;
372 static char dispcache
[]=" ";
374 static long lasttime
=0;
375 long sector
,osector
=0;
376 struct timeval thistime
;
377 static char heartbeat
=' ';
378 int position
=0,aheadposition
=0;
379 static int overlap
=0;
380 static int printit
=-1;
384 static int stimeout
=0;
385 char *smilie
="= :-)";
388 fprintf(stderr
,"##: %d [%s] @ %ld\n",
389 function
,(function
>=-2&&function
<=13?callback_strings
[function
+2]:
395 sector
=inpos
/CD_FRAMEWORDS
;
398 if(isatty(STDERR_FILENO
)){
405 if(printit
==1){ /* else don't bother; it's probably being
407 position
=((float)(sector
-callbegin
)/
408 (callend
-callbegin
))*graph
;
410 aheadposition
=((float)(c_sector
-callbegin
)/
411 (callend
-callbegin
))*graph
;
423 if(position
<graph
&& position
>=0)
425 case PARANOIA_CB_VERIFY
:
427 if(overlap
>CD_FRAMEWORDS
)
433 case PARANOIA_CB_READ
:
434 if(sector
>c_sector
)c_sector
=sector
;
437 case PARANOIA_CB_FIXUP_EDGE
:
439 if(overlap
>CD_FRAMEWORDS
)
444 if(dispcache
[position
]==' ')
445 dispcache
[position
]='-';
447 case PARANOIA_CB_FIXUP_ATOM
:
448 if(slevel
<3 || stimeout
>5)slevel
=3;
449 if(dispcache
[position
]==' ' ||
450 dispcache
[position
]=='-')
451 dispcache
[position
]='+';
453 case PARANOIA_CB_READERR
:
455 if(dispcache
[position
]!='V')
456 dispcache
[position
]='e';
458 case PARANOIA_CB_SKIP
:
460 dispcache
[position
]='V';
462 case PARANOIA_CB_OVERLAP
:
465 case PARANOIA_CB_SCRATCH
:
468 case PARANOIA_CB_DRIFT
:
469 if(slevel
<4 || stimeout
>5)slevel
=4;
471 case PARANOIA_CB_FIXUP_DROPPED
:
472 case PARANOIA_CB_FIXUP_DUPED
:
474 if(dispcache
[position
]==' ' ||
475 dispcache
[position
]=='-' ||
476 dispcache
[position
]=='+')
477 dispcache
[position
]='!';
482 case 0: /* finished, or no jitter */
488 case 1: /* normal. no atom, low jitter */
491 case 2: /* normal, overlap > 1 */
497 case 3: /* unreported loss of streaming */
500 case 5: /* dropped/duped bytes */
503 case 6: /* scsi error */
506 case 7: /* scratch */
516 gettimeofday(&thistime
,NULL
);
517 test
=thistime
.tv_sec
*10+thistime
.tv_usec
/100000;
519 if(lasttime
!=test
|| function
==-1 || slast
!=slevel
){
520 if(lasttime
!=test
|| function
==-1){
551 if(abort_on_skip
&& skipped_flag
&& function
!=-1){
553 "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ",
554 " ...aborting; please wait... ",
555 v_sector
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
559 "\r (== PROGRESS == [%s| ...... %02d ] ==%s %c ==) ",
560 dispcache
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
564 "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ",
565 dispcache
,v_sector
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
567 if(aheadposition
>=0 && aheadposition
<graph
&& !(function
==-1))
568 buffer
[aheadposition
+19]='>';
571 fprintf(stderr
,buffer
);
573 if (logfile
!= NULL
&& function
==-1) {
574 fprintf(logfile
,buffer
+1);
575 fprintf(logfile
,"\n\n");
582 /* clear the indicator for next batch */
584 memset(dispcache
,' ',graph
);
587 const char *optstring
= "escCn:o:O:d:g:k:S:prRwafvqVQhZz::YXWBi:Tt:l:U";
589 struct option options
[] = {
590 {"stderr-progress",no_argument
,NULL
,'e'},
591 {"search-for-drive",no_argument
,NULL
,'s'},
592 {"force-cdrom-little-endian",no_argument
,NULL
,'c'},
593 {"force-cdrom-big-endian",no_argument
,NULL
,'C'},
594 {"force-default-sectors",required_argument
,NULL
,'n'},
595 {"force-search-overlap",required_argument
,NULL
,'o'},
596 {"force-cdrom-device",required_argument
,NULL
,'d'},
597 {"force-cooked-device",required_argument
,NULL
,'k'},
598 {"force-generic-device",required_argument
,NULL
,'g'},
599 {"force-read-speed",required_argument
,NULL
,'S'},
600 {"sample-offset",required_argument
,NULL
,'O'},
601 {"toc-offset",required_argument
,NULL
,'t'},
602 {"toc-bias",no_argument
,NULL
,'T'},
603 {"output-raw",no_argument
,NULL
,'p'},
604 {"output-raw-little-endian",no_argument
,NULL
,'r'},
605 {"output-raw-big-endian",no_argument
,NULL
,'R'},
606 {"output-wav",no_argument
,NULL
,'w'},
607 {"output-aiff",no_argument
,NULL
,'f'},
608 {"output-aifc",no_argument
,NULL
,'a'},
609 {"batch",no_argument
,NULL
,'B'},
610 {"verbose",no_argument
,NULL
,'v'},
611 {"quiet",no_argument
,NULL
,'q'},
612 {"version",no_argument
,NULL
,'V'},
613 {"query",no_argument
,NULL
,'Q'},
614 {"help",no_argument
,NULL
,'h'},
615 {"cache-test",no_argument
,NULL
,'U'},
616 {"disable-paranoia",no_argument
,NULL
,'Z'},
617 {"disable-extra-paranoia",no_argument
,NULL
,'Y'},
618 {"abort-on-skip",no_argument
,NULL
,'X'},
619 {"disable-fragmentation",no_argument
,NULL
,'F'},
620 {"output-info",required_argument
,NULL
,'i'},
621 {"never-skip",optional_argument
,NULL
,'z'},
622 {"log-summary",required_argument
,NULL
,'l'},
627 long blocking_write(int outf
, char *buffer
, long num
){
631 temp
=write(outf
,buffer
+words
,num
-words
);
633 if(errno
!=EINTR
&& errno
!=EAGAIN
)
642 static cdrom_drive
*d
=NULL
;
643 static cdrom_paranoia
*p
=NULL
;
645 static void cleanup(void){
646 if(p
)paranoia_free(p
);
650 int main(int argc
,char *argv
[]){
654 int force_cdrom_endian
=-1;
655 int force_cdrom_sectors
=-1;
656 int force_cdrom_overlap
=-1;
657 char *force_cdrom_device
=NULL
;
658 char *force_generic_device
=NULL
;
659 char *force_cooked_device
=NULL
;
660 int force_cdrom_speed
=0;
663 int output_type
=1; /* 0=raw, 1=wav, 2=aifc */
664 int output_endian
=0; /* -1=host, 0=little, 1=big */
667 int run_cache_test
=0;
669 /* full paranoia, but allow skipping */
670 int paranoia_mode
=PARANOIA_MODE_FULL
^PARANOIA_MODE_NEVERSKIP
;
672 char *info_file
=NULL
;
676 int c
,long_option_index
;
680 while((c
=getopt_long(argc
,argv
,optstring
,options
,&long_option_index
))!=EOF
){
686 force_cdrom_endian
=0;
689 force_cdrom_endian
=1;
692 force_cdrom_sectors
=atoi(optarg
);
695 force_cdrom_overlap
=atoi(optarg
);
698 if(force_cdrom_device
)free(force_cdrom_device
);
699 force_cdrom_device
=copystring(optarg
);
702 if(force_cooked_device
){
703 report("-g option incompatable with -k\n");
706 force_cooked_device
=NULL
;
707 if(force_generic_device
)free(force_generic_device
);
708 force_generic_device
=copystring(optarg
);
711 if(force_generic_device
|| force_cdrom_device
){
712 report("-k option incompatable with -d and -g\n");
715 if(force_cooked_device
)free(force_cooked_device
);
716 force_cooked_device
=copystring(optarg
);
719 force_cdrom_speed
=atoi(optarg
);
746 verbose
=CDDA_MESSAGE_PRINTIT
;
753 verbose
=CDDA_MESSAGE_FORGETIT
;
758 fprintf(stderr
,"Sending all callbacks to stderr for wrapper script\n");
761 fprintf(stderr
,VERSION
);
762 fprintf(stderr
,"\n");
772 paranoia_mode
=PARANOIA_MODE_DISABLE
;
780 max_retries
= atoi (optarg
);
781 paranoia_mode
&=~PARANOIA_MODE_NEVERSKIP
;
783 paranoia_mode
|=PARANOIA_MODE_NEVERSKIP
;
787 paranoia_mode
|=PARANOIA_MODE_OVERLAP
; /* cdda2wav style overlap
789 paranoia_mode
&=~PARANOIA_MODE_VERIFY
;
792 /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/
796 paranoia_mode
&=~PARANOIA_MODE_REPAIR
;
799 paranoia_mode
&=~(PARANOIA_MODE_FRAGMENT
);
802 if(info_file
)free(info_file
);
803 info_file
=copystring(info_file
);
809 toc_offset
=atoi(optarg
);
812 if(logfile
&& logfile
!= stdout
)fclose(logfile
);
813 if(!strcmp(optarg
,"-"))
816 logfile
=fopen(optarg
,"w");
818 report("Cannot open log summary file %s: %s",(char*)optarg
,
826 sample_offset
=atoi(optarg
);
835 /* log command line and version */
837 for (i
= 0; i
< argc
; i
++)
838 fprintf(logfile
,"%s ",argv
[i
]);
839 fprintf(logfile
,"\n");
841 fprintf(logfile
,VERSION
);
842 fprintf(logfile
,"\n");
846 if(optind
>=argc
&& !query_only
){
850 /* D'oh. No span. Fetch me a brain, Igor. */
855 span
=copystring(argv
[optind
]);
859 /* Query the cdrom/disc; we may need to override some settings */
861 if(force_cooked_device
){
862 d
=cdda_identify_cooked(force_cooked_device
,verbose
,NULL
);
863 }else if(force_generic_device
)
864 d
=cdda_identify_scsi(force_generic_device
,force_cdrom_device
,verbose
,NULL
);
866 if(force_cdrom_device
)
867 d
=cdda_identify(force_cdrom_device
,verbose
,NULL
);
870 d
=cdda_find_a_cdrom(verbose
,NULL
);
872 /* does the /dev/cdrom link exist? */
874 if(lstat("/dev/cdrom",&s
)){
875 /* no link. Search anyway */
876 d
=cdda_find_a_cdrom(verbose
,NULL
);
878 d
=cdda_identify("/dev/cdrom",verbose
,NULL
);
879 if(d
==NULL
&& !verbose
){
881 report("\n/dev/cdrom exists but isn't accessible. By default,\n"
882 "cdparanoia stops searching for an accessible drive here.\n"
883 "Consider using -sv to force a more complete autosense\n"
884 "of the machine.\n\nMore information about /dev/cdrom:");
886 d
=cdda_identify("/dev/cdrom",CDDA_MESSAGE_PRINTIT
,NULL
);
896 report("\nUnable to open cdrom drive; -v will give more information.");
901 cdda_verbose_set(d
,CDDA_MESSAGE_PRINTIT
,CDDA_MESSAGE_PRINTIT
);
903 cdda_verbose_set(d
,CDDA_MESSAGE_PRINTIT
,CDDA_MESSAGE_FORGETIT
);
905 /* possibly force hand on endianness of drive, sector request size */
906 if(force_cdrom_endian
!=-1){
907 d
->bigendianp
=force_cdrom_endian
;
908 switch(force_cdrom_endian
){
910 report("Forcing CDROM sense to little-endian; ignoring preset and autosense");
913 report("Forcing CDROM sense to big-endian; ignoring preset and autosense");
917 if(force_cdrom_sectors
!=-1){
918 if(force_cdrom_sectors
<0 || force_cdrom_sectors
>100){
919 report("Default sector read size must be 1<= n <= 100\n");
926 sprintf(buffer
,"Forcing default to read %d sectors; "
927 "ignoring preset and autosense",force_cdrom_sectors
);
929 d
->nsectors
=force_cdrom_sectors
;
930 d
->bigbuff
=force_cdrom_sectors
*CD_FRAMESIZE_RAW
;
933 if(force_cdrom_overlap
!=-1){
934 if(force_cdrom_overlap
<0 || force_cdrom_overlap
>75){
935 report("Search overlap sectors must be 0<= n <=75\n");
942 sprintf(buffer
,"Forcing search overlap to %d sectors; "
943 "ignoring autosense",force_cdrom_overlap
);
948 switch(cdda_open(d
)){
949 case -2:case -3:case -4:case -5:
950 report("\nUnable to open disc. Is there an audio CD in the drive?");
953 report("\ncdparanoia could not find a way to read audio from this drive.");
958 report("\nUnable to open disc.");
962 if(force_cdrom_speed
!=0){
964 sprintf(buf
,"\nAttempting to set speed to %dx... ",force_cdrom_speed
);
966 if(cdda_speed_set(d
,force_cdrom_speed
)){
970 report("\tdrive returned OK.");
975 return analyze_timing_and_cache(d
);
978 if(query_only
|| verbose
)display_toc(d
);
979 if(query_only
)exit(0);
981 /* bias the disc. A hack. Of course. */
982 /* we may need to read before or past user area; this is never
983 default, and we do it because the [allegedly informed] user told
986 toc_offset
+=sample_offset
/588;
995 toc_offset
=-cdda_track_firstsector(d
,1);
997 for(i
=0;i
<d
->tracks
+1;i
++)
998 d
->disc_toc
[i
].dwStartSector
+=toc_offset
;
1002 report("WARNING: The autosensed/selected sectors per read value is\n"
1003 " one sector, making it very unlikely Paranoia can \n"
1005 " Attempting to continue...\n\n");
1008 /* parse the span, set up begin and end sectors */
1018 /* look for the hyphen */
1019 char *span2
=strchr(span
,'-');
1020 if(strrchr(span
,'-')!=span2
){
1021 report("Error parsing span argument");
1032 first_sector
=parse_offset(d
,span
,-1);
1033 if(first_sector
==-1)
1034 last_sector
=parse_offset(d
,span2
,cdda_disc_firstsector(d
));
1036 last_sector
=parse_offset(d
,span2
,first_sector
);
1038 if(first_sector
==-1){
1039 if(last_sector
==-1){
1040 report("Error parsing span argument");
1045 first_sector
=cdda_disc_firstsector(d
);
1048 if(last_sector
==-1){
1049 if(span2
){ /* There was a hyphen */
1050 last_sector
=cdda_disc_lastsector(d
);
1053 cdda_track_lastsector(d
,cdda_sector_gettrack(d
,first_sector
));
1058 first_sector
=cdda_disc_firstsector(d
);
1059 last_sector
=cdda_disc_lastsector(d
);
1064 int track1
=cdda_sector_gettrack(d
,first_sector
);
1065 int track2
=cdda_sector_gettrack(d
,last_sector
);
1066 long off1
=first_sector
-cdda_track_firstsector(d
,track1
);
1067 long off2
=last_sector
-cdda_track_firstsector(d
,track2
);
1070 for(i
=track1
;i
<=track2
;i
++)
1071 if(!cdda_track_audiop(d
,i
)){
1072 report("Selected span contains non audio tracks. Aborting.\n\n");
1076 sprintf(buffer
,"Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n"
1077 "\t to sector %7ld (track %2d [%d:%02d.%02d])\n",first_sector
,
1078 track1
,(int)(off1
/(60*75)),(int)((off1
/75)%60),(int)(off1
%75),
1080 track2
,(int)(off2
/(60*75)),(int)((off2
/75)%60),(int)(off2
%75));
1087 int16_t offset_buffer
[1176];
1088 int offset_buffer_used
=0;
1089 int offset_skip
=sample_offset
*4;
1092 paranoia_modeset(p
,paranoia_mode
);
1093 if(force_cdrom_overlap
!=-1)paranoia_overlapset(p
,force_cdrom_overlap
);
1096 cdda_verbose_set(d
,CDDA_MESSAGE_LOGIT
,CDDA_MESSAGE_LOGIT
);
1098 cdda_verbose_set(d
,CDDA_MESSAGE_FORGETIT
,CDDA_MESSAGE_FORGETIT
);
1100 paranoia_seek(p
,cursor
=first_sector
,SEEK_SET
);
1102 /* this is probably a good idea in general */
1106 /* we'll need to be able to read one sector past user data if we
1107 have a sample offset in order to pick up the last bytes. We
1108 need to set the disc length forward here so that the libs are
1109 willing to read past, assuming that works on the hardware, of
1112 d
->disc_toc
[d
->tracks
].dwStartSector
++;
1114 while(cursor
<=last_sector
){
1115 char outfile_name
[256];
1119 cdda_track_lastsector(d
,batch_track
=
1120 cdda_sector_gettrack(d
,cursor
));
1121 if(batch_last
>last_sector
)batch_last
=last_sector
;
1123 batch_first
=first_sector
;
1124 batch_last
=last_sector
;
1128 callbegin
=batch_first
;
1131 /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */
1134 if(!strcmp(argv
[optind
+1],"-")){
1135 out
=dup(fileno(stdout
));
1136 if(batch
)report("Are you sure you wanted 'batch' "
1137 "(-B) output with stdout?");
1138 report("outputting to stdout\n");
1140 fprintf(logfile
,"outputting to stdout\n");
1143 outfile_name
[0]='\0';
1147 char *post
=strrchr(argv
[optind
+1],'/');
1148 int pos
=(post
?post
-argv
[optind
+1]+1:0);
1149 char *file
=argv
[optind
+1]+pos
;
1154 strncat(path
,argv
[optind
+1],pos
>256?256:pos
);
1157 snprintf(outfile_name
,246,"%strack%02d.%s",path
,batch_track
,file
);
1159 snprintf(outfile_name
,246,"%s%s",path
,file
);
1162 switch(output_type
){
1164 strcat(outfile_name
,"cdda.raw");
1167 strcat(outfile_name
,"cdda.wav");
1170 strcat(outfile_name
,"cdda.aifc");
1173 strcat(outfile_name
,"cdda.aiff");
1178 out
=open(outfile_name
,O_RDWR
|O_CREAT
|O_TRUNC
,0666);
1180 report("Cannot open specified output file %s: %s",outfile_name
,
1186 report("outputting to %s\n",outfile_name
);
1188 fprintf(logfile
,"outputting to %s\n",outfile_name
);
1195 sprintf(outfile_name
,"track%02d.",batch_track
);
1197 outfile_name
[0]='\0';
1199 switch(output_type
){
1201 strcat(outfile_name
,"cdda.raw");
1204 strcat(outfile_name
,"cdda.wav");
1207 strcat(outfile_name
,"cdda.aifc");
1210 strcat(outfile_name
,"cdda.aiff");
1214 out
=open(outfile_name
,O_RDWR
|O_CREAT
|O_TRUNC
,0666);
1216 report("Cannot open default output file %s: %s",outfile_name
,
1222 report("outputting to %s\n",outfile_name
);
1224 fprintf(logfile
,"outputting to %s\n",outfile_name
);
1229 switch(output_type
){
1233 WriteWav(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1236 WriteAifc(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1239 WriteAiff(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1245 if(offset_buffer_used
){
1246 /* partial sector from previous batch read */
1248 if(buffering_write(out
,
1249 ((char *)offset_buffer
)+offset_buffer_used
,
1250 CD_FRAMESIZE_RAW
-offset_buffer_used
)){
1251 report("Error writing output: %s",strerror(errno
));
1257 while(cursor
<=batch_last
){
1259 int16_t *readbuf
=paranoia_read_limited(p
,callback
,max_retries
);
1260 char *err
=cdda_errors(d
);
1261 char *mes
=cdda_messages(d
);
1264 fprintf(stderr
,"\r "
1266 mes
?mes
:"",err
?err
:"");
1271 if(errno
==EBADF
|| errno
==ENOMEDIUM
){
1272 report("\nparanoia_read: CDROM drive unavailable, bailing.\n");
1276 report("\nparanoia_read: Unrecoverable error, bailing.\n");
1279 if(skipped_flag
&& abort_on_skip
){
1280 cursor
=batch_last
+1;
1287 if(output_endian
!=bigendianp()){
1289 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)readbuf
[i
]=swap16(readbuf
[i
]);
1292 callback(cursor
*(CD_FRAMEWORDS
)-1,-2);
1294 if(buffering_write(out
,((char *)readbuf
)+offset_skip
,
1295 CD_FRAMESIZE_RAW
-offset_skip
)){
1296 report("Error writing output: %s",strerror(errno
));
1301 if(output_endian
!=bigendianp()){
1303 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)readbuf
[i
]=swap16(readbuf
[i
]);
1306 /* One last bit of silliness to deal with sample offsets */
1307 if(sample_offset
&& cursor
>batch_last
){
1309 /* read a sector and output the partial offset. Save the
1310 rest for the next batch iteration */
1311 readbuf
=paranoia_read_limited(p
,callback
,max_retries
);
1312 err
=cdda_errors(d
);mes
=cdda_messages(d
);
1315 fprintf(stderr
,"\r "
1317 mes
?mes
:"",err
?err
:"");
1319 if(err
)free(err
);if(mes
)free(mes
);
1322 report("\nparanoia_read: Unrecoverable error reading through "
1323 "sample_offset shift\n\tat end of track, bailing.\n");
1326 if(skipped_flag
&& abort_on_skip
)break;
1328 /* do not move the cursor */
1330 if(output_endian
!=bigendianp())
1331 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)
1332 offset_buffer
[i
]=swap16(readbuf
[i
]);
1334 memcpy(offset_buffer
,readbuf
,CD_FRAMESIZE_RAW
);
1335 offset_buffer_used
=sample_offset
*4;
1337 callback(cursor
*(CD_FRAMEWORDS
),-2);
1339 if(buffering_write(out
,(char *)offset_buffer
,
1340 offset_buffer_used
)){
1341 report("Error writing output: %s",strerror(errno
));
1346 callback(cursor
*(CD_FRAMESIZE_RAW
/2)-1,-1);
1347 buffering_close(out
);
1349 /* remove the file */
1350 report("\nRemoving aborted file: %s",outfile_name
);
1351 unlink(outfile_name
);
1352 /* make the cursor correct if we have another track */
1353 if(batch_track
!=-1){
1355 cursor
=cdda_track_firstsector(d
,batch_track
);
1356 paranoia_seek(p
,cursor
,SEEK_SET
);
1357 offset_skip
=sample_offset
*4;
1358 offset_buffer_used
=0;
1369 report("Done.\n\n");
1373 if(logfile
&& logfile
!= stdout
)