/[debburn]/nonameyet/trunk/cdda2wav/cdda2wav.c
ViewVC logotype

Contents of /nonameyet/trunk/cdda2wav/cdda2wav.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 171 - (show annotations) (download)
Sat Sep 2 21:05:33 2006 UTC (6 years, 8 months ago) by blade
File MIME type: text/plain
File size: 85031 byte(s)
Added a modified-version message to cdda2wav version output
1 /* @(#)cdda2wav.c 1.64 06/02/19 Copyright 1998-2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */
2 #ifndef lint
3 static char sccsid[] =
4 "@(#)cdda2wav.c 1.64 06/02/19 Copyright 1998-2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling";
5
6 #endif
7 #undef DEBUG_BUFFER_ADDRESSES
8 #undef GPROF
9 #undef DEBUG_FORKED
10 #undef DEBUG_CLEANUP
11 #undef DEBUG_DYN_OVERLAP
12 #undef DEBUG_READS
13 #define DEBUG_ILLLEADOUT 0 /* 0 disables, 1 enables */
14 /*
15 * Copyright: GNU Public License 2 applies
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2, or (at your option)
20 * any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 *
31 */
32 /*
33 * parts (C) Peter Widow
34 * parts (C) Thomas Niederreiter
35 * parts (C) RSA Data Security, Inc.
36 *
37 * last changes:
38 * 18.12.93 - first version, OK
39 * 01.01.94 - generalized & clean up HE
40 * 10.06.94 - first linux version HE
41 * 12.06.94 - wav header alignment problem fixed HE
42 * 12.08.94 - open the cdrom device O_RDONLY makes more sense :-)
43 * no more floating point math
44 * change to sector size 2352 which is more common
45 * sub-q-channel information per kernel ioctl requested
46 * doesn't work as well as before
47 * some new options (-max -i)
48 * 01.02.95 - async i/o via semaphores and shared memory
49 * 03.02.95 - overlapped reading on sectors
50 * 03.02.95 - generalized sample rates. all integral divisors are legal
51 * 04.02.95 - sun format added
52 * more divisors: all integral halves >= 1 allowed
53 * floating point math needed again
54 * 06.02.95 - bugfix for last track and not d0
55 * tested with photo-cd with audio tracks
56 * tested with xa disk
57 * 29.01.96 - new options for bulk transfer
58 * 01.06.96 - tested with enhanced cd
59 * 01.06.96 - tested with cd-plus
60 * 02.06.96 - support pipes
61 * 02.06.96 - support raw format
62 * 04.02.96 - security hole fixed
63 * 22.04.97 - large parts rewritten
64 * 28.04.97 - make file names DOS compatible
65 * 01.09.97 - add speed control
66 * 20.10.97 - add find mono option
67 * Jan/Feb 98 - conversion to use Joerg Schillings SCSI library
68 * see ChangeLog
69 */
70
71 #include "config.h"
72
73 #include <unixstd.h>
74 #include <stdio.h>
75 #include <standard.h>
76 #include <stdxlib.h>
77 #include <strdefs.h>
78 #include <schily.h>
79 #include <signal.h>
80 #include <math.h>
81 #include <fctldefs.h>
82 #include <timedefs.h>
83 #if defined (HAVE_LIMITS_H) && (HAVE_LIMITS_H == 1)
84 #include <limits.h>
85 #endif
86 #if defined (HAVE_SYS_IOCTL_H) && (HAVE_SYS_IOCTL_H == 1)
87 #include <sys/ioctl.h>
88 #endif
89 #include <errno.h>
90 #include <statdefs.h>
91 #include <waitdefs.h>
92 #if defined (HAVE_SETPRIORITY) && (HAVE_SETPRIORITY == 1)
93 #include <sys/resource.h>
94 #endif
95 #include <vadefs.h>
96
97 #include <scg/scsitransp.h>
98
99 #ifdef HAVE_AREAS
100 #include <be/kernel/OS.h>
101 #endif
102
103 #include "mytype.h"
104 #include "sndconfig.h"
105
106 #include "semshm.h" /* semaphore functions */
107 #include "sndfile.h"
108 #include "wav.h" /* wav file header structures */
109 #include "sun.h" /* sun audio file header structures */
110 #include "raw.h" /* raw file handling */
111 #include "aiff.h" /* aiff file handling */
112 #include "aifc.h" /* aifc file handling */
113 #ifdef USE_LAME
114 #include "mp3.h" /* mp3 file handling */
115 #endif
116 #include "interface.h" /* low level cdrom interfacing */
117 #include "cdda2wav.h"
118 #include "resample.h"
119 #include "toc.h"
120 #include "setuid.h"
121 #include "ringbuff.h"
122 #include "global.h"
123 #include "exitcodes.h"
124 #ifdef USE_PARANOIA
125 #include "cdda_paranoia.h"
126 #endif
127 #include "defaults.h"
128
129 EXPORT int main __PR((int argc, char **argv));
130 static void RestrictPlaybackRate __PR((long newrate));
131 static void output_indices __PR((FILE *fp, index_list *p, unsigned trackstart));
132 static int write_info_file __PR((char *fname_baseval, unsigned int track, unsigned long SamplesDone, int numbered));
133 static void CloseAudio __PR((int channels_val, unsigned long nSamples, struct soundfile *audio_out));
134 static void CloseAll __PR((void));
135 static void OpenAudio __PR((char *fname, double rate, long nBitsPerSample, long channels_val, unsigned long expected_bytes, struct soundfile*audio_out));
136 static void set_offset __PR((myringbuff *p, int offset));
137 static int get_offset __PR((myringbuff *p));
138 static void usage __PR((int));
139 static void init_globals __PR((void));
140 static int is_fifo __PR((char * filename));
141
142
143 /* Rules:
144 * unique parameterless options first,
145 * unique parametrized option names next,
146 * ambigious parameterless option names next,
147 * ambigious string parametrized option names last
148 */
149 static const char *opts = "paranoia,paraopts&,version,help,h,\
150 no-write,N,dump-rates,R,bulk,B,alltracks,verbose-scsi+,V+,\
151 find-extremes,F,find-mono,G,no-infofile,H,\
152 deemphasize,T,info-only,J,silent-scsi,Q,\
153 cddbp-server*,cddbp-port*,\
154 scanbus,device*,dev*,D*,auxdevice*,A*,interface*,I*,output-format*,O*,\
155 output-endianess*,E*,cdrom-endianess*,C*,speed#,S#,\
156 playback-realtime#L,p#L,md5#,M#,set-overlap#,P#,sound-device*,K*,\
157 cddb#,L#,channels*,c*,bits-per-sample#,b#,rate#,r#,gui,g,\
158 divider*,a*,track*,t*,index#,i#,duration*,d*,offset#,o#,\
159 sectors-per-request#,n#,verbose-level&,v&,buffers-in-ring#,l#,\
160 stereo,s,mono,m,wait,w,echo,e,quiet,q,max,x\
161 ";
162
163
164 #ifdef NEED_O_BINARY
165 #include <io.h> /* for setmode() prototype */
166 #endif
167
168 /* global variables */
169 global_t global;
170
171 /* static variables */
172 static unsigned long nSamplesDone = 0;
173
174 static int child_pid = -2;
175
176 static unsigned long *nSamplesToDo;
177 static unsigned int current_track;
178 static int bulk = 0;
179
180 unsigned int get_current_track __PR((void));
181
182 unsigned int get_current_track()
183 {
184 return current_track;
185 }
186
187 static void RestrictPlaybackRate( newrate )
188 long newrate;
189 {
190 global.playback_rate = newrate;
191
192 if ( global.playback_rate < 25 ) global.playback_rate = 25; /* filter out insane values */
193 if ( global.playback_rate > 250 ) global.playback_rate = 250;
194
195 if ( global.playback_rate < 100 )
196 global.nsectors = (global.nsectors*global.playback_rate)/100;
197 }
198
199
200 long SamplesNeeded( amount, undersampling_val)
201 long amount;
202 long undersampling_val;
203 {
204 long retval = ((undersampling_val * 2 + Halved)*amount)/2;
205 if (Halved && (*nSamplesToDo & 1))
206 retval += 2;
207 return retval;
208 }
209
210 static int argc2;
211 static int argc3;
212 static char **argv2;
213
214 static void reset_name_iterator __PR((void));
215 static void reset_name_iterator ()
216 {
217 argv2 -= argc3 - argc2;
218 argc2 = argc3;
219 }
220
221 static char *get_next_name __PR((void));
222 static char *get_next_name ()
223 {
224 if (argc2 > 0) {
225 argc2--;
226 return (*argv2++);
227 } else {
228 return NULL;
229 }
230 }
231
232 static char *cut_extension __PR(( char * fname ));
233
234 static char
235 *cut_extension (fname)
236 char *fname;
237 {
238 char *pp;
239
240 pp = strrchr(fname, '.');
241
242 if (pp == NULL) {
243 pp = fname + strlen(fname);
244 }
245 *pp = '\0';
246
247 return pp;
248 }
249
250 #ifdef INFOFILES
251 static void output_indices(fp, p, trackstart)
252 FILE *fp;
253 index_list *p;
254 unsigned trackstart;
255 {
256 int ci;
257
258 fprintf(fp, "Index=\t\t");
259
260 if (p == NULL) {
261 fprintf(fp, "0\n");
262 return;
263 }
264
265 for (ci = 1; p != NULL; ci++, p = p->next) {
266 int frameoff = p->frameoffset;
267
268 if (p->next == NULL)
269 fputs("\nIndex0=\t\t", fp);
270 #if 0
271 else if ( ci > 8 && (ci % 8) == 1)
272 fputs("\nIndex =\t\t", fp);
273 #endif
274 if (frameoff != -1)
275 fprintf(fp, "%d ", frameoff - trackstart);
276 else
277 fprintf(fp, "-1 ");
278 }
279 fputs("\n", fp);
280 }
281
282 /*
283 * write information before the start of the sampling process
284 *
285 *
286 * uglyfied for Joerg Schillings ultra dumb line parser
287 */
288 static int write_info_file(fname_baseval, track, SamplesDone, numbered)
289 char *fname_baseval;
290 unsigned int track;
291 unsigned long int SamplesDone;
292 int numbered;
293 {
294 FILE *info_fp;
295 char fname[200];
296 char datetime[30];
297 time_t utc_time;
298 struct tm *tmptr;
299
300 /* write info file */
301 if (!strcmp(fname_baseval,"-")) return 0;
302
303 strncpy(fname, fname_baseval, sizeof(fname) -1);
304 fname[sizeof(fname) -1] = 0;
305 if (numbered)
306 sprintf(cut_extension(fname), "_%02u.inf", track);
307 else
308 strcpy(cut_extension(fname), ".inf");
309
310 info_fp = fopen (fname, "w");
311 if (!info_fp)
312 return -1;
313
314 #if 0
315 #ifdef MD5_SIGNATURES
316 if (global.md5blocksize)
317 MD5Final (global.MD5_result, &global.context);
318 #endif
319 #endif
320
321 utc_time = time(NULL);
322 tmptr = localtime(&utc_time);
323 if (tmptr) {
324 strftime(datetime, sizeof(datetime), "%x %X", tmptr);
325 } else {
326 strncpy(datetime, "unknown", sizeof(datetime));
327 }
328 fprintf(info_fp, "#created by cdda2wav %s %s\n#\n", VERSION
329 , datetime
330 );
331 fprintf(info_fp,
332 "CDINDEX_DISCID=\t'%s'\n" , global.cdindex_id);
333 fprintf(info_fp,
334 "CDDB_DISCID=\t0x%08lx\n\
335 MCN=\t\t%s\n\
336 ISRC=\t\t%15.15s\n\
337 #\n\
338 Albumperformer=\t'%s'\n\
339 Performer=\t'%s'\n\
340 Albumtitle=\t'%s'\n"
341 , (unsigned long) global.cddb_id
342 , Get_MCN()
343 , Get_ISRC(track)
344 , global.creator != NULL ? global.creator : (const unsigned char *)""
345 , global.trackcreator[track] != NULL ? global.trackcreator[track] :
346 (global.creator != NULL ? global.creator : (const unsigned char *)"")
347 , global.disctitle != NULL ? global.disctitle : (const unsigned char *)""
348 );
349 fprintf(info_fp,
350 "Tracktitle=\t'%s'\n"
351 , global.tracktitle[track] ? global.tracktitle[track] : (const unsigned char *)""
352 );
353 fprintf(info_fp, "Tracknumber=\t%u\n"
354 , track
355 );
356 fprintf(info_fp,
357 "Trackstart=\t%ld\n"
358 , Get_AudioStartSector(track)
359 );
360 fprintf(info_fp,
361 "# track length in sectors (1/75 seconds each), rest samples\nTracklength=\t%ld, %d\n"
362 , SamplesDone/588L,(int)(SamplesDone%588));
363 fprintf(info_fp,
364 "Pre-emphasis=\t%s\n"
365 , Get_Preemphasis(track) && (global.deemphasize == 0) ? "yes" : "no");
366 fprintf(info_fp,
367 "Channels=\t%d\n"
368 , Get_Channels(track) ? 4 : global.channels == 2 ? 2 : 1);
369 { int cr = Get_Copyright(track);
370 fputs("Copy_permitted=\t", info_fp);
371 switch (cr) {
372 case 0:
373 fputs("once (copyright protected)\n", info_fp);
374 break;
375 case 1:
376 fputs("no (SCMS first copy)\n", info_fp);
377 break;
378 case 2:
379 fputs("yes (not copyright protected)\n", info_fp);
380 break;
381 default:
382 fputs("unknown\n", info_fp);
383 }
384 }
385 fprintf(info_fp,
386 "Endianess=\t%s\n"
387 , global.need_big_endian ? "big" : "little"
388 );
389 fprintf(info_fp, "# index list\n");
390 output_indices(info_fp, global.trackindexlist[track],
391 Get_AudioStartSector(track));
392 #if 0
393 /* MD5 checksums in info files are currently broken.
394 * for on-the-fly-recording the generation of info files has been shifted
395 * before the recording starts, so there is no checksum at that point.
396 */
397 #ifdef MD5_SIGNATURES
398 fprintf(info_fp,
399 "#(blocksize) checksum\nMD-5=\t\t(%d) %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n"
400 , global.md5blocksize
401 , global.MD5_result[0]
402 , global.MD5_result[1]
403 , global.MD5_result[2]
404 , global.MD5_result[3]
405 , global.MD5_result[4]
406 , global.MD5_result[5]
407 , global.MD5_result[6]
408 , global.MD5_result[7]
409 , global.MD5_result[8]
410 , global.MD5_result[9]
411 , global.MD5_result[10]
412 , global.MD5_result[11]
413 , global.MD5_result[12]
414 , global.MD5_result[13]
415 , global.MD5_result[14]
416 , global.MD5_result[15]);
417 #endif
418 #endif
419 fclose(info_fp);
420 return 0;
421 }
422 #endif
423
424 static void CloseAudio(channels_val, nSamples, audio_out)
425 int channels_val;
426 unsigned long nSamples;
427 struct soundfile *audio_out;
428 {
429 /* define length */
430 audio_out->ExitSound( global.audio, (nSamples-global.SkippedSamples)*global.OutSampleSize*channels_val );
431
432 close (global.audio);
433 global.audio = -1;
434 }
435
436 static unsigned int track = 1;
437
438 /* On terminating:
439 * define size-related entries in audio file header, update and close file */
440 static void CloseAll ()
441 {
442 WAIT_T chld_return_status;
443 int amiparent;
444
445 /* terminate child process first */
446 amiparent = child_pid > 0;
447
448 if (global.iloop > 0) {
449 /* set to zero */
450 global.iloop = 0;
451 }
452
453 #if defined HAVE_FORK_AND_SHAREDMEM
454 # ifdef DEBUG_CLEANUP
455 fprintf(stderr, "%s terminating, \n", amiparent ?
456 "Parent (READER)" : "Child (WRITER)");
457 #endif
458 #else
459 # ifdef DEBUG_CLEANUP
460 fprintf(stderr, "Cdda2wav single process terminating, \n");
461 # endif
462 #endif
463
464 if (amiparent || child_pid < 0) {
465 /* switch to original mode and close device */
466 EnableCdda (get_scsi_p(), 0, 0);
467 }
468
469 if (!amiparent) {
470 /* do general clean up */
471
472 if (global.audio>=0) {
473 if (bulk) {
474 /* finish sample file for this track */
475 CloseAudio(global.channels,
476 global.nSamplesDoneInTrack, global.audio_out);
477 } else {
478 /* finish sample file for this track */
479 CloseAudio(global.channels,
480 (unsigned int) *nSamplesToDo, global.audio_out);
481 }
482 }
483
484 /* tell minimum and maximum amplitudes, if required */
485 if (global.findminmax) {
486 fprintf(stderr,
487 "Right channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n",
488 global.minamp[0], global.maxamp[0]);
489 fprintf(stderr,
490 "Left channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n",
491 global.minamp[1], global.maxamp[1]);
492 }
493
494 /* tell mono or stereo recording, if required */
495 if (global.findmono) {
496 fprintf(stderr, "Audio samples are originally %s.\n", global.ismono ? "mono" : "stereo");
497 }
498
499 return; /* end of child or single process */
500 }
501
502
503 if (global.have_forked == 1) {
504 #ifdef DEBUG_CLEANUP
505 fprintf(stderr, "Parent wait for child death, \n");
506 #endif
507
508 /* wait for child to terminate */
509 if (0 > wait(&chld_return_status)) {
510 perror("");
511 } else {
512 if (WIFEXITED(chld_return_status)) {
513 if (WEXITSTATUS(chld_return_status)) {
514 fprintf(stderr, "\nW Child exited with %d\n", WEXITSTATUS(chld_return_status));
515 }
516 }
517 if (WIFSIGNALED(chld_return_status)) {
518 fprintf(stderr, "\nW Child exited due to signal %d\n", WTERMSIG(chld_return_status));
519 }
520 if (WIFSTOPPED(chld_return_status)) {
521 fprintf(stderr, "\nW Child is stopped due to signal %d\n", WSTOPSIG(chld_return_status));
522 }
523 }
524
525 #ifdef DEBUG_CLEANUP
526 fprintf(stderr, "\nW Parent child death, state:%d\n", chld_return_status);
527 #endif
528 }
529
530 #ifdef GPROF
531 rename("gmon.out", "gmon.child");
532 #endif
533 }
534
535
536 /* report a usage error and exit */
537 #ifdef PROTOTYPES
538 static void usage2 (const char *szMessage, ...)
539 #else
540 static void usage2 (szMessage, va_alist)
541 const char *szMessage;
542 va_dcl
543 #endif
544 {
545 va_list marker;
546
547 #ifdef PROTOTYPES
548 va_start(marker, szMessage);
549 #else
550 va_start(marker);
551 #endif
552
553 error("%r", szMessage, marker);
554
555 va_end(marker);
556 fprintf(stderr, "\nPlease use -help or consult the man page for help.\n");
557
558 exit (1);
559 }
560
561
562 /* report a fatal error, clean up and exit */
563 #ifdef PROTOTYPES
564 void FatalError (const char *szMessage, ...)
565 #else
566 void FatalError (szMessage, va_alist)
567 const char *szMessage;
568 va_dcl
569 #endif
570 {
571 va_list marker;
572
573 #ifdef PROTOTYPES
574 va_start(marker, szMessage);
575 #else
576 va_start(marker);
577 #endif
578
579 error("%r", szMessage, marker);
580
581 va_end(marker);
582
583 if (child_pid >= 0) {
584 if (child_pid == 0) {
585 pid_t ppid;
586 /*
587 * Kill the parent too if we are not orphaned.
588 */
589 ppid = getppid();
590 if (ppid > 1)
591 kill(ppid, SIGINT);
592 } else {
593 kill(child_pid, SIGINT);
594 }
595 }
596 exit (1);
597 }
598
599
600 /* open the audio output file and prepare the header.
601 * the header will be defined on terminating (when the size
602 * is known). So hitting the interrupt key leaves an intact
603 * file.
604 */
605 static void OpenAudio (fname, rate, nBitsPerSample, channels_val, expected_bytes, audio_out)
606 char *fname;
607 double rate;
608 long nBitsPerSample;
609 long channels_val;
610 unsigned long expected_bytes;
611 struct soundfile * audio_out;
612 {
613 if (global.audio == -1) {
614
615 global.audio = open (fname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY
616 #ifdef SYNCHRONOUS_WRITE
617 | O_SYNC
618 #endif
619 , 0666);
620 if (global.audio == -1) {
621 if (errno == EAGAIN && is_fifo(fname)) {
622 FatalError ("Could not open fifo %s. Probably no fifo reader present.\n", fname);
623 }
624 perror("open audio sample file");
625 FatalError ("Could not open file %s\n", fname);
626 }
627 }
628 global.SkippedSamples = 0;
629 any_signal = 0;
630 audio_out->InitSound( global.audio, channels_val, (unsigned long)rate, nBitsPerSample, expected_bytes );
631
632 #ifdef MD5_SIGNATURES
633 if (global.md5blocksize)
634 MD5Init (&global.context);
635 global.md5count = global.md5blocksize;
636 #endif
637 }
638
639 #include "scsi_cmds.h"
640
641 static int RealEnd __PR((SCSI *scgp, UINT4 *buff));
642
643 static int RealEnd(scgp, buff)
644 SCSI *scgp;
645 UINT4 *buff;
646 {
647 if (scg_cmd_err(scgp) != 0) {
648 int c,k,q;
649
650 k = scg_sense_key(scgp);
651 c = scg_sense_code(scgp);
652 q = scg_sense_qual(scgp);
653 if ((k == 0x05 /* ILLEGAL_REQUEST */ &&
654 c == 0x21 /* lba out of range */ &&
655 q == 0x00) ||
656 (k == 0x05 /* ILLEGAL_REQUEST */ &&
657 c == 0x63 /*end of user area encountered on this track*/ &&
658 q == 0x00) ||
659 (k == 0x08 /* BLANK_CHECK */ &&
660 c == 0x64 /* illegal mode for this track */ &&
661 q == 0x00)) {
662 return 1;
663 }
664 }
665
666 if (scg_getresid(scgp) > 16) return 1;
667
668 {
669 unsigned char *p;
670 /* Look into the subchannel data */
671 buff += CD_FRAMESAMPLES;
672 p = (unsigned char *)buff;
673 if (p[0] == 0x21 && p[1] == 0xaa) {
674 return 1;
675 }
676 }
677 return 0;
678 }
679
680 static void set_offset(p, offset)
681 myringbuff *p;
682 int offset;
683 {
684 #ifdef DEBUG_SHM
685 fprintf(stderr, "Write offset %d at %p\n", offset, &p->offset);
686 #endif
687 p->offset = offset;
688 }
689
690
691 static int get_offset(p)
692 myringbuff *p;
693 {
694 #ifdef DEBUG_SHM
695 fprintf(stderr, "Read offset %d from %p\n", p->offset, &p->offset);
696 #endif
697 return p->offset;
698 }
699
700
701 static void usage(int deliberate)
702 {
703 FILE *target=deliberate ? stdout : stderr;
704
705 fputs(
706 "usage: cdda2wav [OPTIONS ...] [trackfilenames ...]\n\
707 OPTIONS:\n\
708 [-c chans] [-s] [-m] [-b bits] [-r rate] [-a divider] [-S speed] [-x]\n\
709 [-t track[+endtrack]] [-i index] [-o offset] [-d duration] [-F] [-G]\n\
710 [-q] [-w] [-v vopts] [-R] [-P overlap] [-B] [-T] [-C input-endianess]\n\
711 [-e] [-n sectors] [-N] [-J] [-L cddbp-mode] [-H] [-g] [-l buffers] [-D cd-device]\n\
712 [-I interface] [-K sound-device] [-O audiotype] [-E output-endianess]\n\
713 [-A auxdevice] [-paranoia] [-cddbp-server=name] [-cddbp-port=port] [-version]\n", stderr);
714 fputs("\
715 (-D) dev=device set the cdrom or scsi device (as Bus,Id,Lun).\n\
716 (-A) auxdevice=device set the aux device (typically /dev/cdrom).\n\
717 (-K) sound-device=device set the sound device to use for -e (typically /dev/dsp).\n\
718 (-I) interface=interface specify the interface for cdrom access.\n\
719 (generic_scsi or cooked_ioctl).\n\
720 (-c) channels=channels set 1 for mono, 2 or s for stereo (s: channels swapped).\n\
721 (-s) -stereo select stereo recording.\n\
722 (-m) -mono select mono recording.\n\
723 (-x) -max select maximum quality (stereo/16-bit/44.1 KHz).\n\
724 (-b) bits=bits set bits per sample per channel (8, 12 or 16 bits).\n\
725 (-r) rate=rate set rate in samples per second. -R gives all rates\n\
726 (-a) divider=divider set rate to 44100Hz / divider. -R gives all rates\n\
727 (-R) -dump-rates dump a table with all available sample rates\n\
728 (-S) speed=speedfactor set the cdrom drive to a given speed during reading\n\
729 (-P) set-overlap=sectors set amount of overlap sampling (default is 0)\n\
730 (-n) sectors-per-request=secs read 'sectors' sectors per request.\n\
731 (-l) buffers-in-ring=buffers use a ring buffer with 'buffers' elements.\n\
732 (-t) track=track[+end track] select start track (option. end track).\n\
733 (-i) index=index select start index.\n\
734 (-o) offset=offset start at 'offset' sectors behind start track/index.\n\
735 one sector equivalents 1/75 second.\n\
736 (-O) output-format=audiotype set to wav, au (sun), cdr (raw), aiff or aifc format.\n\
737 (-C) cdrom-endianess=endian set little, big or guess input sample endianess.\n\
738 (-E) output-endianess=endian set little or big output sample endianess.\n\
739 (-d) duration=seconds set recording time in seconds or 0 for whole track.\n\
740 (-w) -wait wait for audio signal, then start recording.\n\
741 (-F) -find-extremes find extrem amplitudes in samples.\n\
742 (-G) -find-mono find if input samples are mono.\n\
743 (-T) -deemphasize undo pre-emphasis in input samples.\n\
744 (-e) -echo echo audio data to sound device (see -K) SOUND_DEV.\n\
745 (-v) verbose-level=optlist controls verbosity (for a list use -vhelp).\n\
746 (-N) -no-write do not create audio sample files.\n\
747 (-J) -info-only give disc information only.\n\
748 (-L) cddb=cddbpmode do cddbp title lookups.\n\
749 resolve multiple entries according to cddbpmode: 0=interactive, 1=first entry\n\
750 (-H) -no-infofile no info file generation.\n\
751 (-g) -gui generate special output suitable for gui frontends.\n\
752 (-Q) -silent-scsi do not print status of erreneous scsi-commands.\n\
753 -scanbus scan the SCSI bus and exit\n\
754 (-M) md5=count calculate MD-5 checksum for blocks of 'count' bytes.\n\
755 (-q) -quiet quiet operation, no screen output.\n\
756 (-p) playback-realtime=perc play (echo) audio pitched at perc percent (50%-200%).\n\
757 (-V) -verbose-scsi each option increases verbosity for SCSI commands.\n\
758 (-h) -help show this help screen.\n\
759 (-B) -alltracks, -bulk record each track into a seperate file.\n\
760 -paranoia use the lib paranoia for reading.\n\
761 -paraopts=opts set options for lib paranoia (see -paraopts=help).\n\
762 -cddbp-server=servername set the cddbp server to use for title lookups.\n\
763 -cddbp-port=portnumber set the cddbp port to use for title lookups.\n\
764 -version print version information.\n\
765 \n\
766 Please note: some short options will be phased out soon (disappear)!\n\
767 \n\
768 parameters: (optional) one or more file names or - for standard output.\n\
769 ", target);
770 fputs("Version ", target);
771 fputs(VERSION, target);
772 fprintf(target, "\n\
773 defaults %s, %d bit, %d.%02d Hz, track 1, no offset, one track,\n",
774 CHANNELS-1?"stereo":"mono", BITS_P_S,
775 44100 / UNDERSAMPLING,
776 (4410000 / UNDERSAMPLING) % 100);
777 fprintf(target, "\
778 type %s '%s', don't wait for signal, not quiet,\n",
779 AUDIOTYPE, FILENAME);
780 fprintf(target, "\
781 use %s, device %s, aux %s\n",
782 DEF_INTERFACE, CD_DEVICE, AUX_DEVICE);
783 exit( SYNTAX_ERROR );
784 }
785
786 static void init_globals()
787 {
788 #ifdef HISTORICAL_JUNK
789 global.dev_name = CD_DEVICE; /* device name */
790 #endif
791 global.aux_name = AUX_DEVICE;/* auxiliary cdrom device */
792 strncpy(global.fname_base, FILENAME, sizeof(global.fname_base));/* auxiliary cdrom device */
793 global.have_forked = 0; /* state variable for clean up */
794 global.parent_died = 0; /* state variable for clean up */
795 global.audio = -1; /* audio file desc */
796 global.cooked_fd = -1; /* cdrom file desc */
797 global.no_file = 0; /* flag no_file */
798 global.no_infofile = 0; /* flag no_infofile */
799 global.no_cddbfile = 0; /* flag no_cddbfile */
800 global.quiet = 0; /* flag quiet */
801 global.verbose = SHOW_TOC + SHOW_SUMMARY + SHOW_STARTPOSITIONS + SHOW_TITLES; /* verbose level */
802 global.scsi_silent = 0;
803 global.scsi_verbose = 0; /* SCSI verbose level */
804 global.scanbus = 0;
805 global.multiname = 0; /* multiple file names given */
806 global.sh_bits = 0; /* sh_bits: sample bit shift */
807 global.Remainder= 0; /* remainder */
808 global.iloop = 0; /* todo counter */
809 global.SkippedSamples = 0; /* skipped samples */
810 global.OutSampleSize = 0; /* output sample size */
811 global.channels = CHANNELS; /* output sound channels */
812 global.nSamplesDoneInTrack = 0; /* written samples in current track */
813 global.buffers = 4; /* buffers to use */
814 global.nsectors = NSECTORS; /* sectors to read in one request */
815 global.overlap = 1; /* amount of overlapping sectors */
816 global.useroverlap = -1; /* amount of overlapping sectors user override */
817 global.need_hostorder = 0; /* processing needs samples in host endianess */
818 global.in_lendian = -1; /* input endianess from SetupSCSI() */
819 global.outputendianess = NONE; /* user specified output endianess */
820 global.findminmax = 0; /* flag find extrem amplitudes */
821 #ifdef HAVE_LIMITS_H
822 global.maxamp[0] = INT_MIN; /* maximum amplitude */
823 global.maxamp[1] = INT_MIN; /* maximum amplitude */
824 global.minamp[0] = INT_MAX; /* minimum amplitude */
825 global.minamp[1] = INT_MAX; /* minimum amplitude */
826 #else
827 global.maxamp[0] = -32768; /* maximum amplitude */
828 global.maxamp[1] = -32768; /* maximum amplitude */
829 global.minamp[0] = 32767; /* minimum amplitude */
830 global.minamp[1] = 32767; /* minimum amplitude */
831 #endif
832 global.speed = DEFAULT_SPEED; /* use default */
833 global.userspeed = -1; /* speed user override */
834 global.findmono = 0; /* flag find if samples are mono */
835 global.ismono = 1; /* flag if samples are mono */
836 global.swapchannels = 0; /* flag if channels shall be swapped */
837 global.deemphasize = 0; /* flag undo pre-emphasis in samples */
838 global.playback_rate = 100; /* new fancy selectable sound output rate */
839 global.gui = 0; /* flag plain formatting for guis */
840 global.cddb_id = 0; /* disc identifying id for CDDB database */
841 global.cddb_revision = 0; /* entry revision for CDDB database */
842 global.cddb_year = 0; /* disc identifying year for CDDB database */
843 global.cddb_genre[0] = '\0'; /* disc identifying genre for CDDB database */
844 global.cddbp = 0; /* flag if titles shall be looked up from CDDBP */
845 global.cddbp_server = 0; /* user supplied CDDBP server */
846 global.cddbp_port = 0; /* user supplied CDDBP port */
847 global.illleadout_cd = 0; /* flag if illegal leadout is present */
848 global.reads_illleadout = 0; /* flag if cdrom drive reads cds with illegal leadouts */
849 global.disctitle = NULL;
850 global.creator = NULL;
851 global.copyright_message = NULL;
852 memset(global.tracktitle, 0, sizeof(global.tracktitle));
853 memset(global.trackindexlist, 0, sizeof(global.trackindexlist));
854
855 global.just_the_toc = 0;
856 #ifdef USE_PARANOIA
857 global.paranoia_parms.disable_paranoia =
858 global.paranoia_parms.disable_extra_paranoia =
859 global.paranoia_parms.disable_scratch_detect =
860 global.paranoia_parms.disable_scratch_repair = 0;
861 global.paranoia_parms.retries = 20;
862 global.paranoia_parms.overlap = -1;
863 global.paranoia_parms.mindynoverlap = -1;
864 global.paranoia_parms.maxdynoverlap = -1;
865 #endif
866 }
867
868 #if !defined (HAVE_STRCASECMP) || (HAVE_STRCASECMP != 1)
869 #include <ctype.h>
870 static int strcasecmp __PR(( const char *s1, const char *s2 ));
871 static int strcasecmp(s1, s2)
872 const char *s1;
873 const char *s2;
874 {
875 if (s1 && s2) {
876 while (*s1 && *s2 && (tolower(*s1) - tolower(*s2) == 0)) {
877 s1++;
878 s2++;
879 }
880 if (*s1 == '\0' && *s2 == '\0') return 0;
881 if (*s1 == '\0') return -1;
882 if (*s2 == '\0') return +1;
883 return tolower(*s1) - tolower(*s2);
884 }
885 return -1;
886 }
887 #endif
888
889 static int is_fifo(filename)
890 char * filename;
891 {
892 #if defined S_ISFIFO
893 struct stat statstruct;
894
895 if (stat(filename, &statstruct)) {
896 /* maybe the output file does not exist. */
897 if (errno == ENOENT)
898 return 0;
899 else comerr("Error during stat for output file\n");
900 } else {
901 if (S_ISFIFO(statstruct.st_mode)) {
902 return 1;
903 }
904 }
905 return 0;
906 #else
907 return 0;
908 #endif
909 }
910
911
912 #if !defined (HAVE_STRTOUL) || (HAVE_STRTOUL != 1)
913 static unsigned int strtoul __PR(( const char *s1, char **s2, int base ));
914 static unsigned int strtoul(s1, s2, base)
915 const char *s1;
916 char **s2;
917 int base;
918 {
919 long retval;
920
921 if (base == 10) {
922 /* strip zeros in front */
923 while (*s1 == '0')
924 s1++;
925 }
926 if (s2 != NULL) {
927 *s2 = astol(s1, &retval);
928 } else {
929 (void) astol(s1, &retval);
930 }
931
932 return (unsigned long) retval;
933 }
934 #endif
935
936 static unsigned long SectorBurst;
937 #if (SENTINEL > CD_FRAMESIZE_RAW)
938 error block size for overlap check has to be < sector size
939 #endif
940
941
942 static void
943 switch_to_realtime_priority __PR((void));
944
945 #ifdef HAVE_SYS_PRIOCNTL_H
946
947 #include <sys/priocntl.h>
948 #include <sys/rtpriocntl.h>
949 static void
950 switch_to_realtime_priority()
951 {
952 pcinfo_t info;
953 pcparms_t param;
954 rtinfo_t rtinfo;
955 rtparms_t rtparam;
956 int pid;
957
958 pid = getpid();
959
960 /* get info */
961 strcpy(info.pc_clname, "RT");
962 if (-1 == priocntl(P_PID, pid, PC_GETCID, (void *)&info)) {
963 errmsg("Cannot get priority class id priocntl(PC_GETCID)\n");
964 goto prio_done;
965 }
966
967 memmove(&rtinfo, info.pc_clinfo, sizeof(rtinfo_t));
968
969 /* set priority not to the max */
970 rtparam.rt_pri = rtinfo.rt_maxpri - 2;
971 rtparam.rt_tqsecs = 0;
972 rtparam.rt_tqnsecs = RT_TQDEF;
973 param.pc_cid = info.pc_cid;
974 memmove(param.pc_clparms, &rtparam, sizeof(rtparms_t));
975 priv_on();
976 needroot(0);
977 if (-1 == priocntl(P_PID, pid, PC_SETPARMS, (void *)&param))
978 errmsg("Cannot set priority class parameters priocntl(PC_SETPARMS)\n");
979 prio_done:
980 priv_off();
981 dontneedroot();
982 }
983 #else
984 #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING -0 >= 0
985 #define USE_POSIX_PRIORITY_SCHEDULING
986 #endif
987 #ifdef USE_POSIX_PRIORITY_SCHEDULING
988 #include <sched.h>
989
990 static void
991 switch_to_realtime_priority()
992 {
993 #ifdef _SC_PRIORITY_SCHEDULING
994 if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) {
995 errmsg("WARNING: RR-scheduler not available, disabling.\n");
996 } else
997 #endif
998 {
999 int sched_fifo_min, sched_fifo_max;
1000 struct sched_param sched_parms;
1001
1002 sched_fifo_min = sched_get_priority_min(SCHED_FIFO);
1003 sched_fifo_max = sched_get_priority_max(SCHED_FIFO);
1004 sched_parms.sched_priority = sched_fifo_max - 1;
1005 priv_on();
1006 needroot(0);
1007 if (-1 == sched_setscheduler(getpid(), SCHED_FIFO, &sched_parms)
1008 && global.quiet != 1)
1009 errmsg("cannot set posix realtime scheduling policy\n");
1010 priv_off();
1011 dontneedroot();
1012 }
1013 }
1014 #else
1015 #if defined(__CYGWIN32__)
1016
1017 /*
1018 * NOTE: Base.h from Cygwin-B20 has a second typedef for BOOL.
1019 * We define BOOL to make all local code use BOOL
1020 * from Windows.h and use the hidden __SBOOL for
1021 * our global interfaces.
1022 *
1023 * NOTE: windows.h from Cygwin-1.x includes a structure field named sample,
1024 * so me may not define our own 'sample' or need to #undef it now.
1025 * With a few nasty exceptions, Microsoft assumes that any global
1026 * defines or identifiers will begin with an Uppercase letter, so
1027 * there may be more of these problems in the future.
1028 *
1029 * NOTE: windows.h defines interface as an alias for struct, this
1030 * is used by COM/OLE2, I guess it is class on C++
1031 * We man need to #undef 'interface'
1032 */
1033 #define BOOL WBOOL /* This is the Win BOOL */
1034 #define format __format /* Avoid format parameter hides global ... */
1035 #include <windows.h>
1036 #undef format
1037 #undef interface
1038
1039 static void
1040 switch_to_realtime_priority()
1041 {
1042 /* set priority class */
1043 if (FALSE == SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) {
1044 fprintf(stderr, "No realtime priority possible.\n");
1045 return;
1046 }
1047
1048 /* set thread priority */
1049 if (FALSE == SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) {
1050 fprintf(stderr, "Could not set realtime priority.\n");
1051 }
1052 }
1053 #else
1054 static void
1055 switch_to_realtime_priority()
1056 {
1057 }
1058 #endif
1059 #endif
1060 #endif
1061
1062 /* SCSI cleanup */
1063 int on_exitscsi __PR((void *status));
1064
1065 int
1066 on_exitscsi(status)
1067 void *status;
1068 {
1069 exit((int)status);
1070 return 0;
1071 }
1072
1073 /* wrapper for signal handler exit needed for Mac-OS-X */
1074 static void exit_wrapper __PR((int status));
1075
1076 static void exit_wrapper(status)
1077 int status;
1078 {
1079 #if defined DEBUG_CLEANUP
1080 fprintf( stderr, "Exit(%d) for %s\n", status, child_pid == 0 ? "Child" : "Parent");
1081 fflush(stderr);
1082 #endif
1083
1084 if (child_pid != 0) {
1085 SCSI *scgp = get_scsi_p();
1086 if (scgp->running) {
1087 scgp->cb_fun = on_exitscsi;
1088 scgp->cb_arg = (void *)status;
1089 } else {
1090 on_exitscsi((void *)status);
1091 }
1092 } else {
1093 exit(status);
1094 }
1095 }
1096
1097 /* signal handler for process communication */
1098 static void set_nonforked __PR((int status));
1099
1100 /* ARGSUSED */
1101 static void set_nonforked(status)
1102 int status;
1103 {
1104 global.parent_died = 1;
1105 #if defined DEBUG_CLEANUP
1106 fprintf( stderr, "SIGPIPE received from %s\n.", child_pid == 0 ? "Child" : "Parent");
1107 #endif
1108 if (child_pid == 0) {
1109 pid_t ppid;
1110 /*
1111 * Kill the parent too if we are not orphaned.
1112 */
1113 ppid = getppid();
1114 if (ppid > 1)
1115 kill(ppid, SIGINT);
1116 } else {
1117 kill(child_pid, SIGINT);
1118 }
1119 exit(SIGPIPE_ERROR);
1120 }
1121
1122
1123
1124 #ifdef USE_PARANOIA
1125 static struct paranoia_statistics
1126 {
1127 long c_sector;
1128 long v_sector;
1129 int last_heartbeatstate;
1130 long lasttime;
1131 char heartbeat;
1132 int minoverlap;
1133 int curoverlap;
1134 int maxoverlap;
1135 int slevel;
1136 int slastlevel;
1137 int stimeout;
1138 int rip_smile_level;
1139 unsigned verifies;
1140 unsigned reads;
1141 unsigned fixup_edges;
1142 unsigned fixup_atoms;
1143 unsigned readerrs;
1144 unsigned skips;
1145 unsigned overlaps;
1146 unsigned scratchs;
1147 unsigned drifts;
1148 unsigned fixup_droppeds;
1149 unsigned fixup_dupeds;
1150 } *para_stat;
1151
1152
1153 static void paranoia_reset __PR((void));
1154 static void paranoia_reset()
1155 {
1156 para_stat->c_sector = 0;
1157 para_stat->v_sector = 0;
1158 para_stat->last_heartbeatstate = 0;
1159 para_stat->lasttime = 0;
1160 para_stat->heartbeat = ' ';
1161 para_stat->minoverlap = 0x7FFFFFFF;
1162 para_stat->curoverlap = 0;
1163 para_stat->maxoverlap = 0;
1164 para_stat->slevel = 0;
1165 para_stat->slastlevel = 0;
1166 para_stat->stimeout = 0;
1167 para_stat->rip_smile_level = 0;
1168 para_stat->verifies = 0;
1169 para_stat->reads = 0;
1170 para_stat->readerrs = 0;
1171 para_stat->fixup_edges = 0;
1172 para_stat->fixup_atoms = 0;
1173 para_stat->fixup_droppeds = 0;
1174 para_stat->fixup_dupeds = 0;
1175 para_stat->drifts = 0;
1176 para_stat->scratchs = 0;
1177 para_stat->overlaps = 0;
1178 para_stat->skips = 0;
1179 }
1180
1181 static void paranoia_callback __PR((long inpos, int function));
1182
1183 static void paranoia_callback(inpos, function)
1184 long inpos;
1185 int function;
1186 {
1187 struct timeval thistime;
1188 long test;
1189
1190 switch (function) {
1191 case -2:
1192 para_stat->v_sector = inpos / CD_FRAMEWORDS;
1193 return;
1194 case -1:
1195 para_stat->last_heartbeatstate = 8;
1196 para_stat->heartbeat = '*';
1197 para_stat->slevel = 0;
1198 para_stat->v_sector = inpos / CD_FRAMEWORDS;
1199 break;
1200 case PARANOIA_CB_VERIFY:
1201 if (para_stat->stimeout >= 30) {
1202 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1203 para_stat->slevel = 2;
1204 } else {
1205 para_stat->slevel = 1;
1206 }
1207 }
1208 para_stat->verifies++;
1209 break;
1210 case PARANOIA_CB_READ:
1211 if (inpos / CD_FRAMEWORDS > para_stat->c_sector) {
1212 para_stat->c_sector = inpos / CD_FRAMEWORDS;
1213 }
1214 para_stat->reads++;
1215 break;
1216 case PARANOIA_CB_FIXUP_EDGE:
1217 if (para_stat->stimeout >= 5) {
1218 if (para_stat->curoverlap > CD_FRAMEWORDS) {
1219 para_stat->slevel = 2;
1220 } else {
1221 para_stat->slevel = 1;
1222 }
1223 }
1224 para_stat->fixup_edges++;
1225 break;
1226 case PARANOIA_CB_FIXUP_ATOM:
1227 if (para_stat->slevel < 3 || para_stat->stimeout > 5) {
1228 para_stat->slevel = 3;
1229 }
1230 para_stat->fixup_atoms++;
1231 break;
1232 case PARANOIA_CB_READERR:
1233 para_stat->slevel = 6;
1234 para_stat->readerrs++;
1235 break;
1236 case PARANOIA_CB_SKIP:
1237 para_stat->slevel = 8;
1238 para_stat->skips++;
1239 break;
1240 case PARANOIA_CB_OVERLAP:
1241 para_stat->curoverlap = inpos;
1242 if (inpos > para_stat->maxoverlap)
1243 para_stat->maxoverlap = inpos;
1244 if (inpos < para_stat->minoverlap)
1245 para_stat->minoverlap = inpos;
1246 para_stat->overlaps++;
1247 break;
1248 case PARANOIA_CB_SCRATCH:
1249 para_stat->slevel = 7;
1250 para_stat->scratchs++;
1251 break;
1252 case PARANOIA_CB_DRIFT:
1253 if (para_stat->slevel < 4 || para_stat->stimeout > 5) {
1254 para_stat->slevel = 4;
1255 }
1256 para_stat->drifts++;
1257 break;
1258 case PARANOIA_CB_FIXUP_DROPPED:
1259 para_stat->slevel = 5;
1260 para_stat->fixup_droppeds++;
1261 break;
1262 case PARANOIA_CB_FIXUP_DUPED:
1263 para_stat->slevel = 5;
1264 para_stat->fixup_dupeds++;
1265 break;
1266 }
1267
1268 gettimeofday(&thistime, NULL);
1269 /* now in tenth of seconds. */
1270 test = thistime.tv_sec * 10 + thistime.tv_usec / 100000;
1271
1272 if (para_stat->lasttime != test
1273 || function == -1
1274 || para_stat->slastlevel != para_stat->slevel) {
1275
1276 if (function == -1
1277 || para_stat->slastlevel != para_stat->slevel) {
1278
1279 static const char hstates[] = " .o0O0o.";
1280
1281 para_stat->lasttime = test;
1282 para_stat->stimeout++;
1283
1284 para_stat->last_heartbeatstate++;
1285 if (para_stat->last_heartbeatstate > 7) {
1286 para_stat->last_heartbeatstate = 0;
1287 }
1288 para_stat->heartbeat = hstates[para_stat->last_heartbeatstate];
1289
1290 if (function == -1) {
1291 para_stat->heartbeat = '*';
1292 }
1293 }
1294
1295 if (para_stat->slastlevel != para_stat->slevel) {
1296 para_stat->stimeout = 0;
1297 }
1298 para_stat->slastlevel = para_stat->slevel;
1299 }
1300
1301 if (para_stat->slevel < 8) {
1302 para_stat->rip_smile_level = para_stat->slevel;
1303 } else {
1304 para_stat->rip_smile_level = 0;
1305 }
1306 }
1307 #endif
1308
1309 static long lSector;
1310 static long lSector_p2;
1311 static double rate = 44100.0 / UNDERSAMPLING;
1312 static int bits = BITS_P_S;
1313 static char fname[200];
1314 static const char *audio_type;
1315 static long BeginAtSample;
1316 static unsigned long SamplesToWrite;
1317 static unsigned minover;
1318 static unsigned maxover;
1319
1320 static unsigned long calc_SectorBurst __PR((void));
1321 static unsigned long calc_SectorBurst()
1322 {
1323 unsigned long SectorBurstVal;
1324
1325 SectorBurstVal = min(global.nsectors,
1326 (global.iloop + CD_FRAMESAMPLES-1) / CD_FRAMESAMPLES);
1327 if ( lSector+(int)SectorBurst-1 >= lSector_p2 )
1328 SectorBurstVal = lSector_p2 - lSector;
1329 return SectorBurstVal;
1330 }
1331
1332 /* if PERCENTAGE_PER_TRACK is defined, the percentage message will reach
1333 * 100% every time a track end is reached or the time limit is reached.
1334 *
1335 * Otherwise if PERCENTAGE_PER_TRACK is not defined, the percentage message
1336 * will reach 100% once at the very end of the last track.
1337 */
1338 #define PERCENTAGE_PER_TRACK
1339
1340 static int do_read __PR((myringbuff *p, unsigned *total_unsuccessful_retries));
1341 static int do_read (p, total_unsuccessful_retries)
1342 myringbuff *p;
1343 unsigned *total_unsuccessful_retries;
1344 {
1345 unsigned char *newbuf;
1346 int offset;
1347 unsigned int added_size;
1348
1349 /* how many sectors should be read */
1350 SectorBurst = calc_SectorBurst();
1351
1352 #ifdef USE_PARANOIA
1353 if (global.paranoia_selected) {
1354 int i;
1355
1356 for (i = 0; i < SectorBurst; i++) {
1357 void *dp;
1358
1359 dp = paranoia_read_limited(global.cdp, paranoia_callback,
1360 global.paranoia_parms.retries);
1361 /*
1362 {
1363 char *err;
1364 char *msg;
1365 err = cdda_errors(global.cdp);
1366 msg = cdda_messages(global.cdp);
1367 if (err) {
1368 fputs(err, stderr);
1369 free(err);
1370 }
1371 if (msg) {
1372 fputs(msg, stderr);
1373 free(msg);
1374 }
1375 }
1376 */
1377 if (dp != NULL) {
1378 memcpy(p->data + i*CD_FRAMESAMPLES, dp,
1379 CD_FRAMESIZE_RAW);
1380 } else {
1381 fputs("E unrecoverable error!", stderr);
1382 exit(READ_ERROR);
1383 }
1384 }
1385 newbuf = (unsigned char *)p->data;
1386 offset = 0;
1387 set_offset(p,offset);
1388 added_size = SectorBurst * CD_FRAMESAMPLES;
1389 global.overlap = 0;
1390 handle_inputendianess(p->data, added_size);
1391 } else
1392 #endif
1393 {
1394 unsigned int retry_count;
1395 #define MAX_READRETRY 12
1396
1397 retry_count = 0;
1398 do {
1399 SCSI *scgp = get_scsi_p();
1400 int retval;
1401 #ifdef DEBUG_READS
1402 fprintf(stderr, "reading from %lu to %lu, overlap %u\n", lSector, lSector + SectorBurst -1, global.overlap);
1403 #endif
1404
1405 #ifdef DEBUG_BUFFER_ADDRESSES
1406 fprintf(stderr, "%p %l\n", p->data, global.pagesize);
1407 if (((unsigned)p->data) & (global.pagesize -1) != 0) {
1408 fprintf(stderr, "Address %p is NOT page aligned!!\n", p->data);
1409 }
1410 #endif
1411
1412 if (global.reads_illleadout != 0 && lSector > Get_StartSector(LastTrack())) {
1413 int singles = 0;
1414 UINT4 bufferSub[CD_FRAMESAMPLES + 24];
1415
1416 /* we switch to single sector reads,
1417 * in order to handle the remaining sectors. */
1418 scgp->silent++;
1419 do {
1420 int retval2 = ReadCdRomSub( scgp, bufferSub, lSector+singles, 1 );
1421 *eorecording = RealEnd( scgp, bufferSub );
1422 if (*eorecording) {
1423 break;
1424 }
1425 memcpy(p->data+singles*CD_FRAMESAMPLES, bufferSub, CD_FRAMESIZE_RAW);
1426 singles++;
1427 } while (singles < SectorBurst);
1428 scgp->silent--;
1429
1430 if ( *eorecording ) {
1431 patch_real_end(lSector+singles);
1432 SectorBurst = singles;
1433 #if DEBUG_ILLLEADOUT
1434 fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu, end=%lu -->\n",
1435 global.iloop, *nSamplesToDo, lSector+singles);
1436 #endif
1437
1438 *nSamplesToDo -= global.iloop - SectorBurst*CD_FRAMESAMPLES;
1439 global.iloop = SectorBurst*CD_FRAMESAMPLES;
1440 #if DEBUG_ILLLEADOUT
1441 fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu\n\n",
1442 global.iloop, *nSamplesToDo);
1443 #endif
1444
1445 }
1446 } else {
1447 retval = ReadCdRom( scgp, p->data, lSector, SectorBurst );
1448 }
1449 handle_inputendianess(p->data, SectorBurst * CD_FRAMESAMPLES);
1450 if (NULL ==
1451 (newbuf = synchronize( p->data, SectorBurst*CD_FRAMESAMPLES,
1452 *nSamplesToDo-global.iloop ))) {
1453 /* could not synchronize!
1454 * Try to invalidate the cdrom cache.
1455 * Increase overlap setting, if possible.
1456 */
1457 /*trash_cache(p->data, lSector, SectorBurst);*/
1458 if (global.overlap < global.nsectors - 1) {
1459 global.overlap++;
1460 lSector--;
1461 SectorBurst = calc_SectorBurst();
1462 #ifdef DEBUG_DYN_OVERLAP
1463 fprintf(stderr, "using increased overlap of %u\n", global.overlap);
1464 #endif
1465 } else {
1466 lSector += global.overlap - 1;
1467 global.overlap = 1;
1468 SectorBurst = calc_SectorBurst();
1469 }
1470 } else
1471 break;
1472 } while (++retry_count < MAX_READRETRY);
1473
1474 if (retry_count == MAX_READRETRY && newbuf == NULL && global.verbose != 0) {
1475 (*total_unsuccessful_retries)++;
1476 }
1477
1478 if (newbuf) {
1479 offset = newbuf - ((unsigned char *)p->data);
1480 } else {
1481 offset = global.overlap * CD_FRAMESIZE_RAW;
1482 }
1483 set_offset(p,offset);
1484
1485 /* how much has been added? */
1486 added_size = SectorBurst * CD_FRAMESAMPLES - offset/4;
1487
1488 if (newbuf && *nSamplesToDo != global.iloop) {
1489 minover = min(global.overlap, minover);
1490 maxover = max(global.overlap, maxover);
1491
1492
1493 /* should we reduce the overlap setting ? */
1494 if (offset > CD_FRAMESIZE_RAW && global.overlap > 1) {
1495 #ifdef DEBUG_DYN_OVERLAP
1496 fprintf(stderr, "decreasing overlap from %u to %u (jitter %d)\n", global.overlap, global.overlap-1, offset - (global.overlap)*CD_FRAMESIZE_RAW);
1497 #endif
1498 global.overlap--;
1499 SectorBurst = calc_SectorBurst();
1500 }
1501 }
1502 }
1503 if (global.iloop >= added_size) {
1504 global.iloop -= added_size;
1505 } else {
1506 global.iloop = 0;
1507 }
1508
1509 lSector += SectorBurst - global.overlap;
1510
1511 #if defined PERCENTAGE_PER_TRACK && defined HAVE_FORK_AND_SHAREDMEM
1512 {
1513 int as;
1514 while ((as = Get_StartSector(current_track+1)) != -1
1515 && lSector >= as) {
1516 current_track++;
1517 }
1518 }
1519 #endif
1520
1521 return offset;
1522 }
1523
1524 static void
1525 print_percentage __PR((unsigned *poper, int c_offset));
1526
1527 static void
1528 print_percentage(poper, c_offset)
1529 unsigned *poper;
1530 int c_offset;
1531 {
1532 unsigned per;
1533 #ifdef PERCENTAGE_PER_TRACK
1534 /* Thomas Niederreiter wants percentage per track */
1535 unsigned start_in_track = max(BeginAtSample,
1536 Get_AudioStartSector(current_track)*CD_FRAMESAMPLES);
1537
1538 per = min(BeginAtSample + (long)*nSamplesToDo,
1539 Get_StartSector(current_track+1)*CD_FRAMESAMPLES)
1540 - (long)start_in_track;
1541
1542 per = (BeginAtSample+nSamplesDone
1543 - start_in_track
1544 )/(per/100);
1545
1546 #else
1547 per = global.iloop ? (nSamplesDone)/(*nSamplesToDo/100) : 100;
1548 #endif
1549
1550 if (global.overlap > 0) {
1551 fprintf(stderr, "\r%2d/%2d/%2d/%7d %3d%%",
1552 minover, maxover, global.overlap,
1553 c_offset - global.overlap*CD_FRAMESIZE_RAW,
1554 per);
1555 } else if (*poper != per) {
1556 fprintf(stderr, "\r%3d%%", per);
1557 }
1558 *poper = per;
1559 fflush(stderr);
1560 }
1561
1562 static unsigned long do_write __PR((myringbuff *p));
1563 static unsigned long do_write (p)
1564 myringbuff *p;
1565 {
1566 int current_offset;
1567 unsigned int InSamples;
1568 static unsigned oper = 200;
1569
1570 current_offset = get_offset(p);
1571
1572 /* how many bytes are available? */
1573 InSamples = global.nsectors*CD_FRAMESAMPLES - current_offset/4;
1574 /* how many samples are wanted? */
1575 InSamples = min((*nSamplesToDo-nSamplesDone),InSamples);
1576
1577 /* when track end is reached, close current file and start a new one */
1578 while ((nSamplesDone < *nSamplesToDo) && (InSamples != 0)) {
1579 long unsigned int how_much = InSamples;
1580
1581 long int left_in_track;
1582 left_in_track = Get_StartSector(current_track+1)*CD_FRAMESAMPLES
1583 - (int)(BeginAtSample+nSamplesDone);
1584
1585 if (*eorecording != 0 && current_track == cdtracks+1 &&
1586 (*total_segments_read) == (*total_segments_written)+1) {
1587 /* limit, if the actual end of the last track is
1588 * not known from the toc. */
1589 left_in_track = InSamples;
1590 }
1591
1592 if (left_in_track < 0) {
1593 fprintf(stderr, "internal error: negative left_in_track:%ld, current_track=%d\n",left_in_track, current_track);
1594 }
1595
1596 if (bulk) {
1597 how_much = min(how_much, (unsigned long) left_in_track);
1598 }
1599
1600 #ifdef MD5_SIGNATURES
1601 if (global.md5count) {
1602 MD5Update (&global.context, ((unsigned char *)p->data) +current_offset, min(global.md5count,how_much));
1603 global.md5count -= min(global.md5count,how_much);
1604 }
1605 #endif
1606 if ( SaveBuffer ( p->data + current_offset/4,
1607 how_much,
1608 &nSamplesDone) ) {
1609 if (global.have_forked == 1) {
1610 pid_t ppid;
1611 /*
1612 * Kill the parent too if we are not orphaned.
1613 */
1614 ppid = getppid();
1615 if (ppid > 1)
1616 kill(ppid, SIGINT);
1617 }
1618 exit(WRITE_ERROR);
1619 }
1620
1621 global.nSamplesDoneInTrack += how_much;
1622 SamplesToWrite -= how_much;
1623
1624 /* move residual samples upto buffer start */
1625 if (how_much < InSamples) {
1626 memmove(
1627 (char *)(p->data) + current_offset,
1628 (char *)(p->data) + current_offset + how_much*4,
1629 (InSamples - how_much) * 4);
1630 }
1631
1632 if ((unsigned long) left_in_track <= InSamples || SamplesToWrite == 0) {
1633 /* the current portion to be handled is
1634 the end of a track */
1635
1636 if (bulk) {
1637 /* finish sample file for this track */
1638 CloseAudio(global.channels,
1639 global.nSamplesDoneInTrack, global.audio_out);
1640 } else if (SamplesToWrite == 0) {
1641 /* finish sample file for this track */
1642 CloseAudio(global.channels,
1643 (unsigned int) *nSamplesToDo, global.audio_out);
1644 }
1645
1646 if (global.verbose) {
1647 #ifdef USE_PARANOIA
1648 double f;
1649 #endif
1650 print_percentage(&oper, current_offset);
1651 fputc(' ', stderr);
1652 #ifndef THOMAS_SCHAU_MAL
1653 if ((unsigned long)left_in_track > InSamples) {
1654 fputs(" incomplete", stderr);
1655 }
1656 #endif
1657 if (global.tracktitle[current_track] != NULL) {
1658 fprintf( stderr,
1659 " track %2u '%s' recorded",
1660 current_track,
1661 global.tracktitle[current_track]);
1662 } else {
1663 fprintf( stderr,
1664 " track %2u recorded",
1665 current_track);
1666 }
1667 #ifdef USE_PARANOIA
1668 oper = para_stat->readerrs + para_stat->skips +
1669 para_stat->fixup_edges + para_stat->fixup_atoms +
1670 para_stat->fixup_droppeds + para_stat->fixup_dupeds +
1671 para_stat->drifts;
1672 f = (100.0 * oper) / (((double)global.nSamplesDoneInTrack)/588.0);
1673
1674 if (para_stat->readerrs) {
1675 fprintf(stderr, " with audible hard errors");
1676 } else if ((para_stat->skips) > 0) {
1677 fprintf(stderr, " with %sretry/skip errors",
1678 f < 2.0 ? "":"audible ");
1679 } else if (oper > 0) {
1680 oper = f;
1681
1682 fprintf(stderr, " with ");
1683 if (oper < 2)
1684 fprintf(stderr, "minor");
1685 else if (oper < 10)
1686 fprintf(stderr, "medium");
1687 else if (oper < 67)
1688 fprintf(stderr, "noticable audible");
1689 else if (oper < 100)
1690 fprintf(stderr, "major audible");
1691 else
1692 fprintf(stderr, "extreme audible");
1693 fprintf(stderr, " problems");
1694 } else {
1695 fprintf(stderr, " successfully");
1696 }
1697 if (f >= 0.1)
1698 fprintf(stderr, " (%.1f%% problem sectors)", f);
1699 #else
1700 fprintf(stderr, " successfully");
1701 #endif
1702
1703 if (waitforsignal == 1) {
1704 fprintf(stderr, ". %d silent samples omitted", global.SkippedSamples);
1705 }
1706 fputs("\n", stderr);
1707
1708 if (global.reads_illleadout && *eorecording == 1) {
1709 fprintf(stderr, "Real lead out at: %ld sectors\n",
1710 (*nSamplesToDo+BeginAtSample)/CD_FRAMESAMPLES);
1711 }
1712 #ifdef USE_PARANOIA
1713 if (global.paranoia_selected) {
1714 oper = 200; /* force new output */
1715 print_percentage(&oper, current_offset);
1716 if (para_stat->minoverlap == 0x7FFFFFFF)
1717 para_stat->minoverlap = 0;
1718 fprintf(stderr, " %u rderr, %u skip, %u atom, %u edge, %u drop, %u dup, %u drift\n"
1719 ,para_stat->readerrs
1720 ,para_stat->skips
1721 ,para_stat->fixup_atoms
1722 ,para_stat->fixup_edges
1723 ,para_stat->fixup_droppeds
1724 ,para_stat->fixup_dupeds
1725 ,para_stat->drifts);
1726 oper = 200; /* force new output */
1727 print_percentage(&oper, current_offset);
1728 fprintf(stderr, " %u overlap(%.4g .. %.4g)\n",
1729 para_stat->overlaps,
1730 (float)para_stat->minoverlap / (2352.0/2.0),
1731 (float)para_stat->maxoverlap / (2352.0/2.0));
1732 paranoia_reset();
1733 }
1734 #endif
1735 }
1736
1737 global.nSamplesDoneInTrack = 0;
1738 if ( bulk && SamplesToWrite > 0 ) {
1739 if ( !global.no_file ) {
1740 char *tmp_fname;
1741
1742 /* build next filename */
1743 tmp_fname = get_next_name();
1744 if (tmp_fname != NULL) {
1745 strncpy(global.fname_base,
1746 tmp_fname,
1747 sizeof global.fname_base);
1748 global.fname_base[
1749 sizeof(global.fname_base)-1] =
1750 '\0';
1751 }
1752
1753 tmp_fname = cut_extension(global.fname_base);
1754 tmp_fname[0] = '\0';
1755
1756 if (global.multiname == 0) {
1757 sprintf(fname, "%s_%02u.%s",
1758 global.fname_base,
1759 current_track+1,
1760 audio_type);
1761 } else {
1762 sprintf(fname, "%s.%s",
1763 global.fname_base,
1764 audio_type);
1765 }
1766
1767 OpenAudio( fname, rate, bits, global.channels,
1768 (Get_AudioStartSector(current_track+1) -
1769 Get_AudioStartSector(current_track))
1770 *CD_FRAMESIZE_RAW,
1771 global.audio_out);
1772 } /* global.nofile */
1773 } /* if ( bulk && SamplesToWrite > 0 ) */
1774 current_track++;
1775
1776 } /* left_in_track <= InSamples */
1777 InSamples -= how_much;
1778
1779 } /* end while */
1780 if (!global.quiet && *nSamplesToDo != nSamplesDone) {
1781 print_percentage(&oper, current_offset);
1782 }
1783 return nSamplesDone;
1784 }
1785
1786 #define PRINT_OVERLAP_INIT \
1787 if (global.verbose) { \
1788 if (global.overlap > 0) \
1789 fprintf(stderr, "overlap:min/max/cur, jitter, percent_done:\n / / / 0%%"); \
1790 else \
1791 fputs("percent_done:\n 0%", stderr); \
1792 }
1793
1794 #if defined HAVE_FORK_AND_SHAREDMEM
1795 static void forked_read __PR((void));
1796
1797 /* This function does all audio cdrom reads
1798 * until there is nothing more to do
1799 */
1800 static void
1801 forked_read()
1802 {
1803 unsigned total_unsuccessful_retries = 0;
1804
1805 #if !defined(HAVE_SEMGET) || !defined(USE_SEMAPHORES)
1806 init_child();
1807 #endif
1808
1809 minover = global.nsectors;
1810
1811 PRINT_OVERLAP_INIT
1812 while (global.iloop) {
1813
1814 do_read(get_next_buffer(), &total_unsuccessful_retries);
1815
1816 define_buffer();
1817
1818 } /* while (global.iloop) */
1819
1820 if (total_unsuccessful_retries) {
1821 fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries);
1822 }
1823 }
1824
1825 static void forked_write __PR((void));
1826
1827 static void
1828 forked_write()
1829 {
1830
1831 /* don't need these anymore. Good security policy says we get rid
1832 of them ASAP */
1833 priv_off();
1834 neverneedroot();
1835 neverneedgroup();
1836
1837 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
1838 #else
1839 init_parent();
1840 #endif
1841
1842 for (;nSamplesDone < *nSamplesToDo;) {
1843 if (*eorecording == 1 && (*total_segments_read) == (*total_segments_written)) break;
1844
1845 /* get oldest buffers */
1846
1847 nSamplesDone = do_write(get_oldest_buffer());
1848
1849 drop_buffer();
1850
1851 } /* end for */
1852
1853 }
1854 #endif
1855
1856 /* This function implements the read and write calls in one loop (in case
1857 * there is no fork/thread_create system call).
1858 * This means reads and writes have to wait for each other to complete.
1859 */
1860 static void nonforked_loop __PR((void));
1861
1862 static void
1863 nonforked_loop()
1864 {
1865 unsigned total_unsuccessful_retries = 0;
1866
1867 minover = global.nsectors;
1868
1869 PRINT_OVERLAP_INIT
1870 while (global.iloop) {
1871
1872 do_read(get_next_buffer(), &total_unsuccessful_retries);
1873
1874 do_write(get_oldest_buffer());
1875
1876 }
1877
1878 if (total_unsuccessful_retries) {
1879 fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries);
1880 }
1881
1882 }
1883
1884 void verbose_usage __PR((void));
1885
1886 void verbose_usage()
1887 {
1888 fputs("\
1889 help lists all verbose options.\n\
1890 disable disables verbose mode.\n\
1891 all enables all verbose options.\n\
1892 toc display the table of contents.\n\
1893 summary display a summary of track parameters.\n\
1894 indices retrieve/display index positions.\n\
1895 catalog retrieve/display media catalog number.\n\
1896 trackid retrieve/display international standard recording code.\n\
1897 sectors display the start sectors of each track.\n\
1898 titles display any known track titles.\n\
1899 ", stderr);
1900 }
1901
1902 #ifdef USE_PARANOIA
1903 void paranoia_usage __PR((void));
1904
1905 void paranoia_usage()
1906 {
1907 fputs("\
1908 help lists all paranoia options.\n\
1909 disable disables paranoia mode. Paranoia is still being used.\n\
1910 no-verify switches verify off, and overlap on.\n\
1911 retries=amount set the number of maximum retries per sector.\n\
1912 overlap=amount set the number of sectors used for statical paranoia overlap.\n\
1913 minoverlap=amt set the min. number of sectors used for dynamic paranoia overlap.\n\
1914 maxoverlap=amt set the max. number of sectors used for dynamic paranoia overlap.\n\
1915 ", stderr);
1916 }
1917 #endif
1918
1919 int
1920 handle_verbose_opts __PR((char *optstr, long *flagp));
1921
1922 int
1923 handle_verbose_opts(optstr, flagp)
1924 char *optstr;
1925 long *flagp;
1926 {
1927 char *ep;
1928 char *np;
1929 int optlen;
1930
1931 *flagp = 0;
1932 while (*optstr) {
1933 if ((ep = strchr(optstr, ',')) != NULL) {
1934 optlen = ep - optstr;
1935 np = ep + 1;
1936 } else {
1937 optlen = strlen(optstr);
1938 np = optstr + optlen;
1939 }
1940 if (strncmp(optstr, "toc", optlen) == 0) {
1941 *flagp |= SHOW_TOC;
1942 }
1943 else if (strncmp(optstr, "summary", optlen) == 0) {
1944 *flagp |= SHOW_SUMMARY;
1945 }
1946 else if (strncmp(optstr, "indices", optlen) == 0) {
1947 *flagp |= SHOW_INDICES;
1948 }
1949 else if (strncmp(optstr, "catalog", optlen) == 0) {
1950 *flagp |= SHOW_MCN;
1951 }
1952 else if (strncmp(optstr, "trackid", optlen) == 0) {
1953 *flagp |= SHOW_ISRC;
1954 }
1955 else if (strncmp(optstr, "sectors", optlen) == 0) {
1956 *flagp |= SHOW_STARTPOSITIONS;
1957 }
1958 else if (strncmp(optstr, "titles", optlen) == 0) {
1959 *flagp |= SHOW_TITLES;
1960 }
1961 else if (strncmp(optstr, "all", optlen) == 0) {
1962 *flagp |= SHOW_MAX;
1963 }
1964 else if (strncmp(optstr, "disable", optlen) == 0) {
1965 *flagp = 0;
1966 }
1967 else if (strncmp(optstr, "help", optlen) == 0) {
1968 verbose_usage();
1969 exit(NO_ERROR);
1970 }
1971 else {
1972 char *endptr;
1973 unsigned arg = strtoul(optstr, &endptr, 10);
1974 if (optstr != endptr
1975 && arg <= SHOW_MAX) {
1976 *flagp |= arg;
1977 fprintf(stderr, "Warning: numerical parameters for -v are no more supported in the next releases!\n");
1978 }
1979 else {
1980 fprintf(stderr, "unknown option %s\n", optstr);
1981 verbose_usage();
1982 exit(SYNTAX_ERROR);
1983 }
1984 }
1985 optstr = np;
1986 }
1987 return 1;
1988 }
1989
1990
1991 int
1992 handle_paranoia_opts __PR((char *optstr, long *flagp));
1993
1994 int
1995 handle_paranoia_opts(optstr, flagp)
1996 char *optstr;
1997 long *flagp;
1998 {
1999 #ifdef USE_PARANOIA
2000 char *ep;
2001 char *np;
2002 int optlen;
2003
2004 while (*optstr) {
2005 if ((ep = strchr(optstr, ',')) != NULL) {
2006 optlen = ep - optstr;
2007 np = ep + 1;
2008 } else {
2009 optlen = strlen(optstr);
2010 np = optstr + optlen;
2011 }
2012 if (strncmp(optstr, "retries=", min(8,optlen)) == 0) {
2013 char *eqp = strchr(optstr, '=');
2014 int rets;
2015
2016 astoi(eqp+1, &rets);
2017 if (rets >= 0) {
2018 global.paranoia_parms.retries = rets;
2019 }
2020 }
2021 else if (strncmp(optstr, "overlap=", min(8, optlen)) == 0) {
2022 char *eqp = strchr(optstr, '=');
2023 int rets;
2024
2025 astoi(eqp+1, &rets);
2026 if (rets >= 0) {
2027 global.paranoia_parms.overlap = rets;
2028 }
2029 }
2030 else if (strncmp(optstr, "minoverlap=", min(11, optlen)) == 0) {
2031 char *eqp = strchr(optstr, '=');
2032 int rets;
2033
2034 astoi(eqp+1, &rets);
2035 if (rets >= 0) {
2036 global.paranoia_parms.mindynoverlap = rets;
2037 }
2038 }
2039 else if (strncmp(optstr, "maxoverlap=", min(11, optlen)) == 0) {
2040 char *eqp = strchr(optstr, '=');
2041 int rets;
2042
2043 astoi(eqp+1, &rets);
2044 if (rets >= 0) {
2045 global.paranoia_parms.maxdynoverlap = rets;
2046 }
2047 }
2048 else if (strncmp(optstr, "no-verify", optlen) == 0) {
2049 global.paranoia_parms.disable_extra_paranoia = 1;
2050 }
2051 else if (strncmp(optstr, "disable", optlen) == 0) {
2052 global.paranoia_parms.disable_paranoia = 1;
2053 }
2054 else if (strncmp(optstr, "help", optlen) == 0) {
2055 paranoia_usage();
2056 exit(NO_ERROR);
2057 }
2058 else {
2059 fprintf(stderr, "unknown option %s\n", optstr);
2060 paranoia_usage();
2061 exit(SYNTAX_ERROR);
2062 }
2063 optstr = np;
2064 }
2065 return 1;
2066 #else
2067 fputs("lib paranoia support is not configured!\n", stderr);
2068 return 0;
2069 #endif
2070 }
2071
2072
2073 /* and finally: the MAIN program */
2074 int main( argc, argv )
2075 int argc;
2076 char *argv [];
2077 {
2078 long lSector_p1;
2079 long sector_offset = 0;
2080 unsigned long endtrack = 1;
2081 double rectime = DURATION;
2082 int cd_index = -1;
2083 double int_part;
2084 int littleendian = -1;
2085 char *int_name;
2086 static char *user_sound_device = "";
2087 char * env_p;
2088 int tracks_included;
2089 int moreargs;
2090
2091 int_name = DEF_INTERFACE;
2092 audio_type = AUDIOTYPE;
2093 save_args(argc, argv);
2094
2095 /* init global variables */
2096 init_globals();
2097 {
2098 int am_i_cdda2wav;
2099 /* When being invoked as list_audio_tracks, just dump a list of
2100 audio tracks. */
2101 am_i_cdda2wav = !(strlen(argv[0]) >= sizeof("list_audio_tracks")-1
2102 && !strcmp(argv[0]+strlen(argv[0])+1-sizeof("list_audio_tracks"),"list_audio_tracks"));
2103 if (!am_i_cdda2wav) global.verbose = SHOW_JUSTAUDIOTRACKS;
2104 }
2105 /* Control those set-id privileges... */
2106 initsecurity();
2107
2108 env_p = getenv("CDDA_DEVICE");
2109 if (env_p != NULL) {
2110 global.dev_name = env_p;
2111 }
2112
2113 env_p = getenv("CDDBP_SERVER");
2114 if (env_p != NULL) {
2115 global.cddbp_server = env_p;
2116 }
2117
2118 env_p = getenv("CDDBP_PORT");
2119 if (env_p != NULL) {
2120 global.cddbp_port = env_p;
2121 }
2122
2123 {
2124 int cac;
2125 char *const*cav;
2126
2127 BOOL version = FALSE;
2128 BOOL help = FALSE;
2129 char *channels = NULL;
2130 int irate = -1;
2131 char *divider = NULL;
2132 char *trackspec = NULL;
2133 char *duration = NULL;
2134
2135 char *oendianess = NULL;
2136 char *cendianess = NULL;
2137 int cddbp = -1;
2138 BOOL stereo = FALSE;
2139 BOOL mono = FALSE;
2140 BOOL domax = FALSE;
2141 BOOL dump_rates = FALSE;
2142 int userverbose = -1;
2143 long paraopts = 0;
2144
2145 cac = argc;
2146 cav = argv;
2147 cac--;
2148 cav++;
2149 if (getargs(&cac, &cav, opts
2150 , &global.paranoia_selected
2151 , handle_paranoia_opts, &paraopts
2152 , &version
2153 , &help, &help
2154
2155 , &global.no_file, &global.no_file
2156 , &dump_rates, &dump_rates
2157 , &bulk, &bulk, &bulk
2158 , &global.scsi_verbose, &global.scsi_verbose
2159
2160 , &global.findminmax, &global.findminmax
2161 , &global.findmono, &global.findmono
2162 , &global.no_infofile, &global.no_infofile
2163
2164 , &global.deemphasize, &global.deemphasize
2165 , &global.just_the_toc, &global.just_the_toc
2166 , &global.scsi_silent, &global.scsi_silent
2167
2168 , &global.cddbp_server, &global.cddbp_port
2169 , &global.scanbus
2170 , &global.dev_name, &global.dev_name, &global.dev_name
2171 , &global.aux_name, &global.aux_name
2172 , &int_name, &int_name
2173 , &audio_type, &audio_type
2174
2175 , &oendianess, &oendianess
2176 , &cendianess, &cendianess
2177 , &global.userspeed, &global.userspeed
2178
2179 , &global.playback_rate, &global.playback_rate
2180 , &global.md5blocksize, &global.md5blocksize
2181 , &global.useroverlap, &global.useroverlap
2182 , &user_sound_device, &user_sound_device
2183
2184 , &cddbp, &cddbp
2185 , &channels, &channels
2186 , &bits, &bits
2187 , &irate, &irate
2188 , &global.gui, &global.gui
2189
2190 , &divider, &divider
2191 , &trackspec, &trackspec
2192 , &cd_index, &cd_index
2193 , &duration, &duration
2194 , &sector_offset, &sector_offset
2195
2196 , &global.nsectors, &global.nsectors
2197 , handle_verbose_opts, &userverbose
2198 , handle_verbose_opts, &userverbose
2199 , &global.buffers, &global.buffers
2200
2201 , &stereo, &stereo
2202 , &mono, &mono
2203 , &waitforsignal, &waitforsignal
2204 , &global.echo, &global.echo
2205 , &global.quiet, &global.quiet
2206 , &domax, &domax
2207
2208 ) < 0) {
2209 errmsgno(EX_BAD, "Bad Option: %s.\n", cav[0]);
2210 fputs ("use 'cdda2wav -help' to get more information.\n", stderr);
2211 exit (SYNTAX_ERROR);
2212 }
2213 if (getfiles(&cac, &cav, opts) == 0)
2214 /* No more file type arguments */;
2215 moreargs = cav - argv;
2216 if (version) {
2217 fputs ("cdda2wav version ", stderr);
2218 fputs (VERSION, stderr);
2219 fputs ("\n"
2220 "NOTE: modified version of the cdrkit suite, differs from the original\n", stderr);
2221 exit (NO_ERROR);
2222 }
2223 if (help) {
2224 usage(1);
2225 }
2226 if (!global.scanbus)
2227 cdr_defaults(&global.dev_name, NULL, NULL, NULL);
2228 if (dump_rates) { /* list available rates */
2229 int ii;
2230
2231 fputs("\
2232 Available rates are:\n\
2233 Rate Divider Rate Divider Rate Divider Rate Divider\n\
2234 " , stderr );
2235 for (ii = 1; ii <= 44100 / 880 / 2; ii++) {
2236 long i2 = ii;
2237 fprintf(stderr, "%7.1f %2ld %7.1f %2ld.5 ",
2238 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
2239 i2 += 25;
2240 fprintf(stderr, "%7.1f %2ld %7.1f %2ld.5\n",
2241 44100.0/i2, i2, 44100.0/(i2+0.5), i2);
2242 i2 -= 25;
2243 }
2244 exit(NO_ERROR);
2245 }
2246 if (channels) {
2247 if (*channels == 's') {
2248 global.channels = 2;
2249 global.swapchannels = 1;
2250 } else {
2251 global.channels = strtol(channels, NULL, 10);
2252 }
2253 }
2254 if (irate >= 0) {
2255 rate = irate;
2256 }
2257 if (divider) {
2258 double divider_d;
2259 divider_d = strtod(divider , NULL);
2260 if (divider_d > 0.0) {
2261 rate = 44100.0 / divider_d;
2262 } else {
2263 fputs("E option -divider requires a nonzero, positive argument.\nSee -dump-rates.", stderr);
2264 exit(SYNTAX_ERROR);
2265 }
2266 }
2267 if (trackspec) {
2268 char * endptr;
2269 char * endptr2;
2270 track = strtoul(trackspec, &endptr, 10 );
2271 endtrack = strtoul(endptr, &endptr2, 10 );
2272 if (endptr2 == endptr) {
2273 endtrack = track;
2274 } else if (track == endtrack) {
2275 bulk = -1;
2276 }
2277 }
2278 if (duration) {
2279 char *end_ptr = NULL;
2280 rectime = strtod(duration, &end_ptr );
2281 if (*end_ptr == 'f') {
2282 rectime = rectime / 75.0;
2283 /* TODO: add an absolute end of recording. */
2284 #if 0
2285 } else if (*end_ptr == 'F') {
2286 rectime = rectime / 75.0;
2287 #endif
2288 } else if (*end_ptr != '\0') {
2289 rectime = -1.0;
2290 }
2291 }
2292 if (oendianess) {
2293 if (strcasecmp(oendianess, "little") == 0) {
2294 global.outputendianess = LITTLE;
2295 } else if (strcasecmp(oendianess, "big") == 0) {
2296 global.outputendianess = BIG;
2297 } else {
2298 usage2("wrong parameter '%s' for option -E", oendianess);
2299 }
2300 }
2301 if (cendianess) {
2302 if (strcasecmp(cendianess, "little") == 0) {
2303 littleendian = 1;
2304 } else if (strcasecmp(cendianess, "big") == 0) {
2305 littleendian = 0;
2306 } else if (strcasecmp(cendianess, "guess") == 0) {
2307 littleendian = -2;
2308 } else {
2309 usage2("wrong parameter '%s' for option -C", cendianess);
2310 }
2311 }
2312 if (cddbp >= 0) {
2313 global.cddbp = 1 + cddbp;
2314 }
2315 if (stereo) {
2316 global.channels = 2;
2317 }
2318 if (mono) {
2319 global.channels = 1;
2320 global.need_hostorder = 1;
2321 }
2322 if (global.echo) {
2323 #ifdef ECHO_TO_SOUNDCARD
2324 if (global.playback_rate != 100) {
2325 RestrictPlaybackRate( global.playback_rate );
2326 }
2327 global.need_hostorder = 1;
2328 #else
2329 fprintf(stderr, "There is no sound support compiled into %s.\n",argv[0]);
2330 global.echo = 0;
2331 #endif
2332 }
2333 if (global.quiet) {
2334 global.verbose = 0;
2335 }
2336 if (domax) {
2337 global.channels = 2; bits = 16; rate = 44100;
2338 }
2339 if (global.findminmax) {
2340 global.need_hostorder = 1;
2341 }
2342 if (global.deemphasize) {
2343 global.need_hostorder = 1;
2344 }
2345 if (global.just_the_toc) {
2346 global.verbose = SHOW_MAX;
2347 bulk = 1;
2348 }
2349 if (global.gui) {
2350 #ifdef Thomas_will_es
2351 global.no_file = 1;
2352 global.no_infofile = 1;
2353 global.verbose = SHOW_MAX;
2354 #endif
2355 global.no_cddbfile = 1;
2356 }
2357 if (global.no_file) {
2358 global.no_infofile = 1;
2359 global.no_cddbfile = 1;
2360 }
2361 if (global.no_infofile) {
2362 global.no_cddbfile = 1;
2363 }
2364 if (global.md5blocksize) {
2365 #ifdef MD5_SIGNATURES
2366 fputs("MD5 signatures are currently broken! Sorry\n", stderr);
2367 #else
2368 fputs("The option MD5 signatures is not configured!\n", stderr);
2369 #endif
2370 }
2371 if (user_sound_device) {
2372 #ifndef ECHO_TO_SOUNDCARD
2373 fputs("There is no sound support configured!\n", stderr);
2374 #endif
2375 }
2376 if (global.paranoia_selected) {
2377 global.useroverlap = 0;
2378 }
2379 if (userverbose >= 0) {
2380 global.verbose = userverbose;
2381 }
2382 }
2383
2384 /* check all parameters */
2385 if (global.buffers < 1) {
2386 usage2("Incorrect buffer setting: %d", global.buffers);
2387 }
2388
2389 if (global.nsectors < 1) {
2390 usage2("Incorrect nsectors setting: %d", global.nsectors);
2391 }
2392
2393 if (global.verbose < 0 || global.verbose > SHOW_MAX) {
2394 usage2("Incorrect verbose level setting: %d",global.verbose);
2395 }
2396 if (global.verbose == 0) global.quiet = 1;
2397
2398 if ( rectime < 0.0 ) {
2399 usage2("Incorrect recording time setting: %d.%02d",
2400 (int)rectime, (int)(rectime*100+0.5) % 100);
2401 }
2402
2403 if ( global.channels != 1 && global.channels != 2 ) {
2404 usage2("Incorrect channel setting: %d",global.channels);
2405 }
2406
2407 if ( bits != 8 && bits != 12 && bits != 16 ) {
2408 usage2("Incorrect bits_per_sample setting: %d",bits);
2409 }
2410
2411 if ( rate < 827.0 || rate > 44100.0 ) {
2412 usage2("Incorrect sample rate setting: %d.%02d",
2413 (int)rate, ((int)rate*100) % 100);
2414 }
2415
2416 int_part = (double)(long) (2*44100.0 / rate);
2417
2418 if (2*44100.0 / rate - int_part >= 0.5 ) {
2419 int_part += 1.0;
2420 fprintf( stderr, "Nearest available sample rate is %d.%02d Hertz\n",
2421 2*44100 / (int)int_part,
2422 (2*4410000 / (int)int_part) % 100);
2423 }
2424 Halved = ((int) int_part) & 1;
2425 rate = 2*44100.0 / int_part;
2426 undersampling = (int) int_part / 2.0;
2427 samples_to_do = undersampling;
2428
2429 if (!strcmp((char *)int_name,"generic_scsi"))
2430 interface = GENERIC_SCSI;
2431 else if (!strcmp((char *)int_name,"cooked_ioctl"))
2432 interface = COOKED_IOCTL;
2433 else {
2434 usage2("Incorrect interface setting: %s",int_name);
2435 }
2436
2437 /* check * init audio file */
2438 if (!strncmp(audio_type,"wav",3)) {
2439 global.audio_out = &wavsound;
2440 } else if (!strncmp(audio_type, "sun", 3) || !strncmp(audio_type, "au", 2)) {
2441 /* Enhanced compatibility */
2442 audio_type = "au";
2443 global.audio_out = &sunsound;
2444 } else if (!strncmp(audio_type, "cdr", 3) ||
2445 !strncmp(audio_type, "raw", 3)) {
2446 global.audio_out = &rawsound;
2447 } else if (!strncmp(audio_type, "aiff", 4)) {
2448 global.audio_out = &aiffsound;
2449 } else if (!strncmp(audio_type, "aifc", 4)) {
2450 global.audio_out = &aifcsound;
2451 #ifdef USE_LAME
2452 } else if (!strncmp(audio_type, "mp3", 3)) {
2453 global.audio_out = &mp3sound;
2454 if (!global.quiet) {
2455 unsigned char Lame_version[20];
2456
2457 fetch_lame_version(Lame_version);
2458 fprintf(stderr, "Using LAME version %s.\n", Lame_version);
2459 }
2460 if (bits < 9) {
2461 bits = 16;
2462 fprintf(stderr, "Warning: sample size forced to 16 bit for MP3 format.\n");
2463 }
2464 #endif /* USE_LAME */
2465 } else {
2466 usage2("Incorrect audio type setting: %3s", audio_type);
2467 }
2468
2469 if (bulk == -1) bulk = 0;
2470
2471 global.need_big_endian = global.audio_out->need_big_endian;
2472 if (global.outputendianess != NONE)
2473 global.need_big_endian = global.outputendianess == BIG;
2474
2475 if (global.no_file) global.fname_base[0] = '\0';
2476
2477 if (!bulk) {
2478 strcat(global.fname_base, ".");
2479 strcat(global.fname_base, audio_type);
2480 }
2481
2482 /* If we need to calculate with samples or write them to a soundcard,
2483 * we need a conversion to host byte order.
2484 */
2485 if (global.channels != 2
2486 || bits != 16
2487 || rate != 44100)
2488 global.need_hostorder = 1;
2489
2490 /* Bad hack!!
2491 * Remove for release 2.0
2492 * this is a bug compatibility feature.
2493 */
2494 if (global.gui && global.verbose == SHOW_TOC)
2495 global.verbose |= SHOW_STARTPOSITIONS | SHOW_SUMMARY | SHOW_TITLES;
2496
2497 /*
2498 * all options processed.
2499 * Now a file name per track may follow
2500 */
2501 argc2 = argc3 = argc - moreargs;
2502 argv2 = argv + moreargs;
2503 if ( moreargs < argc ) {
2504 if (!strcmp(argv[moreargs],"-")) {
2505 #ifdef NEED_O_BINARY
2506 setmode(fileno(stdout), O_BINARY);
2507 #endif
2508 global.audio = dup (fileno(stdout));
2509 strncpy( global.fname_base, "standard_output", sizeof(global.fname_base) );
2510 global.fname_base[sizeof(global.fname_base)-1]=0;
2511 } else if (!is_fifo(argv[moreargs])) {
2512 /* we do have at least one argument */
2513 global.multiname = 1;
2514 }
2515 }
2516
2517 #define SETSIGHAND(PROC, SIG, SIGNAME) if (signal(SIG, PROC) == SIG_ERR) \
2518 { fprintf(stderr, "cannot set signal %s handler\n", SIGNAME); exit(SETSIG_ERROR); }
2519 SETSIGHAND(exit_wrapper, SIGINT, "SIGINT")
2520 SETSIGHAND(exit_wrapper, SIGQUIT, "SIGQUIT")
2521 SETSIGHAND(exit_wrapper, SIGTERM, "SIGTERM")
2522 SETSIGHAND(exit_wrapper, SIGHUP, "SIGHUP")
2523
2524 SETSIGHAND(set_nonforked, SIGPIPE, "SIGPIPE")
2525
2526 /* setup interface and open cdrom device */
2527 /* request sychronization facilities and shared memory */
2528 SetupInterface( );
2529
2530 /* use global.useroverlap to set our overlap */
2531 if (global.useroverlap != -1)
2532 global.overlap = global.useroverlap;
2533
2534 /* check for more valid option combinations */
2535
2536 if (global.nsectors < 1+global.overlap) {
2537 fprintf( stderr, "Warning: Setting #nsectors to minimum of %d, due to jitter correction!\n", global.overlap+1);
2538 global.nsectors = global.overlap+1;
2539 }
2540
2541 if (global.overlap > 0 && global.buffers < 2) {
2542 fprintf( stderr, "Warning: Setting #buffers to minimum of 2, due to jitter correction!\n");
2543 global.buffers = 2;
2544 }
2545
2546 /* Value of 'nsectors' must be defined here */
2547
2548 global.shmsize = 0;
2549 #ifdef USE_PARANOIA
2550 while (global.shmsize < sizeof (struct paranoia_statistics))
2551 global.shmsize += global.pagesize;
2552 #endif
2553 global.shmsize += 10*global.pagesize; /* XXX Der Speicherfehler ist nicht in libparanoia sondern in cdda2wav :-( */
2554 global.shmsize += HEADER_SIZE + ENTRY_SIZE_PAGE_AL * global.buffers;
2555
2556 #if defined (HAVE_FORK_AND_SHAREDMEM)
2557 /*
2558 * The (void *) cast is to avoid a GCC warning like:
2559 * warning: dereferencing type-punned pointer will break strict-aliasing rules
2560 * which does not apply to this code. (void *) introduces a compatible
2561 * intermediate type in the cast list.
2562 */
2563 he_fill_buffer = request_shm_sem(global.shmsize, (unsigned char **)(void *)&he_fill_buffer);
2564 if (he_fill_buffer == NULL) {
2565 fprintf( stderr, "no shared memory available!\n");
2566 exit(SHMMEM_ERROR);
2567 }
2568 #else /* do not have fork() and shared memory */
2569 he_fill_buffer = malloc(global.shmsize);
2570 if (he_fill_buffer == NULL) {
2571 fprintf( stderr, "no buffer memory available!\n");
2572 exit(NOMEM_ERROR);
2573 }
2574 #endif
2575 #ifdef USE_PARANOIA
2576 {
2577 int i = 0;
2578
2579 para_stat = (struct paranoia_statistics *)he_fill_buffer;
2580 while (i < sizeof (struct paranoia_statistics)) {
2581 i += global.pagesize;
2582 he_fill_buffer += global.pagesize;
2583 global.shmsize -= global.pagesize;
2584 }
2585 }
2586 #endif
2587
2588 if (global.verbose != 0)
2589 fprintf(stderr,
2590 "%u bytes buffer memory requested, %d buffers, %d sectors\n",
2591 global.shmsize, global.buffers, global.nsectors);
2592
2593 /* initialize pointers into shared memory segment */
2594 last_buffer = he_fill_buffer + 1;
2595 total_segments_read = (unsigned long *) (last_buffer + 1);
2596 total_segments_written = total_segments_read + 1;
2597 child_waits = (int *) (total_segments_written + 1);
2598 parent_waits = child_waits + 1;
2599 in_lendian = parent_waits + 1;
2600 eorecording = in_lendian + 1;
2601 *total_segments_read = *total_segments_written = 0;
2602 nSamplesToDo = (unsigned long *)(eorecording + 1);
2603 *eorecording = 0;
2604 *in_lendian = global.in_lendian;
2605
2606 set_total_buffers(global.buffers, sem_id);
2607
2608
2609 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
2610 atexit ( free_sem );
2611 #endif
2612
2613 /*
2614 * set input endian default
2615 */
2616 if (littleendian != -1)
2617 *in_lendian = littleendian;
2618
2619 /* get table of contents */
2620 cdtracks = ReadToc();
2621 if (cdtracks == 0) {
2622 fprintf(stderr, "No track in table of contents! Aborting...\n");
2623 exit(MEDIA_ERROR);
2624 }
2625
2626 calc_cddb_id();
2627 calc_cdindex_id();
2628
2629 #if 1
2630 Check_Toc();
2631 #endif
2632
2633 if (ReadTocText != NULL && FirstAudioTrack () != -1) {
2634 ReadTocText(get_scsi_p());
2635 handle_cdtext();
2636 }
2637 if ( global.verbose == SHOW_JUSTAUDIOTRACKS ) {
2638 unsigned int z;
2639
2640 for (z = 0; z < cdtracks; z++)
2641 if (Get_Datatrack(z) == 0)
2642 printf("%02d\t%06ld\n", Get_Tracknumber(z), Get_AudioStartSector(z));
2643 exit(NO_ERROR);
2644 }
2645
2646 if ( global.verbose != 0 ) {
2647 fputs( "#Cdda2wav version ", stderr );
2648 fputs( VERSION, stderr );
2649 #if defined USE_POSIX_PRIORITY_SCHEDULING || defined HAVE_SYS_PRIOCNTL_H
2650 fputs( ", real time sched.", stderr );
2651 #endif
2652 #if defined ECHO_TO_SOUNDCARD
2653 fputs( ", soundcard", stderr );
2654 #endif
2655 #if defined USE_PARANOIA
2656 fputs( ", libparanoia", stderr );
2657 #endif
2658 fputs( " support\n", stderr );
2659 }
2660
2661 FixupTOC(cdtracks + 1);
2662
2663 #if 0
2664 if (!global.paranoia_selected) {
2665 error("NICE\n");
2666 /* try to get some extra kicks */
2667 priv_on();
2668 needroot(0);
2669 #if defined HAVE_SETPRIORITY
2670 setpriority(PRIO_PROCESS, 0, -20);
2671 #else
2672 # if defined(HAVE_NICE) && (HAVE_NICE == 1)
2673 nice(-20);
2674 # endif
2675 #endif
2676 priv_off();
2677 dontneedroot();
2678 }
2679 #endif
2680
2681 /* switch cdrom to audio mode */
2682 EnableCdda (get_scsi_p(), 1, CD_FRAMESIZE_RAW);
2683
2684 atexit ( CloseAll );
2685
2686 DisplayToc();
2687 if ( FirstAudioTrack () == -1 ) {
2688 if (no_disguised_audiotracks()) {
2689 FatalError ( "This disk has no audio tracks\n" );
2690 }
2691 }
2692
2693 Read_MCN_ISRC();
2694
2695 /* check if start track is in range */
2696 if ( track < 1 || track > cdtracks ) {
2697 usage2("Incorrect start track setting: %d",track);
2698 }
2699
2700 /* check if end track is in range */
2701 if ( endtrack < track || endtrack > cdtracks ) {
2702 usage2("Incorrect end track setting: %ld",endtrack);
2703 }
2704
2705 do {
2706 lSector = Get_AudioStartSector ( track );
2707 lSector_p1 = Get_EndSector ( track ) + 1;
2708
2709 if ( lSector < 0 ) {
2710 if ( bulk == 0 ) {
2711 FatalError ( "Track %d not found\n", track );
2712 } else {
2713 fprintf(stderr, "Skipping data track %d...\n", track);
2714 if (endtrack == track) endtrack++;
2715 track++;
2716 }
2717 }
2718 } while (bulk != 0 && track <= cdtracks && lSector < 0);
2719
2720 if ((global.illleadout_cd == 0 || global.reads_illleadout != 0) && cd_index != -1) {
2721 if (global.verbose && !global.quiet) {
2722 global.verbose |= SHOW_INDICES;
2723 }
2724 sector_offset += ScanIndices( track, cd_index, bulk );
2725 } else {
2726 cd_index = 1;
2727 if (global.deemphasize || (global.verbose & SHOW_INDICES)) {
2728 ScanIndices( track, cd_index, bulk );
2729 }
2730 }
2731
2732 lSector += sector_offset;
2733 /* check against end sector of track */
2734 if ( lSector >= lSector_p1 ) {
2735 fprintf(stderr, "W Sector offset %lu exceeds track size (ignored)\n", sector_offset );
2736 lSector -= sector_offset;
2737 }
2738
2739 if ( lSector < 0L ) {
2740 fputs( "Negative start sector! Set to zero.\n", stderr );
2741 lSector = 0L;
2742 }
2743
2744 lSector_p2 = Get_LastSectorOnCd( track );
2745 if (bulk == 1 && track == endtrack && rectime == 0.0)
2746 rectime = 99999.0;
2747 if ( rectime == 0.0 ) {
2748 /* set time to track time */
2749 *nSamplesToDo = (lSector_p1 - lSector) * CD_FRAMESAMPLES;
2750 rectime = (lSector_p1 - lSector) / 75.0;
2751 if (CheckTrackrange( track, endtrack) == 1) {
2752 lSector_p2 = Get_EndSector ( endtrack ) + 1;
2753
2754 if (lSector_p2 >= 0) {
2755 rectime = (lSector_p2 - lSector) / 75.0;
2756 *nSamplesToDo = (long)(rectime*44100.0 + 0.5);
2757 } else {
2758 fputs( "End track is no valid audio track (ignored)\n", stderr );
2759 }
2760 } else {
2761 fputs( "Track range does not consist of audio tracks only (ignored)\n", stderr );
2762 }
2763 } else {
2764 /* Prepare the maximum recording duration.
2765 * It is defined as the biggest amount of
2766 * adjacent audio sectors beginning with the
2767 * specified track/index/offset. */
2768
2769 if ( rectime > (lSector_p2 - lSector) / 75.0 ) {
2770 rectime = (lSector_p2 - lSector) / 75.0;
2771 lSector_p1 = lSector_p2;
2772 }
2773
2774 /* calculate # of samples to read */
2775 *nSamplesToDo = (long)(rectime*44100.0 + 0.5);
2776 }
2777
2778 global.OutSampleSize = (1+bits/12);
2779 if (*nSamplesToDo/undersampling == 0L) {
2780 usage2("Time interval is too short. Choose a duration greater than %d.%02d secs!",
2781 undersampling/44100, (int)(undersampling/44100) % 100);
2782 }
2783 if ( moreargs < argc ) {
2784 if (!strcmp(argv[moreargs],"-") || is_fifo(argv[moreargs])) {
2785 /*
2786 * pipe mode
2787 */
2788 if (bulk == 1) {
2789 fprintf(stderr, "W Bulk mode is disabled while outputting to a %spipe\n",
2790 is_fifo(argv[moreargs]) ? "named " : "");
2791 bulk = 0;
2792 }
2793 global.no_cddbfile = 1;
2794 }
2795 }
2796 if (global.no_infofile == 0) {
2797 global.no_infofile = 1;
2798 if (global.channels == 1 || bits != 16 || rate != 44100) {
2799 fprintf(stderr, "W Sample conversions disable generation of info files!\n");
2800 } else if (waitforsignal == 1) {
2801 fprintf(stderr, "W Option -w 'wait for signal' disables generation of info files!\n");
2802 } else if (sector_offset != 0) {
2803 fprintf(stderr, "W Using an start offset (option -o) disables generation of info files!\n");
2804 } else if (!bulk &&
2805 !((lSector == Get_AudioStartSector(track)) &&
2806 ((long)(lSector + rectime*75.0 + 0.5) == Get_EndSector(track) + 1))) {
2807 fprintf(stderr, "W Duration is not set for complete tracks (option -d), this disables generation\n of info files!\n");
2808 } else {
2809 global.no_infofile = 0;
2810 }
2811 }
2812
2813 SamplesToWrite = *nSamplesToDo*2/(int)int_part;
2814
2815 {
2816 int first = FirstAudioTrack();
2817 tracks_included = Get_Track(
2818 (unsigned) (lSector + *nSamplesToDo/CD_FRAMESAMPLES -1))
2819 - max((int)track,first) +1;
2820 }
2821
2822 if (global.multiname != 0 && moreargs + tracks_included > argc) {
2823 global.multiname = 0;
2824 }
2825
2826 if ( !waitforsignal ) {
2827
2828 #ifdef INFOFILES
2829 if (!global.no_infofile) {
2830 int i;
2831
2832 for (i = track; i < (int)track + tracks_included; i++) {
2833 unsigned minsec, maxsec;
2834 char *tmp_fname;
2835
2836 /* build next filename */
2837
2838 tmp_fname = get_next_name();
2839 if (tmp_fname != NULL)
2840 strncpy( global.fname_base, tmp_fname, sizeof(global.fname_base)-8 );
2841 global.fname_base[sizeof(global.fname_base)-1]=0;
2842 minsec = max(lSector, Get_AudioStartSector(i));
2843 maxsec = min(lSector + rectime*75.0 + 0.5, 1+Get_EndSector(i));
2844 if ((int)minsec == Get_AudioStartSector(i) &&
2845 (int)maxsec == 1+Get_EndSector(i)) {
2846 write_info_file(global.fname_base,i,(maxsec-minsec)*CD_FRAMESAMPLES, bulk && global.multiname == 0);
2847 } else {
2848 fprintf(stderr,
2849 "Partial length copy for track %d, no info file will be generated for this track!\n", i);
2850 }
2851 if (!bulk) break;
2852 }
2853 reset_name_iterator();
2854 }
2855 #endif
2856
2857 }
2858
2859 if (global.just_the_toc) exit(NO_ERROR);
2860
2861 #ifdef ECHO_TO_SOUNDCARD
2862 if (user_sound_device[0] != '\0') {
2863 set_snd_device(user_sound_device);
2864 }
2865 init_soundcard(rate, bits);
2866 #endif /* ECHO_TO_SOUNDCARD */
2867
2868 if (global.userspeed > -1)
2869 global.speed = global.userspeed;
2870
2871 if (global.speed != 0 && SelectSpeed != NULL) {
2872 SelectSpeed(get_scsi_p(), global.speed);
2873 }
2874
2875 current_track = track;
2876
2877 if ( !global.no_file ) {
2878 {
2879 char *myfname;
2880
2881 myfname = get_next_name();
2882
2883 if (myfname != NULL) {
2884 strncpy( global.fname_base, myfname, sizeof(global.fname_base)-8 );
2885 global.fname_base[sizeof(global.fname_base)-1]=0;
2886 }
2887 }
2888
2889 /* strip audio_type extension */
2890 {
2891 char *cp = global.fname_base;
2892
2893 cp = strrchr(cp, '.');
2894 if (cp == NULL) {
2895 cp = global.fname_base + strlen(global.fname_base);
2896 }
2897 *cp = '\0';
2898 }
2899 if (bulk && global.multiname == 0) {
2900 sprintf(fname, "%s_%02u.%s",global.fname_base,current_track,audio_type);
2901 } else {
2902 sprintf(fname, "%s.%s",global.fname_base,audio_type);
2903 }
2904
2905 OpenAudio( fname, rate, bits, global.channels,
2906 (unsigned)(SamplesToWrite*global.OutSampleSize*global.channels),
2907 global.audio_out);
2908 }
2909
2910 global.Remainder = (75 % global.nsectors)+1;
2911
2912 global.sh_bits = 16 - bits; /* shift counter */
2913
2914 global.iloop = *nSamplesToDo;
2915 if (Halved && (global.iloop&1))
2916 global.iloop += 2;
2917
2918 BeginAtSample = lSector * CD_FRAMESAMPLES;
2919
2920 #if 1
2921 if ( (global.verbose & SHOW_SUMMARY) && !global.just_the_toc &&
2922 (global.reads_illleadout == 0 ||
2923 lSector+*nSamplesToDo/CD_FRAMESAMPLES
2924 <= (unsigned) Get_AudioStartSector(cdtracks-1))) {
2925
2926 fprintf(stderr, "samplefile size will be %lu bytes.\n",
2927 global.audio_out->GetHdrSize() +
2928 global.audio_out->InSizeToOutSize(SamplesToWrite*global.OutSampleSize*global.channels) );
2929 fprintf (stderr, "recording %d.%04d seconds %s with %d bits @ %5d.%01d Hz"
2930 ,(int)rectime , (int)(rectime * 10000) % 10000,
2931 global.channels == 1 ? "mono":"stereo", bits, (int)rate, (int)(rate*10)%10);
2932 if (!global.no_file && *global.fname_base)
2933 fprintf(stderr, " ->'%s'...", global.fname_base );
2934 fputs("\n", stderr);
2935 }
2936 #endif
2937
2938 #if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES)
2939 #else
2940 init_pipes();
2941 #endif
2942
2943 #ifdef USE_PARANOIA
2944 if (global.paranoia_selected) {
2945 long paranoia_mode;
2946
2947 global.cdp = paranoia_init(get_scsi_p(), global.nsectors);
2948
2949 if (global.paranoia_parms.overlap >= 0) {
2950 int overlap = global.paranoia_parms.overlap;
2951
2952 if (overlap > global.nsectors - 1)
2953 overlap = global.nsectors - 1;
2954 paranoia_overlapset(global.cdp, overlap);
2955 }
2956 /*
2957 * Default to a minimum of dynamic overlapping == 0.5 sectors.
2958 * If we don't do this, we get the default from libparanoia
2959 * which is approx. 0.1.
2960 */
2961 if (global.paranoia_parms.mindynoverlap < 0)
2962 paranoia_dynoverlapset(global.cdp, CD_FRAMEWORDS/2, -1);
2963 paranoia_dynoverlapset(global.cdp,
2964 global.paranoia_parms.mindynoverlap * CD_FRAMEWORDS,
2965 global.paranoia_parms.maxdynoverlap * CD_FRAMEWORDS);
2966
2967 paranoia_mode = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP;
2968
2969 if (global.paranoia_parms.disable_paranoia) {
2970 paranoia_mode = PARANOIA_MODE_DISABLE;
2971 }
2972 if (global.paranoia_parms.disable_extra_paranoia) {
2973 paranoia_mode |= PARANOIA_MODE_OVERLAP;
2974 paranoia_mode &= ~PARANOIA_MODE_VERIFY;
2975 }
2976 /* not yet implemented */
2977 if (global.paranoia_parms.disable_scratch_detect) {
2978 paranoia_mode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR);
2979 }
2980 /* not yet implemented */
2981 if (global.paranoia_parms.disable_scratch_repair) {
2982 paranoia_mode &= ~PARANOIA_MODE_REPAIR;
2983 }
2984
2985 paranoia_modeset(global.cdp, paranoia_mode);
2986 if (global.verbose)
2987 fprintf(stderr, "using lib paranoia for reading.\n");
2988 paranoia_seek(global.cdp, lSector, SEEK_SET);
2989 paranoia_reset();
2990 }
2991 #endif
2992 #if defined(HAVE_FORK_AND_SHAREDMEM)
2993
2994 /* Everything is set up. Now fork and let one process read cdda sectors
2995 and let the other one store them in a wav file */
2996
2997 /* forking */
2998 child_pid = fork();
2999 if (child_pid > 0 && global.gui > 0 && global.verbose > 0)
3000 fprintf( stderr, "child pid is %d\n", child_pid);
3001
3002 /*********************** fork **************************************/
3003 if (child_pid == 0) {
3004 /* child WRITER section */
3005
3006 #ifdef HAVE_AREAS
3007 /* Under BeOS a fork() with shared memory does not work as
3008 * it does under System V Rel. 4. The mapping of the child
3009 * works with copy on write semantics, so changes do not propagate
3010 * back and forth. The existing mapping has to be deleted
3011 * and replaced by an clone without copy on write semantics.
3012 * This is done with clone_area(...,B_CLONE_ADDRESS,...).
3013 * Thanks to file support.c from the postgreSQL project.
3014 */
3015 area_info inf;
3016 int32 cook = 0;
3017 /* iterate over all mappings to find our shared memory mapping. */
3018 while (get_next_area_info(0, &cook, &inf) == B_OK)
3019 {
3020 /* check the name of the mapping. */
3021 if (!strcmp(inf.name, AREA_NAME))
3022 {
3023 void *area_address;
3024 area_id area_parent;
3025
3026 /* kill the cow mapping. */
3027 area_address = inf.address;
3028 if (B_OK != delete_area(inf.area))
3029 {
3030 fprintf(stderr, "delete_area: no valid area.\n");
3031 exit(SHMMEM_ERROR);
3032 }
3033 /* get the parent mapping. */
3034 area_parent = find_area(inf.name);
3035 if (area_parent == B_NAME_NOT_FOUND)
3036 {
3037 fprintf(stderr, "find_area: no such area name.\n");
3038 exit(SHMMEM_ERROR);
3039 }
3040 /* clone the parent mapping without cow. */
3041 if (B_OK > clone_area("shm_child", &area_address, B_CLONE_ADDRESS,
3042 B_READ_AREA | B_WRITE_AREA, area_parent))
3043 {
3044 fprintf(stderr,"clone_area failed\n");
3045 exit(SHMMEM_ERROR);
3046 }
3047 }
3048 }
3049 #endif
3050 #ifdef __EMX__
3051 if (DosGetSharedMem(he_fill_buffer, 3)) {
3052 comerr("DosGetSharedMem() failed.\n");
3053 }
3054 #endif
3055 global.have_forked = 1;
3056 forked_write();
3057 #ifdef __EMX__
3058 DosFreeMem(he_fill_buffer);
3059 _exit(NO_ERROR);
3060 /* NOTREACHED */
3061 #endif
3062 exit_wrapper(NO_ERROR);
3063 /* NOTREACHED */
3064 } else if (child_pid > 0) {
3065 /* parent READER section */
3066
3067 global.have_forked = 1;
3068 switch_to_realtime_priority();
3069
3070 forked_read();
3071 #ifdef HAVE_AREAS
3072 {
3073 area_id aid;
3074 aid = find_area(AREA_NAME);
3075 if (aid < B_OK) {
3076 comerrno(aid, "find_area() failed.\n");
3077 }
3078 delete_area(aid);
3079 }
3080 #endif
3081 #ifdef __EMX__
3082 DosFreeMem(he_fill_buffer);
3083 #endif
3084 exit_wrapper(NO_ERROR);
3085 /* NOTREACHED */
3086 } else
3087 perror("fork error.");
3088
3089 #endif
3090 /* version without fork */
3091 {
3092 global.have_forked = 0;
3093 #if 0
3094 if (!global.paranoia_selected) {
3095 error("REAL\n");
3096 switch_to_realtime_priority();
3097 }
3098 #endif
3099 fprintf(stderr, "a nonforking version is running...\n");
3100 nonforked_loop();
3101 exit_wrapper(NO_ERROR);
3102 /* NOTREACHED */
3103 }
3104 #ifdef USE_PARANOIA
3105 if (global.paranoia_selected)
3106 paranoia_free(global.cdp);
3107 #endif
3108
3109 return 0;
3110 }

  ViewVC Help
Powered by ViewVC 1.1.5