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) 2006 Monty <monty@xiph.org>
34 #include "interface/cdda_interface.h"
35 #include "paranoia/cdda_paranoia.h"
44 static long parse_offset(cdrom_drive
*d
, char *offset
, int begin
){
50 char *time
=NULL
,*temp
=NULL
;
53 if(offset
==NULL
)return(-1);
55 /* seperate track from time offset */
56 temp
=strchr(offset
,']');
59 temp
=strchr(offset
,'[');
61 report("Error parsing span argument");
70 int chars
=strspn(offset
,"0123456789");
74 if(track
<0 || track
>d
->tracks
){ /*take track 0 as pre-gap of 1st track*/
76 sprintf(buffer
,"Track #%ld does not exist.",track
);
85 char *sec
=strrchr(time
,'.');
86 if(!sec
)sec
=strrchr(time
,':');
89 chars
=strspn(sec
+1,"0123456789");
98 report("Error parsing span argument");
113 report("Error parsing span argument");
124 if(seconds
==-1 && sectors
==-1)return(-1);
126 ret
=cdda_disc_firstsector(d
);
130 if(seconds
==-1 && sectors
==-1){
131 if(begin
==-1){ /* first half of a span */
132 return(cdda_track_firstsector(d
,track
));
134 return(cdda_track_lastsector(d
,track
));
137 /* relative offset into a track */
138 ret
=cdda_track_firstsector(d
,track
);
142 /* OK, we had some sort of offset into a track */
144 if(sectors
!=-1)ret
+=sectors
;
145 if(seconds
!=-1)ret
+=seconds
*75;
146 if(minutes
!=-1)ret
+=minutes
*60*75;
147 if(hours
!=-1)ret
+=hours
*60*60*75;
149 /* We don't want to outside of the track; if it's relative, that's OK... */
151 if(cdda_sector_gettrack(d
,ret
)!=track
){
152 report("Time/sector offset goes beyond end of specified track.");
157 /* Don't pass up end of session */
159 if(ret
>cdda_disc_lastsector(d
)){
160 report("Time/sector offset goes beyond end of disc.");
169 static void display_toc(cdrom_drive
*d
){
172 report("\nTable of contents (audio tracks only):\n"
173 "track length begin copy pre ch\n"
174 "===========================================================");
176 for(i
=1;i
<=d
->tracks
;i
++)
177 if(cdda_track_audiop(d
,i
)){
180 long sec
=cdda_track_firstsector(d
,i
);
181 long off
=cdda_track_lastsector(d
,i
)-sec
+1;
184 "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d] %s %s %s",
186 off
,(int)(off
/(60*75)),(int)((off
/75)%60),(int)(off
%75),
187 sec
,(int)(sec
/(60*75)),(int)((sec
/75)%60),(int)(sec
%75),
188 cdda_track_copyp(d
,i
)?" OK":" no",
189 cdda_track_preemp(d
,i
)?" yes":" no",
190 cdda_track_channels(d
,i
)==2?" 2":" 4");
196 sprintf(buffer
, "TOTAL %7ld [%02d:%02d.%02d] (audio only)",
197 audiolen
,(int)(audiolen
/(60*75)),(int)((audiolen
/75)%60),
204 static void usage(FILE *f
){
209 "(C) 2006 Monty <monty@xiph.org> and Xiph.Org\n\n" \
210 "Report bugs to paranoia@xiph.org\n"\
211 "http://www.xiph.org/paranoia/\n"
214 " cdparanoia [options] <span> [outfile]\n\n"
217 " -v --verbose : extra verbose operation\n"
218 " -q --quiet : quiet operation\n"
219 " -e --stderr-progress : force output of progress information to\n"
220 " stderr (for wrapper scripts)\n"
221 " -l --log-summary <file> : save result summary to file\n"
222 " -V --version : print version info and quit\n"
223 " -Q --query : autosense drive, query disc and quit\n"
224 " -B --batch : 'batch' mode (saves each track to a\n"
226 " -s --search-for-drive : do an exhaustive search for drive\n"
227 " -h --help : print help\n\n"
229 " -p --output-raw : output raw 16 bit PCM in host byte \n"
231 " -r --output-raw-little-endian : output raw 16 bit little-endian PCM\n"
232 " -R --output-raw-big-endian : output raw 16 bit big-endian PCM\n"
233 " -w --output-wav : output as WAV file (default)\n"
234 " -f --output-aiff : output as AIFF file\n"
235 " -a --output-aifc : output as AIFF-C file\n\n"
237 " -c --force-cdrom-little-endian : force treating drive as little endian\n"
238 " -C --force-cdrom-big-endian : force treating drive as big endian\n"
239 " -n --force-default-sectors <n> : force default number of sectors in read\n"
241 " -o --force-search-overlap <n> : force minimum overlap search during\n"
242 " verification to n sectors\n"
243 " -d --force-cdrom-device <dev> : use specified device; disallow \n"
245 " -g --force-generic-device <dev> : use specified generic scsi device\n"
246 " -S --force-read-speed <n> : read from device at specified speed\n"
247 " -t --toc-offset <n> : Add <n> sectors to the values reported\n"
248 " when addressing tracks. May be negative\n"
249 " -T --toc-bias : Assume that the beginning offset of \n"
250 " track 1 as reported in the TOC will be\n"
251 " addressed as LBA 0. Necessary for some\n"
252 " Toshiba drives to get track boundaries\n"
254 " -O --sample-offset <n> : Add <n> samples to the offset when\n"
255 " reading data. May be negative.\n"
256 " -z --never-skip[=n] : never accept any less than perfect\n"
257 " data reconstruction (don't allow 'V's)\n"
258 " but if [n] is given, skip after [n]\n"
259 " retries without progress.\n"
260 " -Z --disable-paranoia : disable all paranoia checking\n"
261 " -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n"
262 " -X --abort-on-skip : abort on imperfect reads/skips\n\n"
265 " :-) Normal operation, low/no jitter\n"
266 " :-| Normal operation, considerable jitter\n"
268 " :-P Unreported loss of streaming in atomic read operation\n"
269 " 8-| Finding read problems at same point during reread; hard to correct\n"
270 " :-0 SCSI/ATAPI transport error\n"
271 " :-( Scratch detected\n"
272 " ;-( Gave up trying to perform a correction\n"
273 " 8-X Aborted (as per -X) due to a scratch/skip\n"
274 " :^D Finished extracting\n\n"
276 "PROGRESS BAR SYMBOLS:\n"
277 "<space> No corrections needed\n"
278 " - Jitter correction required\n"
279 " + Unreported loss of streaming/other error in read\n"
280 " ! Errors are getting through stage 1 but corrected in stage2\n"
281 " e SCSI/ATAPI transport error (corrected)\n"
282 " V Uncorrected error/skip\n\n"
285 "The span argument may be a simple track number or a offset/span\n"
286 "specification. The syntax of an offset/span takes the rough form:\n\n"
288 " 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] \n\n"
290 "Here, 1 and 2 are track numbers; the numbers in brackets provide a\n"
291 "finer grained offset within a particular track. [aa:bb:cc.dd] is in\n"
292 "hours/minutes/seconds/sectors format. Zero fields need not be\n"
293 "specified: [::20], [:20], [20], [20.], etc, would be interpreted as\n"
294 "twenty seconds, [10:] would be ten minutes, [.30] would be thirty\n"
295 "sectors (75 sectors per second).\n\n"
297 "When only a single offset is supplied, it is interpreted as a starting\n"
298 "offset and ripping will continue to the end of he track. If a single\n"
299 "offset is preceeded or followed by a hyphen, the implicit missing\n"
300 "offset is taken to be the start or end of the disc, respectively. Thus:\n\n"
302 " 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to \n"
303 " the end of track 1.\n\n"
305 " 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc\n\n"
307 " -2 Specifies ripping from the beginning of the disc up to\n"
308 " (and including) track 2\n\n"
310 " -2:[30.35] Specifies ripping from the beginning of the disc up to\n"
313 " 2-4 Specifies ripping from the beginning of track two to the\n"
314 " end of track 4.\n\n"
316 "Don't forget to protect square brackets and preceeding hyphens from\n"
318 "A few examples, protected from the shell:\n"
319 " A) query only with exhaustive search for a drive and full reporting\n"
321 " cdparanoia -vsQ\n\n"
322 " B) extract up to and including track 3, putting each track in a seperate\n"
324 " cdparanoia -B -- \"-3\"\n\n"
325 " C) extract from track 1, time 0:30.12 to 1:10.00:\n"
326 " cdparanoia \"1[:30.12]-1[1:10]\"\n\n"
328 "Submit bug reports to paranoia@xiph.org\n\n");
335 static char *callback_strings
[15]={"wrote",
351 static int skipped_flag
=0;
352 static int abort_on_skip
=0;
353 FILE *logfile
= NULL
;
354 static void callback(long inpos
, int function
){
357 (== PROGRESS == [--+!---x--------------> | 007218 01 ] == :-) . ==)
363 static long c_sector
=0,v_sector
=0;
364 static char dispcache
[]=" ";
366 static long lasttime
=0;
367 long sector
,osector
=0;
368 struct timeval thistime
;
369 static char heartbeat
=' ';
370 int position
=0,aheadposition
=0;
371 static int overlap
=0;
372 static int printit
=-1;
376 static int stimeout
=0;
377 char *smilie
="= :-)";
380 fprintf(stderr
,"##: %d [%s] @ %ld\n",
381 function
,(function
>=-2&&function
<=13?callback_strings
[function
+2]:
387 sector
=inpos
/CD_FRAMEWORDS
;
390 if(isatty(STDERR_FILENO
)){
397 if(printit
==1){ /* else don't bother; it's probably being
399 position
=((float)(sector
-callbegin
)/
400 (callend
-callbegin
))*graph
;
402 aheadposition
=((float)(c_sector
-callbegin
)/
403 (callend
-callbegin
))*graph
;
415 if(position
<graph
&& position
>=0)
417 case PARANOIA_CB_VERIFY
:
419 if(overlap
>CD_FRAMEWORDS
)
425 case PARANOIA_CB_READ
:
426 if(sector
>c_sector
)c_sector
=sector
;
429 case PARANOIA_CB_FIXUP_EDGE
:
431 if(overlap
>CD_FRAMEWORDS
)
436 if(dispcache
[position
]==' ')
437 dispcache
[position
]='-';
439 case PARANOIA_CB_FIXUP_ATOM
:
440 if(slevel
<3 || stimeout
>5)slevel
=3;
441 if(dispcache
[position
]==' ' ||
442 dispcache
[position
]=='-')
443 dispcache
[position
]='+';
445 case PARANOIA_CB_READERR
:
447 if(dispcache
[position
]!='V')
448 dispcache
[position
]='e';
450 case PARANOIA_CB_SKIP
:
452 dispcache
[position
]='V';
454 case PARANOIA_CB_OVERLAP
:
457 case PARANOIA_CB_SCRATCH
:
460 case PARANOIA_CB_DRIFT
:
461 if(slevel
<4 || stimeout
>5)slevel
=4;
463 case PARANOIA_CB_FIXUP_DROPPED
:
464 case PARANOIA_CB_FIXUP_DUPED
:
466 if(dispcache
[position
]==' ' ||
467 dispcache
[position
]=='-' ||
468 dispcache
[position
]=='+')
469 dispcache
[position
]='!';
474 case 0: /* finished, or no jitter */
480 case 1: /* normal. no atom, low jitter */
483 case 2: /* normal, overlap > 1 */
489 case 3: /* unreported loss of streaming */
492 case 5: /* dropped/duped bytes */
495 case 6: /* scsi error */
498 case 7: /* scratch */
508 gettimeofday(&thistime
,NULL
);
509 test
=thistime
.tv_sec
*10+thistime
.tv_usec
/100000;
511 if(lasttime
!=test
|| function
==-1 || slast
!=slevel
){
512 if(lasttime
!=test
|| function
==-1){
543 if(abort_on_skip
&& skipped_flag
&& function
!=-1){
545 "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ",
546 " ...aborting; please wait... ",
547 v_sector
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
551 "\r (== PROGRESS == [%s| ...... %02d ] ==%s %c ==) ",
552 dispcache
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
556 "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ",
557 dispcache
,v_sector
,overlap
/CD_FRAMEWORDS
,smilie
,heartbeat
);
559 if(aheadposition
>=0 && aheadposition
<graph
&& !(function
==-1))
560 buffer
[aheadposition
+19]='>';
563 fprintf(stderr
,buffer
);
565 if (logfile
!= NULL
&& function
==-1) {
566 fprintf(logfile
,buffer
+1);
567 fprintf(logfile
,"\n\n");
574 /* clear the indicator for next batch */
576 memset(dispcache
,' ',graph
);
579 const char *optstring
= "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:l:";
581 struct option options
[] = {
582 {"stderr-progress",no_argument
,NULL
,'e'},
583 {"search-for-drive",no_argument
,NULL
,'s'},
584 {"force-cdrom-little-endian",no_argument
,NULL
,'c'},
585 {"force-cdrom-big-endian",no_argument
,NULL
,'C'},
586 {"force-default-sectors",required_argument
,NULL
,'n'},
587 {"force-search-overlap",required_argument
,NULL
,'o'},
588 {"force-cdrom-device",required_argument
,NULL
,'d'},
589 {"force-generic-device",required_argument
,NULL
,'g'},
590 {"force-read-speed",required_argument
,NULL
,'S'},
591 {"sample-offset",required_argument
,NULL
,'O'},
592 {"toc-offset",required_argument
,NULL
,'t'},
593 {"toc-bias",no_argument
,NULL
,'T'},
594 {"output-raw",no_argument
,NULL
,'p'},
595 {"output-raw-little-endian",no_argument
,NULL
,'r'},
596 {"output-raw-big-endian",no_argument
,NULL
,'R'},
597 {"output-wav",no_argument
,NULL
,'w'},
598 {"output-aiff",no_argument
,NULL
,'f'},
599 {"output-aifc",no_argument
,NULL
,'a'},
600 {"batch",no_argument
,NULL
,'B'},
601 {"verbose",no_argument
,NULL
,'v'},
602 {"quiet",no_argument
,NULL
,'q'},
603 {"version",no_argument
,NULL
,'V'},
604 {"query",no_argument
,NULL
,'Q'},
605 {"help",no_argument
,NULL
,'h'},
606 {"disable-paranoia",no_argument
,NULL
,'Z'},
607 {"disable-extra-paranoia",no_argument
,NULL
,'Y'},
608 {"abort-on-skip",no_argument
,NULL
,'X'},
609 {"disable-fragmentation",no_argument
,NULL
,'F'},
610 {"output-info",required_argument
,NULL
,'i'},
611 {"never-skip",optional_argument
,NULL
,'z'},
612 {"log-summary",required_argument
,NULL
,'l'},
617 long blocking_write(int outf
, char *buffer
, long num
){
621 temp
=write(outf
,buffer
+words
,num
-words
);
623 if(errno
!=EINTR
&& errno
!=EAGAIN
)
632 static cdrom_drive
*d
=NULL
;
633 static cdrom_paranoia
*p
=NULL
;
635 static void cleanup(void){
636 if(p
)paranoia_free(p
);
640 int main(int argc
,char *argv
[]){
644 int force_cdrom_endian
=-1;
645 int force_cdrom_sectors
=-1;
646 int force_cdrom_overlap
=-1;
647 char *force_cdrom_device
=NULL
;
648 char *force_generic_device
=NULL
;
649 int force_cdrom_speed
=-1;
652 int output_type
=1; /* 0=raw, 1=wav, 2=aifc */
653 int output_endian
=0; /* -1=host, 0=little, 1=big */
657 /* full paranoia, but allow skipping */
658 int paranoia_mode
=PARANOIA_MODE_FULL
^PARANOIA_MODE_NEVERSKIP
;
660 char *info_file
=NULL
;
664 int c
,long_option_index
;
668 while((c
=getopt_long(argc
,argv
,optstring
,options
,&long_option_index
))!=EOF
){
674 force_cdrom_endian
=0;
677 force_cdrom_endian
=1;
680 force_cdrom_sectors
=atoi(optarg
);
683 force_cdrom_overlap
=atoi(optarg
);
686 if(force_cdrom_device
)free(force_cdrom_device
);
687 force_cdrom_device
=copystring(optarg
);
690 if(force_generic_device
)free(force_generic_device
);
691 force_generic_device
=copystring(optarg
);
694 force_cdrom_speed
=atoi(optarg
);
721 verbose
=CDDA_MESSAGE_PRINTIT
;
728 verbose
=CDDA_MESSAGE_FORGETIT
;
733 fprintf(stderr
,"Sending all callcaks to stderr for wrapper script\n");
736 fprintf(stderr
,VERSION
);
737 fprintf(stderr
,"\n");
747 paranoia_mode
=PARANOIA_MODE_DISABLE
;
751 max_retries
= atoi (optarg
);
752 paranoia_mode
&=~PARANOIA_MODE_NEVERSKIP
;
754 paranoia_mode
|=PARANOIA_MODE_NEVERSKIP
;
758 paranoia_mode
|=PARANOIA_MODE_OVERLAP
; /* cdda2wav style overlap
760 paranoia_mode
&=~PARANOIA_MODE_VERIFY
;
763 /*paranoia_mode&=~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);*/
767 paranoia_mode
&=~PARANOIA_MODE_REPAIR
;
770 paranoia_mode
&=~(PARANOIA_MODE_FRAGMENT
);
773 if(info_file
)free(info_file
);
774 info_file
=copystring(info_file
);
780 toc_offset
=atoi(optarg
);
783 if(logfile
&& logfile
!= stdout
)fclose(logfile
);
784 if(!strcmp(optarg
,"-"))
787 logfile
=fopen(optarg
,"w");
789 report3("Cannot open log summary file %s: %s",(char*)optarg
,
797 sample_offset
=atoi(optarg
);
806 /* log command line and version */
808 for (i
= 0; i
< argc
; i
++)
809 fprintf(logfile
,"%s ",argv
[i
]);
810 fprintf(logfile
,"\n",argv
[i
]);
812 fprintf(logfile
,VERSION
);
813 fprintf(logfile
,"\n");
817 if(optind
>=argc
&& !query_only
){
821 /* D'oh. No span. Fetch me a brain, Igor. */
826 span
=copystring(argv
[optind
]);
830 /* Query the cdrom/disc; we may need to override some settings */
832 if(force_generic_device
)
833 d
=cdda_identify_scsi(force_generic_device
,force_cdrom_device
,verbose
,NULL
);
835 if(force_cdrom_device
)
836 d
=cdda_identify(force_cdrom_device
,verbose
,NULL
);
839 d
=cdda_find_a_cdrom(verbose
,NULL
);
841 /* does the /dev/cdrom link exist? */
843 if(lstat("/dev/cdrom",&s
)){
844 /* no link. Search anyway */
845 d
=cdda_find_a_cdrom(verbose
,NULL
);
847 d
=cdda_identify("/dev/cdrom",verbose
,NULL
);
848 if(d
==NULL
&& !verbose
){
850 report("\n/dev/cdrom exists but isn't accessible. By default,\n"
851 "cdparanoia stops searching for an accessible drive here.\n"
852 "Consider using -sv to force a more complete autosense\n"
853 "of the machine.\n\nMore information about /dev/cdrom:");
855 d
=cdda_identify("/dev/cdrom",CDDA_MESSAGE_PRINTIT
,NULL
);
865 report("\nUnable to open cdrom drive; -v will give more information.");
870 cdda_verbose_set(d
,CDDA_MESSAGE_PRINTIT
,CDDA_MESSAGE_PRINTIT
);
872 cdda_verbose_set(d
,CDDA_MESSAGE_PRINTIT
,CDDA_MESSAGE_FORGETIT
);
874 /* possibly force hand on endianness of drive, sector request size */
875 if(force_cdrom_endian
!=-1){
876 d
->bigendianp
=force_cdrom_endian
;
877 switch(force_cdrom_endian
){
879 report("Forcing CDROM sense to little-endian; ignoring preset and autosense");
882 report("Forcing CDROM sense to big-endian; ignoring preset and autosense");
886 if(force_cdrom_sectors
!=-1){
887 if(force_cdrom_sectors
<0 || force_cdrom_sectors
>100){
888 report("Default sector read size must be 1<= n <= 100\n");
895 sprintf(buffer
,"Forcing default to read %d sectors; "
896 "ignoring preset and autosense",force_cdrom_sectors
);
898 d
->nsectors
=force_cdrom_sectors
;
899 d
->bigbuff
=force_cdrom_sectors
*CD_FRAMESIZE_RAW
;
902 if(force_cdrom_overlap
!=-1){
903 if(force_cdrom_overlap
<0 || force_cdrom_overlap
>75){
904 report("Search overlap sectors must be 0<= n <=75\n");
911 sprintf(buffer
,"Forcing search overlap to %d sectors; "
912 "ignoring autosense",force_cdrom_overlap
);
917 switch(cdda_open(d
)){
918 case -2:case -3:case -4:case -5:
919 report("\nUnable to open disc. Is there an audio CD in the drive?");
922 report("\ncdparanoia could not find a way to read audio from this drive.");
927 report("\nUnable to open disc.");
932 if(query_only
|| verbose
)display_toc(d
);
933 if(query_only
)exit(0);
935 /* bias the disc. A hack. Of course. */
936 /* we may need to read before or past user area; this is never
937 default, and we do it because the [allegedly informed] user told
940 toc_offset
+=sample_offset
/588;
949 toc_offset
=-cdda_track_firstsector(d
,1);
951 for(i
=0;i
<d
->tracks
+1;i
++)
952 d
->disc_toc
[i
].dwStartSector
+=toc_offset
;
955 if(force_cdrom_speed
!=-1){
956 cdda_speed_set(d
,force_cdrom_speed
);
960 report("WARNING: The autosensed/selected sectors per read value is\n"
961 " one sector, making it very unlikely Paranoia can \n"
963 " Attempting to continue...\n\n");
966 /* parse the span, set up begin and end sectors */
976 /* look for the hyphen */
977 char *span2
=strchr(span
,'-');
978 if(strrchr(span
,'-')!=span2
){
979 report("Error parsing span argument");
990 first_sector
=parse_offset(d
,span
,-1);
992 last_sector
=parse_offset(d
,span2
,cdda_disc_firstsector(d
));
994 last_sector
=parse_offset(d
,span2
,first_sector
);
996 if(first_sector
==-1){
998 report("Error parsing span argument");
1003 first_sector
=cdda_disc_firstsector(d
);
1006 if(last_sector
==-1){
1007 if(span2
){ /* There was a hyphen */
1008 last_sector
=cdda_disc_lastsector(d
);
1011 cdda_track_lastsector(d
,cdda_sector_gettrack(d
,first_sector
));
1016 first_sector
=cdda_disc_firstsector(d
);
1017 last_sector
=cdda_disc_lastsector(d
);
1022 int track1
=cdda_sector_gettrack(d
,first_sector
);
1023 int track2
=cdda_sector_gettrack(d
,last_sector
);
1024 long off1
=first_sector
-cdda_track_firstsector(d
,track1
);
1025 long off2
=last_sector
-cdda_track_firstsector(d
,track2
);
1028 for(i
=track1
;i
<=track2
;i
++)
1029 if(!cdda_track_audiop(d
,i
)){
1030 report("Selected span contains non audio tracks. Aborting.\n\n");
1034 sprintf(buffer
,"Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n"
1035 "\t to sector %7ld (track %2d [%d:%02d.%02d])\n",first_sector
,
1036 track1
,(int)(off1
/(60*75)),(int)((off1
/75)%60),(int)(off1
%75),
1038 track2
,(int)(off2
/(60*75)),(int)((off2
/75)%60),(int)(off2
%75));
1045 int16_t offset_buffer
[1176];
1046 int offset_buffer_used
=0;
1047 int offset_skip
=sample_offset
*4;
1050 paranoia_modeset(p
,paranoia_mode
);
1051 if(force_cdrom_overlap
!=-1)paranoia_overlapset(p
,force_cdrom_overlap
);
1054 cdda_verbose_set(d
,CDDA_MESSAGE_LOGIT
,CDDA_MESSAGE_LOGIT
);
1056 cdda_verbose_set(d
,CDDA_MESSAGE_FORGETIT
,CDDA_MESSAGE_FORGETIT
);
1058 paranoia_seek(p
,cursor
=first_sector
,SEEK_SET
);
1060 /* this is probably a good idea in general */
1064 /* we'll need to be able to read one sector past user data if we
1065 have a sample offset in order to pick up the last bytes. We
1066 need to set the disc length forward here so that the libs are
1067 willing to read past, assuming that works on the hardware, of
1070 d
->disc_toc
[d
->tracks
].dwStartSector
++;
1072 while(cursor
<=last_sector
){
1073 char outfile_name
[256];
1077 cdda_track_lastsector(d
,batch_track
=
1078 cdda_sector_gettrack(d
,cursor
));
1079 if(batch_last
>last_sector
)batch_last
=last_sector
;
1081 batch_first
=first_sector
;
1082 batch_last
=last_sector
;
1086 callbegin
=batch_first
;
1089 /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */
1092 if(!strcmp(argv
[optind
+1],"-")){
1093 out
=dup(fileno(stdout
));
1094 if(batch
)report("Are you sure you wanted 'batch' "
1095 "(-B) output with stdout?");
1096 report("outputting to stdout\n");
1098 fprintf(logfile
,"outputting to stdout\n");
1101 outfile_name
[0]='\0';
1105 char *post
=strrchr(argv
[optind
+1],'/');
1106 int pos
=(post
?post
-argv
[optind
+1]+1:0);
1107 char *file
=argv
[optind
+1]+pos
;
1112 strncat(path
,argv
[optind
+1],pos
>256?256:pos
);
1115 snprintf(outfile_name
,246,"%strack%02d.%s",path
,batch_track
,file
);
1117 snprintf(outfile_name
,246,"%s%s",path
,file
);
1120 switch(output_type
){
1122 strcat(outfile_name
,"cdda.raw");
1125 strcat(outfile_name
,"cdda.wav");
1128 strcat(outfile_name
,"cdda.aifc");
1131 strcat(outfile_name
,"cdda.aiff");
1136 out
=open(outfile_name
,O_RDWR
|O_CREAT
|O_TRUNC
,0666);
1138 report3("Cannot open specified output file %s: %s",outfile_name
,
1144 report2("outputting to %s\n",outfile_name
);
1146 fprintf(logfile
,"outputting to %s\n",outfile_name
);
1153 sprintf(outfile_name
,"track%02d.",batch_track
);
1155 outfile_name
[0]='\0';
1157 switch(output_type
){
1159 strcat(outfile_name
,"cdda.raw");
1162 strcat(outfile_name
,"cdda.wav");
1165 strcat(outfile_name
,"cdda.aifc");
1168 strcat(outfile_name
,"cdda.aiff");
1172 out
=open(outfile_name
,O_RDWR
|O_CREAT
|O_TRUNC
,0666);
1174 report3("Cannot open default output file %s: %s",outfile_name
,
1180 report2("outputting to %s\n",outfile_name
);
1182 fprintf(logfile
,"outputting to %s\n",outfile_name
);
1187 switch(output_type
){
1191 WriteWav(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1194 WriteAifc(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1197 WriteAiff(out
,(batch_last
-batch_first
+1)*CD_FRAMESIZE_RAW
);
1203 if(offset_buffer_used
){
1204 /* partial sector from previous batch read */
1206 if(buffering_write(out
,
1207 ((char *)offset_buffer
)+offset_buffer_used
,
1208 CD_FRAMESIZE_RAW
-offset_buffer_used
)){
1209 report2("Error writing output: %s",strerror(errno
));
1215 while(cursor
<=batch_last
){
1217 int16_t *readbuf
=paranoia_read_limited(p
,callback
,max_retries
);
1218 char *err
=cdda_errors(d
);
1219 char *mes
=cdda_messages(d
);
1222 fprintf(stderr
,"\r "
1224 mes
?mes
:"",err
?err
:"");
1230 report("\nparanoia_read: Unrecoverable error, bailing.\n");
1233 if(skipped_flag
&& abort_on_skip
){
1234 cursor
=batch_last
+1;
1241 if(output_endian
!=bigendianp()){
1243 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)readbuf
[i
]=swap16(readbuf
[i
]);
1246 callback(cursor
*(CD_FRAMEWORDS
)-1,-2);
1248 if(buffering_write(out
,((char *)readbuf
)+offset_skip
,
1249 CD_FRAMESIZE_RAW
-offset_skip
)){
1250 report2("Error writing output: %s",strerror(errno
));
1255 if(output_endian
!=bigendianp()){
1257 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)readbuf
[i
]=swap16(readbuf
[i
]);
1260 /* One last bit of silliness to deal with sample offsets */
1261 if(sample_offset
&& cursor
>batch_last
){
1263 /* read a sector and output the partial offset. Save the
1264 rest for the next batch iteration */
1265 readbuf
=paranoia_read_limited(p
,callback
,max_retries
);
1266 err
=cdda_errors(d
);mes
=cdda_messages(d
);
1269 fprintf(stderr
,"\r "
1271 mes
?mes
:"",err
?err
:"");
1273 if(err
)free(err
);if(mes
)free(mes
);
1276 report("\nparanoia_read: Unrecoverable error reading through "
1277 "sample_offset shift\n\tat end of track, bailing.\n");
1280 if(skipped_flag
&& abort_on_skip
)break;
1282 /* do not move the cursor */
1284 if(output_endian
!=bigendianp())
1285 for(i
=0;i
<CD_FRAMESIZE_RAW
/2;i
++)
1286 offset_buffer
[i
]=swap16(readbuf
[i
]);
1288 memcpy(offset_buffer
,readbuf
,CD_FRAMESIZE_RAW
);
1289 offset_buffer_used
=sample_offset
*4;
1291 callback(cursor
*(CD_FRAMEWORDS
),-2);
1293 if(buffering_write(out
,(char *)offset_buffer
,
1294 offset_buffer_used
)){
1295 report2("Error writing output: %s",strerror(errno
));
1300 callback(cursor
*(CD_FRAMESIZE_RAW
/2)-1,-1);
1301 buffering_close(out
);
1303 /* remove the file */
1304 report2("\nRemoving aborted file: %s",outfile_name
);
1305 unlink(outfile_name
);
1306 /* make the cursor correct if we have another track */
1307 if(batch_track
!=-1){
1309 cursor
=cdda_track_firstsector(d
,batch_track
);
1310 paranoia_seek(p
,cursor
,SEEK_SET
);
1311 offset_skip
=sample_offset
*4;
1312 offset_buffer_used
=0;
1323 report("Done.\n\n");
1327 if(logfile
&& logfile
!= stdout
)