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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.5