diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-12-31 05:04:42 +0400 |
commit | 71dc8760ff4de5f365330d1bc571d934deb54af9 (patch) | |
tree | 7346d42a282562a3937d82307012b5857d642ce6 /icedax | |
download | cdrkit-941fb342494d2b61ef5fd1870a4fa695d1c7fc69.tar.gz |
Imported Upstream version 1.1.11upstream/1.1.11upstream
Diffstat (limited to 'icedax')
65 files changed, 20861 insertions, 0 deletions
diff --git a/icedax/CMakeLists.txt b/icedax/CMakeLists.txt new file mode 100644 index 0000000..54c2e7d --- /dev/null +++ b/icedax/CMakeLists.txt @@ -0,0 +1,34 @@ +PROJECT (icedax C) +INCLUDE_DIRECTORIES(../include ../wodim ../libparanoia ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/include) +include(../include/AddScgBits.cmake) +include(../include/AddSchilyBits.cmake) +include(../include/AddNetworkBits.cmake) + +FIND_FILE (HAVE_SYS_SOUNDCARD_H sys/soundcard.h) +IF(HAVE_SYS_SOUNDCARD_H) + ADD_DEFINITIONS(-DHAVE_SYS_SOUNDCARD_H) +ENDIF(HAVE_SYS_SOUNDCARD_H) +FIND_FILE (HAVE_LINUX_SOUNDCARD_H linux/soundcard.h) +IF(HAVE_LINUX_SOUNDCARD_H) + ADD_DEFINITIONS(-DHAVE_LINUX_SOUNDCARD_H) +ENDIF(HAVE_LINUX_SOUNDCARD_H) + +FIND_LIBRARY(HAVE_LIBOSSAUDIO "ossaudio") +IF(HAVE_LIBOSSAUDIO) + LIST(APPEND EXTRA_LIBS "ossaudio") +ENDIF(HAVE_LIBOSSAUDIO) + +LIST(APPEND EXTRA_LIBS paranoia) +IF (WIN32) + LIST(APPEND EXTRA_LIBS winmm) +ENDIF (WIN32) + +LINK_DIRECTORIES(../librols ../libusal ../libparanoia) +ADD_EXECUTABLE (icedax aifc.c aiff.c base64.c icedax.c interface.c ioctl.c raw.c resample.c ringbuff.c scsi_cmds.c semshm.c setuid.c sha_func.c sndconfig.c sun.c toc.c wav.c) +TARGET_LINK_LIBRARIES(icedax wodimstuff ${EXTRA_LIBS}) +SET_TARGET_PROPERTIES(icedax PROPERTIES SKIP_BUILD_RPATH TRUE) + +INSTALL(TARGETS icedax DESTINATION bin) +INSTALL(PROGRAMS pitchplay readmult cdda2mp3 cdda2ogg DESTINATION bin) +INSTALL(FILES cdda2ogg.1 icedax.1 pitchplay.1 readmult.1 list_audio_tracks.1 DESTINATION ${MANSUBDIR}/man1) + diff --git a/icedax/Changelog b/icedax/Changelog new file mode 100644 index 0000000..e57a8c1 --- /dev/null +++ b/icedax/Changelog @@ -0,0 +1,570 @@ +210 Einträge +Fri Apr 6 15:58:32 2001 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.16 + bugfix symbolic constant 'linux' -> 'LINUX', code cleanup + +Sun Mar 11 17:55:25 2001 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.11 + schily changes + +Sun Mar 11 17:25:14 2001 Heiko Eissfeldt <heiko@colossus.escape.de> + * semshm.c 1.6 + change to new shared memory scheme. + +Mon Dec 25 11:13:42 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * config.h 1.3 + get rid of PRETEND_TO_USE, use ARGSUSED instead + +Sun Dec 10 16:49:56 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.10 + Large file type fix: u_char -> Uchar + +Sat Dec 9 23:41:42 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * Makefile 1.2 + add libraries for remote scsi + +Sat Dec 9 23:39:59 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.9 + read toc in msf AND lba format. Use mins,secs,frms fields. + +Sat Dec 9 23:38:25 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.h 1.6 + portability fix: change signed char to int for mins,secs,frms + +Sat Dec 9 23:37:18 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.9 + change mins, secs, frms to type int; use conversion function lba_2_msf + +Sat Dec 9 23:35:43 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.15 + add conversion function lba_2_msf + +Fri Dec 1 14:37:10 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.15 + change ReadToc_sim to define new toc struc members mins, secs, frms. + +Fri Dec 1 14:36:22 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.8 + change ReadToc to read in MSF as well as in LBA format. Store seperately. + +Fri Dec 1 14:35:04 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.h 1.5 + add seperate fields in toc structure: mins, secs, frms for + msf can hold different data than lba (as seen by dvds) + +Mon Nov 6 21:14:11 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.23 + fix from Joerg Schilling for better Cygwin old/new compatibility + +Wed Oct 25 23:48:02 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.22 + don't try to get cd text info on discs with data tracks only + +Wed Oct 25 23:47:20 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.14 + disable Read TOC cd text for Sony CRX100E reported by George Fisher (fisher@ssl.berkeley.edu) + +Tue Sep 19 21:30:57 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.21 + fix from js for wait() declarations + +Fri Sep 15 12:51:43 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.20 + adapt for Cygwin 1.0 header files + +Wed Sep 13 23:06:25 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.19 + * interface.c 1.13 + * scsi_cmds.c 1.7 + (r)scsi interface changes + +Sun Aug 20 17:29:02 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.6 + * cdda2wav.c 1.18 + * interface.c 1.12 + adapt for new libscsi + +Sat Jun 24 07:57:38 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.17 + use setpriority if available before nice + +Sat Jun 24 07:56:40 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.14 + ISRC hardening II + +Fri Jun 16 00:12:21 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * mycdrom.h 1.4 + bugfix: FreeBSD should get the ioctl interface again + +Fri Jun 16 00:11:39 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.8 + bugfix: FreeBSD ioctl should work again + +Sat Jun 10 22:27:43 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.13 + recorder id detection and extended character range for ISRC + +Fri Jun 2 08:56:22 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.11 + added schily header files + interface change for ReadCdRom* functions + now allocate always a SCSI structure for use of silent and verbose + thats it. + +Fri Jun 2 08:49:08 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.16 + added schily header files + major changes for cds with illegal leadout positions + moved nSamplesToDo into the shared memory segment + added exit wrapper for portability under Max-OS-X + cleaned up ring buffer handling + bugfix for silent mode (call DisplayToc and Read_MCN_ISRC was needed) + +Fri Jun 2 08:37:12 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.12 + added schily header files + made cd text detection more reliable for plextor/sony non-mmc drives + hardened cdda2wav against illegal ISRC codes + major changes for cds with illegal leadout positions + protected the index scan against illegal leadout positions + *** CHANGED *** 00/06/02 07:43:08 heiko + added schilys header files + +Fri Jun 2 08:33:44 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * aifc.c 1.4 + * aiff.c 1.4 + include schilys header files + +Fri Jun 2 08:32:28 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * semshm.c 1.5 + added schily headerfile + +Fri Jun 2 08:31:53 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.h 1.4 + interface change for ReadCdRom*. Return int instead of void + +Fri Jun 2 08:30:51 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.5 + interface change: Read* function do not exit the program, when + sectors could not be read. Instead they signal this through the return value. + +Fri Jun 2 08:28:37 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.h 1.3 + interface change: Read* functions now return number of sectors read + added myscsierr function for scsi result checking + +Fri Jun 2 08:26:46 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.7 + interface change: ReadCdrom and ReadCdromData return number of read sectors + schily include file added + default buffer size set to 8 sectors for ide on Linux + suppress errors when usalp->silent > 0 + +Fri Jun 2 07:39:55 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ringbuff.c 1.4 + added a pointer for the new shared memory reference eorecording + +Fri Jun 2 07:38:48 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ringbuff.h 1.4 + new variables in shared memory: + end_is_reached is set when the previously unknown leadout is encountered. + nSamplesToDo has been moved into shared memory to be visible for the writer. + +Fri Jun 2 07:36:11 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * local.cnf.in 1.3 + bugfixes: SunOS sound device, NetBSD inclusion of extralibs + +Fri Jun 2 07:34:37 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * configure.in 1.2 + bugfix. include detected libs in EXTRALIBS + +Fri Jun 2 07:29:12 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * global.h 1.4 + added two globals for detection of cds with illegal lead out positions + and one for a drive capability to read beyond the wrong leadout position. + +Tue May 2 21:41:40 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.9 + fixed an signedness warning for buffer pointer for WriteSound() + +Thu Apr 27 23:53:49 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.15 + -t4+4 -B now records only one track +4 is interpreted as a limit + +Sat Apr 22 23:37:57 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * setuid.c 1.3 + fixed a drop root forever bug, when we were currently nonroot + +Mon Apr 17 08:27:51 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.8 + fixed 'wait for signal' + +Mon Apr 17 08:27:23 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.14 + fixed info files generation, added warnings + +Mon Apr 17 08:26:37 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.11 + fixed empty title display + +Thu Apr 13 00:38:04 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.13 + added some consistency checks for info file generation + +Wed Apr 12 22:54:37 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.4 + fixed read cd text wrt reserved track/session field (now 0) + +Mon Apr 10 07:49:11 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * sndfile.h 1.3 + new interface methods for mp3 + +Thu Mar 30 00:03:38 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.10 + add isrc and mcn retrieval for cd-extra + +Wed Mar 29 23:12:09 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.9 + fixed a bug with gui-mode and quote() function usage + +Wed Mar 29 21:24:04 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.6 + allow for sun type ioctl even on non_suns (HAVE_SYS_CDIO_H) + +Wed Mar 29 21:21:51 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * mycdrom.h 1.3 + disable HAVE_IOCTL_INTERFACE even if HAVE_SYS_CDIO_H (for Mac OS X) + +Sun Mar 26 23:17:47 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.7 + change write call for sndfile to new sndfile method WriteSound + +Sun Mar 26 23:14:47 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.12 + variable name change 'fill_buffer' -> 'he_fill_buffer' + prepare for new output format mp3 with lame (disabled with #ifdef USE_LAME) + +Sun Mar 26 23:10:19 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ringbuff.c 1.3 + * ringbuff.h 1.3 + variable name change to avoid collision with fill_buffer from lame + +Sun Mar 26 23:09:14 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.h 1.3 + mask SCSI depend declarations with NO_SCSI_STUFF define + +Sun Mar 26 23:08:27 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.8 + fix an unimportant typo in resolve_id not active + +Sun Mar 26 22:14:53 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * aifc.c 1.3 + * aiff.c 1.3 + * raw.c 1.3 + * sun.c 1.3 + * wav.c 1.3 + prepared sndfile interface for additional functions needed for mp3 + +Tue Mar 21 21:42:10 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.10 + added the DEC RRD47 drive as not mmc/readCD capable + +Tue Mar 21 20:25:44 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.11 + fixed an cd extra detection bug + disabled .cddb and .cdindex file generation with --gui + +Tue Mar 21 20:22:26 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * Makefile.man 1.1 + date and time created 00/03/21 20:22:26 by heiko + +Tue Mar 21 20:17:28 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.7 + added cactus data shield copy protection recognition + fixed display for cd extra (track times) + fix for sony crx140s (delivers Qsubchannel position data in bcd instead of hex) + fixed screen output during index scan cosmetically + +Tue Mar 21 20:06:19 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.5 + added rough debugging messages for -V + fixed index scanning for Linux and FreeBSD + +Tue Mar 21 18:45:30 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.9 + included inquiry message, added rough ioctl debugging messages + +Sun Feb 20 23:07:27 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.6 + fixed a compiler warning + +Sun Feb 20 23:07:16 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.8 + fixed missing global.in_lendian substitutes + +Thu Feb 17 22:00:32 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.10 + made deemphasizing automatic + adjusted info files accordingly + allow non-root users to fail on realtimescheduling (and continue) + get shared memory initialization from interface.c now based on nsectors and + overlap values. + add more checks for buffers and nsectors. + increase buffers and nsectors, if necessary + +Thu Feb 17 21:56:22 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.7 + moved shared memory allocation to cdda2wav.c + open linux ioctl devices with O_NONBLOCK + +Thu Feb 17 21:52:15 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.5 + fix synchronization with channel swaps or deemphasizing + +Thu Feb 17 21:50:59 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * scsi_cmds.c 1.3 + avoid error message, if speedselectMMC fails (is optional) + +Thu Feb 17 21:50:00 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.6 + fix compiler warnings, fix index scanning + +Thu Feb 17 21:48:43 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * semshm.c 1.4 + moved free_sem() in order to compile properly + +Thu Feb 17 21:47:04 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * global.h 1.3 + add input endianess variable for SCSI setup + +Wed Feb 16 21:26:40 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * semshm.c 1.3 + fixed comments and variable names for child/parent role swap + +Sun Feb 13 22:28:42 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * resample.c 1.4 + changed deemphasizing (now for marked tracks) + +Sun Feb 13 22:27:34 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.9 + automatic handling of -T (with index scanning) + +Sun Feb 13 22:26:38 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.h 1.4 + new get_current_track() function + +Sun Feb 13 22:21:04 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.1 1.5 + document new -T, cleanup + +Thu Feb 10 18:35:26 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.5 + implemented reading of cdplus/info.cdp through ISO file system + +Mon Feb 7 22:47:24 2000 root + * interface.c 1.6 + added Hitachi drive to mmc exception list + +Mon Feb 7 18:17:40 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.5 + explicitly let Toshiba ATAPI drives use the mmc command set. + +Sat Feb 5 11:47:00 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.8 + fixed percentage display for the 100% case + +Sat Feb 5 11:46:38 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.4 + extended simulation interface + +Thu Feb 3 20:59:12 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.c 1.4 + added the missing ascii to html character mapper + added check for valid cd extra + +Wed Feb 2 23:54:48 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.7 + fixed mixed mode multinaming + allow nonroot users , do not abort for failing prioctl() + +Tue Jan 25 18:57:39 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.h 1.3 + * toc.h 1.3 + prototype change with index scanning function + +Tue Jan 25 18:55:58 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.4 + fixed dumb warning + +Tue Jan 25 18:43:49 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * interface.c 1.3 + extend ioctl interface for FreeBSD-4.x atapi driver + +Sat Jan 22 21:24:16 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * ioctl.c 1.3 + fixed data reading for cd-Extra+ATAPI+Linux + +Tue Jan 11 23:16:11 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.6 + * toc.c 1.3 + + +Sun Jan 9 12:11:21 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.5 + index scanning limited to single tracks, if requested. + changed vfprintf() to Joerg Schillings error() for better portability. + modified error handling for wrong parameters. no more long usage listing. + + +Mon Jan 3 22:53:51 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.4 + * resample.c 1.3 + * mmsystem.h 1.4 + *_h -> *_H + +Sun Jan 2 23:22:23 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * mmsystem.h 1.3 + delete ctrl-m lineends + +Sun Jan 2 23:18:58 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.1 1.4 + new fix for SCCS (@(x)) + +Sun Jan 2 18:20:36 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.1 1.3 + fixed man page for SCCS header + +Sun Jan 2 18:07:17 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * mmsystem.h 1.2 + put under SCCS + +Sun Jan 2 18:02:48 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * lconfig.h.in 1.3 + * sndconfig.c 1.3 + OSS sound support added for NetBSD + +Sun Jan 2 17:56:13 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * mmsystem.h 1.1 + date and time created 00/01/02 17:56:13 by heiko + +Sun Jan 2 17:53:10 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * Makefile 1.1 + date and time created 00/01/02 17:53:10 by heiko + +Sun Jan 2 17:24:41 2000 Heiko Eissfeldt <heiko@colossus.escape.de> + * configure.in 1.1 + date and time created 00/01/02 17:24:41 by heiko + +Sun Dec 19 22:34:34 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.c 1.3 + multiple file names + +Sun Dec 19 21:52:00 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * toc.h 1.2 + * wav.c 1.2 + * wav.h 1.2 + * sha_func.c 1.2 + * sndconfig.c 1.2 + * sndconfig.h 1.2 + * sndfile.h 1.2 + * sun.c 1.2 + * sun.h 1.2 + * toc.c 1.2 + * ringbuff.h 1.2 + * saveargs.h 1.2 + * scsi_cmds.c 1.2 + * scsi_cmds.h 1.2 + * semshm.c 1.2 + * semshm.h 1.2 + * setuid.c 1.2 + * setuid.h 1.2 + * sha.h 1.2 + * md5c.c 1.2 + * mycdrom.h 1.2 + * mytype.h 1.2 + * raw.c 1.2 + * raw.h 1.2 + * resample.c 1.2 + * resample.h 1.2 + * ringbuff.c 1.2 + * global.h 1.2 + * interface.c 1.2 + * interface.h 1.2 + * ioctl.c 1.2 + * ioctl.h 1.2 + * lconfig.h.in 1.2 + * local.cnf.in 1.2 + * lowlevel.h 1.2 + * md5.h 1.2 + * aiff.h 1.2 + * base64.c 1.2 + * base64.h 1.2 + * byteorder.h 1.2 + * cdda2wav.1 1.2 + * cdda2wav.c 1.2 + * cdda2wav.h 1.2 + * config.h 1.2 + * aifc.c 1.2 + * aifc.h 1.2 + * aiff.c 1.2 + first + +Sat Nov 13 19:30:21 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * cdda2wav.1 1.1 + date and time created 99/11/13 19:30:21 by heiko + +Sat Nov 13 19:25:02 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * lconfig.h.in 1.1 + * local.cnf.in 1.1 + date and time created 99/11/13 19:25:02 by heiko + +Sat Nov 13 19:24:29 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * aifc.h 1.1 + * aiff.h 1.1 + * base64.h 1.1 + * byteorder.h 1.1 + * cdda2wav.h 1.1 + * config.h 1.1 + * global.h 1.1 + * interface.h 1.1 + * ioctl.h 1.1 + * lowlevel.h 1.1 + * md5.h 1.1 + * mycdrom.h 1.1 + * mytype.h 1.1 + * raw.h 1.1 + * resample.h 1.1 + * ringbuff.h 1.1 + * saveargs.h 1.1 + * scsi_cmds.h 1.1 + * semshm.h 1.1 + * setuid.h 1.1 + * sha.h 1.1 + * sndconfig.h 1.1 + * sndfile.h 1.1 + * sun.h 1.1 + * toc.h 1.1 + * wav.c 1.1 + * wav.h 1.1 + date and time created 99/11/13 19:24:29 by heiko + +Sat Nov 13 19:24:28 1999 Heiko Eissfeldt <heiko@colossus.escape.de> + * aifc.c 1.1 + * aiff.c 1.1 + * base64.c 1.1 + * cdda2wav.c 1.1 + * interface.c 1.1 + * ioctl.c 1.1 + * md5c.c 1.1 + * raw.c 1.1 + * resample.c 1.1 + * ringbuff.c 1.1 + * scsi_cmds.c 1.1 + * semshm.c 1.1 + * setuid.c 1.1 + * sha_func.c 1.1 + * sndconfig.c 1.1 + * sun.c 1.1 + * toc.c 1.1 + date and time created 99/11/13 19:24:28 by heiko + diff --git a/icedax/GPL b/icedax/GPL new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/icedax/GPL @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/icedax/aifc.c b/icedax/aifc.c new file mode 100644 index 0000000..a1001c7 --- /dev/null +++ b/icedax/aifc.c @@ -0,0 +1,213 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)aifc.c 1.5 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * + * --------------------------------------------------------------------- + * definitions for aifc pcm output + * --------------------------------------------------------------------- + */ + +#include "config.h" +#include "mytype.h" +#include <stdio.h> +#include <standard.h> +#include <unixstd.h> +#include <strdefs.h> +#include <schily.h> +#include "byteorder.h" +#include "sndfile.h" + +typedef UINT4 FOURCC; /* a four character code */ +typedef struct CHUNKHDR { + FOURCC ckid; /* chunk ID */ + UINT4 dwSize; /* chunk size */ +} CHUNKHDR; + +#define mmioFOURCC(ch0, ch1, ch2, ch3) \ + ((UINT4)(unsigned char)(ch3) | ((UINT4)(unsigned char)(ch2) << 8) | \ + ((UINT4)(unsigned char)(ch1) << 16) | ((UINT4)(unsigned char)(ch0) << 24)) + +#define FOURCC_FORM mmioFOURCC ('F', 'O', 'R', 'M') +#define FOURCC_AIFC mmioFOURCC ('A', 'I', 'F', 'C') +#define FOURCC_FVER mmioFOURCC ('F', 'V', 'E', 'R') +#define FOURCC_COMM mmioFOURCC ('C', 'O', 'M', 'M') +#define FOURCC_NONE mmioFOURCC ('N', 'O', 'N', 'E') +#define FOURCC_SSND mmioFOURCC ('S', 'S', 'N', 'D') + +#define NO_COMPRESSION "not compressed" + +/* brain dead construction from apple involving bigendian 80-bit doubles. + Definitely designed not to be portable. Alignment is a nightmare too. */ +typedef struct AIFCHDR { + CHUNKHDR formChk; + FOURCC formType; + + CHUNKHDR fverChk; /* Version chunk */ + UINT4 timestamp; /* timestamp identifies version */ + + CHUNKHDR commChk; /* Common chunk */ + /* from now on, alignment prevents us from using the original types :-(( */ + unsigned char numChannels[2]; /* Audio Channels */ + unsigned char numSampleFrames[4]; /* # of samples */ + unsigned char samplesize[2]; /* bits per sample */ + unsigned char sample_rate[10]; /* sample rate in extended float */ + unsigned char compressionType[4]; /* AIFC extension */ + unsigned char compressionNameLen; /* AIFC extension */ + char compressionName[sizeof(NO_COMPRESSION)]; /* AIFC extension */ + + unsigned char ssndChkid[4]; /* Sound data chunk */ + unsigned char dwSize[4]; /* size of chunk */ + unsigned char offset[4]; /* start of 1st sample */ + unsigned char blocksize[4]; /* aligned sound data block size */ + +} AIFCHDR; + +static AIFCHDR AifcHdr; + +/* Prototypes */ +static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]); +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes ); +static int ExitSound(int audio, unsigned long nBytesDone); +static unsigned long GetHdrSize(void); +static unsigned long InSizeToOutSize(unsigned long BytesToDo); + +struct soundfile aifcsound = +{ + InitSound, /* init header method */ + ExitSound, /* exit header method */ + GetHdrSize, /* report header size method */ + /* get sound samples out */ + (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo))write, + InSizeToOutSize, /* compressed? output file size */ + 1 /* needs big endian samples */ +}; + +/* format the sample rate into an + bigendian 10-byte IEEE-754 floating point number + */ +static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]) +{ + int i; + + /* normalize rate */ + for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) { + if ((rate & 0x8000) != 0) { + break; + } + } + + /* set exponent and sign */ + the_rate[1] = 14-i; + the_rate[0] = 0x40; /* LSB = sign */ + + /* 16-bit part of mantisse for sample rate */ + the_rate[3] = rate & 0xff; + the_rate[2] = (rate >> 8) & 0xff; + + /* initialize lower digits of mantisse */ + the_rate[4] = the_rate[5] = the_rate[6] = + the_rate[7] = the_rate[8] = the_rate[9] = 0; + + return 0; +} + + +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes) +{ + UINT4 tmp; + + fillbytes(&AifcHdr, sizeof(AifcHdr), '\0'); + AifcHdr.formChk.ckid = cpu_to_be32(FOURCC_FORM); + AifcHdr.formChk.dwSize= cpu_to_be32(expected_bytes + + offset_of(AIFCHDR,blocksize)+sizeof(AifcHdr.blocksize) + - offsetof(AIFCHDR,commChk)); + AifcHdr.formType = cpu_to_be32(FOURCC_AIFC); + + AifcHdr.fverChk.ckid = cpu_to_be32(FOURCC_FVER); + AifcHdr.fverChk.dwSize= cpu_to_be32(offsetof(AIFCHDR,commChk) + - offsetof(AIFCHDR,timestamp)); + + AifcHdr.compressionType[0]='N'; + AifcHdr.compressionType[1]='O'; + AifcHdr.compressionType[2]='N'; + AifcHdr.compressionType[3]='E'; + AifcHdr.compressionNameLen = sizeof(NO_COMPRESSION)-1; + strcpy(AifcHdr.compressionName, NO_COMPRESSION); + AifcHdr.timestamp = cpu_to_be32(UINT4_C(0xA2805140)); /* AIFC Version 1 */ + + AifcHdr.commChk.ckid = cpu_to_be32(FOURCC_COMM); + AifcHdr.commChk.dwSize= cpu_to_be32(offset_of(AIFCHDR,ssndChkid) + - offset_of(AIFCHDR,numChannels)); + + AifcHdr.numChannels[1]= channels; + + tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8))); + AifcHdr.numSampleFrames[0] = tmp >> 24; + AifcHdr.numSampleFrames[1] = tmp >> 16; + AifcHdr.numSampleFrames[2] = tmp >> 8; + AifcHdr.numSampleFrames[3] = tmp >> 0; + AifcHdr.samplesize[1] = nBitsPerSample; + Format_samplerate(rate, AifcHdr.sample_rate); + + memcpy(AifcHdr.ssndChkid, "SSND", 4); + tmp = cpu_to_be32(expected_bytes + offset_of(AIFCHDR,blocksize)+sizeof(AifcHdr.blocksize) - offset_of(AIFCHDR, offset)); + AifcHdr.dwSize[0] = tmp >> 24; + AifcHdr.dwSize[1] = tmp >> 16; + AifcHdr.dwSize[2] = tmp >> 8; + AifcHdr.dwSize[3] = tmp >> 0; + + return write (audio, &AifcHdr, sizeof (AifcHdr)); +} + +static int ExitSound(int audio, unsigned long nBytesDone) +{ + UINT4 tmp; + + AifcHdr.formChk.dwSize= cpu_to_be32(nBytesDone + sizeof(AIFCHDR) + - offsetof(AIFCHDR,commChk)); + tmp = cpu_to_be32(nBytesDone/( + AifcHdr.numChannels[1] * AifcHdr.samplesize[1]/ULONG_C(8))); + AifcHdr.numSampleFrames[0] = tmp >> 24; + AifcHdr.numSampleFrames[1] = tmp >> 16; + AifcHdr.numSampleFrames[2] = tmp >> 8; + AifcHdr.numSampleFrames[3] = tmp >> 0; + + /* If an odd number of bytes has been written, + extend the chunk with one dummy byte. This is a requirement for AIFC. */ + if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) { + return 0; + } + + /* goto beginning */ + if (lseek(audio, 0L, SEEK_SET) == -1) { + return 0; + } + return write (audio, &AifcHdr, sizeof (AifcHdr)); +} + +static unsigned long GetHdrSize() +{ + return sizeof( AifcHdr ); +} + +static unsigned long InSizeToOutSize(unsigned long BytesToDo) +{ + return BytesToDo; +} + diff --git a/icedax/aifc.h b/icedax/aifc.h new file mode 100644 index 0000000..f9a2c9d --- /dev/null +++ b/icedax/aifc.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)aifc.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +extern struct soundfile aifcsound; diff --git a/icedax/aiff.c b/icedax/aiff.c new file mode 100644 index 0000000..cd1d98d --- /dev/null +++ b/icedax/aiff.c @@ -0,0 +1,188 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)aiff.c 1.5 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * + * --------------------------------------------------------------------- + * definitions for aiff pcm output + * --------------------------------------------------------------------- + */ + +#include "config.h" +#include <stdio.h> +#include <unixstd.h> +#include <strdefs.h> +#include <standard.h> +#include <schily.h> +#include "mytype.h" +#include "byteorder.h" +#include "sndfile.h" + +typedef UINT4 FOURCC; /* a four character code */ +typedef struct CHUNKHDR { + FOURCC ckid; /* chunk ID */ + UINT4 dwSize; /* chunk size */ +} CHUNKHDR; + +#define mmioFOURCC(ch0, ch1, ch2, ch3) \ + ((UINT4)(unsigned char)(ch3) | ((UINT4)(unsigned char)(ch2) << 8) | \ + ((UINT4)(unsigned char)(ch1) << 16) | ((UINT4)(unsigned char)(ch0) << 24)) + +#define FOURCC_FORM mmioFOURCC ('F', 'O', 'R', 'M') +#define FOURCC_AIFF mmioFOURCC ('A', 'I', 'F', 'F') +#define FOURCC_COMM mmioFOURCC ('C', 'O', 'M', 'M') +#define FOURCC_SSND mmioFOURCC ('S', 'S', 'N', 'D') + +typedef struct AIFFHDR { + CHUNKHDR formChk; + FOURCC formType; + + CHUNKHDR commChk; /* Common chunk */ + /* from now on, alignment prevents us from using the original types :-(( */ + unsigned char numChannels[2]; /* Audio Channels */ + unsigned char numSampleFrames[4]; /* # of samples */ + unsigned char samplesize[2]; /* bits per sample */ + unsigned char sample_rate[10]; /* sample rate in extended float */ + + unsigned char ssndChkid[4]; /* Sound data chunk */ + unsigned char dwSize[4]; /* size of chunk */ + unsigned char offset[4]; /* start of 1st sample */ + unsigned char blocksize[4]; /* aligned sound data block size */ +} AIFFHDR; + +static AIFFHDR AiffHdr; + +/* Prototypes */ +static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]); +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes); +static int ExitSound(int audio, unsigned long nBytesDone); +static unsigned long GetHdrSize(void); +static unsigned long InSizeToOutSize(unsigned long BytesToDo); + + +/* format the sample rate into an + bigendian 10-byte IEEE-754 floating point number + */ +static int Format_samplerate(unsigned long rate, unsigned char the_rate[10]) +{ + int i; + + /* normalize rate */ + for (i = 0; (rate & 0xffff) != 0; rate <<= 1, i++) { + if ((rate & 0x8000) != 0) { + break; + } + } + + /* set exponent and sign */ + the_rate[1] = 14-i; + the_rate[0] = 0x40; /* LSB = sign */ + + /* 16-bit part of mantisse for sample rate */ + the_rate[3] = rate & 0xff; + the_rate[2] = (rate >> 8) & 0xff; + + /* initialize lower digits of mantisse */ + the_rate[4] = the_rate[5] = the_rate[6] = + the_rate[7] = the_rate[8] = the_rate[9] = 0; + + return 0; +} + +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes) +{ + UINT4 tmp; + + fillbytes(&AiffHdr, sizeof(AiffHdr), '\0'); + AiffHdr.formChk.ckid = cpu_to_be32(FOURCC_FORM); + AiffHdr.formChk.dwSize= cpu_to_be32(expected_bytes + + offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize) + - offsetof(AIFFHDR,formType)); + AiffHdr.formType = cpu_to_be32(FOURCC_AIFF); + + AiffHdr.commChk.ckid = cpu_to_be32(FOURCC_COMM); + AiffHdr.commChk.dwSize= cpu_to_be32(offset_of(AIFFHDR,ssndChkid) + - offset_of(AIFFHDR,numChannels)); + + AiffHdr.numChannels[1]= channels; + tmp = cpu_to_be32(expected_bytes/(channels * (nBitsPerSample/8))); + AiffHdr.numSampleFrames[0] = tmp >> 24; + AiffHdr.numSampleFrames[1] = tmp >> 16; + AiffHdr.numSampleFrames[2] = tmp >> 8; + AiffHdr.numSampleFrames[3] = tmp >> 0; + AiffHdr.samplesize[1] = nBitsPerSample; + Format_samplerate(rate, AiffHdr.sample_rate); + + memcpy(AiffHdr.ssndChkid, "SSND", 4); + tmp = cpu_to_be32(expected_bytes + offset_of(AIFFHDR,blocksize)+sizeof(AiffHdr.blocksize) - offset_of(AIFFHDR, offset)); + AiffHdr.dwSize[0] = tmp >> 24; + AiffHdr.dwSize[1] = tmp >> 16; + AiffHdr.dwSize[2] = tmp >> 8; + AiffHdr.dwSize[3] = tmp >> 0; + + return write (audio, &AiffHdr, sizeof (AiffHdr)); +} + +static int ExitSound(int audio, unsigned long nBytesDone ) +{ + UINT4 tmp; + + AiffHdr.formChk.dwSize= cpu_to_be32(nBytesDone + sizeof(AIFFHDR) + - offsetof(AIFFHDR,commChk)); + tmp = cpu_to_be32(nBytesDone/( + AiffHdr.numChannels[1] * AiffHdr.samplesize[1]/ULONG_C(8))); + AiffHdr.numSampleFrames[0] = tmp >> 24; + AiffHdr.numSampleFrames[1] = tmp >> 16; + AiffHdr.numSampleFrames[2] = tmp >> 8; + AiffHdr.numSampleFrames[3] = tmp >> 0; + + /* If an odd number of bytes has been written, + extend the chunk with one dummy byte. This is a requirement for AIFF. */ + if ((nBytesDone & 1) && (lseek(audio, 1L, SEEK_CUR) == -1)) { + return 0; + } + + /* goto beginning */ + if (lseek(audio, 0L, SEEK_SET) == -1) { + return 0; + } + return write (audio, &AiffHdr, sizeof (AiffHdr)); +} + +static unsigned long GetHdrSize() +{ + return sizeof( AiffHdr ); +} + +static unsigned long InSizeToOutSize(unsigned long BytesToDo) +{ + return BytesToDo; +} + +struct soundfile aiffsound = +{ + InitSound, /* init header method */ + ExitSound, /* exit header method */ + GetHdrSize, /* report header size method */ + /* get sound samples out */ + (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo))write, + InSizeToOutSize, /* compressed? output file size */ + 1 /* needs big endian samples */ +}; + + diff --git a/icedax/aiff.h b/icedax/aiff.h new file mode 100644 index 0000000..cc04849 --- /dev/null +++ b/icedax/aiff.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)aiff.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +extern struct soundfile aiffsound; diff --git a/icedax/base64.c b/icedax/base64.c new file mode 100644 index 0000000..69b75cb --- /dev/null +++ b/icedax/base64.c @@ -0,0 +1,121 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)base64.c 1.4 02/04/06 Copyright 1998,1999 Heiko Eissfeldt */ +/*____________________________________________________________________________ +// +// CD Index - The Internet CD Index +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id: base64.c,v 1.1.1.3 1999/04/29 00:57:14 marc Exp $ +//____________________________________________________________________________ +*/ +/* + * Program: RFC-822 routines (originally from SMTP) + * + * Author: Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Date: 27 July 1988 + * Last Edited: 10 September 1998 + * + * Sponsorship: The original version of this work was developed in the + * Symbolic Systems Resources Group of the Knowledge Systems + * Laboratory at Stanford University in 1987-88, and was funded + * by the Biomedical Research Technology Program of the National + * Institutes of Health under grant number RR-00785. + * + * Original version Copyright 1988 by The Leland Stanford Junior University + * Copyright 1998 by the University of Washington + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notices appear in all copies and that both the + * above copyright notices and this permission notice appear in supporting + * documentation, and that the name of the University of Washington or The + * Leland Stanford Junior University not be used in advertising or publicity + * pertaining to distribution of the software without specific, written prior + * permission. This software is made available "as is", and + * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY + * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF + * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "config.h" +#include <stdio.h> +#include <stdxlib.h> + +#include "base64.h" + +/* NOTE: This is not true RFC822 anymore. The use of the characters +// '/', '+', and '=' is no bueno when the ID will be used as part of a URL. +// '_', '.', and '-' have been used instead +*/ + +/* Convert binary contents to BASE64 + * Accepts: source + * length of source + * pointer to return destination length + * Returns: destination as BASE64 + */ + +unsigned char *rfc822_binary(char *src, unsigned long srcl, unsigned long *len) +{ + unsigned char *ret,*d; + unsigned char *s = (unsigned char *) src; + char *v = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; + unsigned long i = ((srcl + 2) / 3) * 4; + *len = i += 2 * ((i / 60) + 1); + d = ret = malloc ((size_t) ++i); + for (i = 0; srcl; s += 3) { /* process tuplets */ + *d++ = v[s[0] >> 2]; /* byte 1: high 6 bits (1) */ + /* byte 2: low 2 bits (1), high 4 bits (2) */ + *d++ = v[((s[0] << 4) + (--srcl ? (s[1] >> 4) : 0)) & 0x3f]; + /* byte 3: low 4 bits (2), high 2 bits (3) */ + *d++ = srcl ? v[((s[1] << 2) + (--srcl ? (s[2] >> 6) : 0)) & 0x3f] : '-'; + /* byte 4: low 6 bits (3) */ + *d++ = srcl ? v[s[2] & 0x3f] : '-'; + if (srcl) srcl--; /* count third character if processed */ + if ((++i) == 15) { /* output 60 characters? */ + i = 0; /* restart line break count, insert CRLF */ + *d++ = '\015'; *d++ = '\012'; + } + } + *d = '\0'; /* tie off string */ + + return ret; /* return the resulting string */ +} diff --git a/icedax/base64.h b/icedax/base64.h new file mode 100644 index 0000000..5b8522c --- /dev/null +++ b/icedax/base64.h @@ -0,0 +1,83 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)base64.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +/*____________________________________________________________________________ +// +// CD Index - The Internet CD Index +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id: base64.h,v 1.1.1.2 1999/04/29 00:53:34 marc Exp $ +//____________________________________________________________________________ +*/ +/* + * Program: RFC-822 routines (originally from SMTP) + * + * Author: Mark Crispin + * Networks and Distributed Computing + * Computing & Communications + * University of Washington + * Administration Building, AG-44 + * Seattle, WA 98195 + * Internet: MRC@CAC.Washington.EDU + * + * Date: 27 July 1988 + * Last Edited: 10 September 1998 + * + * Sponsorship: The original version of this work was developed in the + * Symbolic Systems Resources Group of the Knowledge Systems + * Laboratory at Stanford University in 1987-88, and was funded + * by the Biomedical Research Technology Program of the National + * Institutes of Health under grant number RR-00785. + * + * Original version Copyright 1988 by The Leland Stanford Junior University + * Copyright 1998 by the University of Washington + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notices appear in all copies and that both the + * above copyright notices and this permission notice appear in supporting + * documentation, and that the name of the University of Washington or The + * Leland Stanford Junior University not be used in advertising or publicity + * pertaining to distribution of the software without specific, written prior + * permission. This software is made available "as is", and + * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY + * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF + * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef BASE64_H +#define BASE64_H + +unsigned char *rfc822_binary(char *src,unsigned long srcl,unsigned long *len); + +#endif diff --git a/icedax/byteorder.h b/icedax/byteorder.h new file mode 100644 index 0000000..0fa8eb6 --- /dev/null +++ b/icedax/byteorder.h @@ -0,0 +1,67 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)byteorder.h 1.3 03/07/20 Copyright 1998,1999 Heiko Eissfeldt */ +#ifndef MYBYTE_ORDER +#define MYBYTE_ORDER 1 +/* supply the byte order macros */ + +#if defined (WORDS_BIGENDIAN) +# define MY_BIG_ENDIAN 1 +# define MY_LITTLE_ENDIAN 0 +#else +# define MY_BIG_ENDIAN 0 +# define MY_LITTLE_ENDIAN 1 +#endif + +# undef cpu_to_le32 +# undef cpu_to_le16 +# undef cpu_to_be32 +# undef cpu_to_be16 +# undef le32_to_cpu +# undef le16_to_cpu +# undef be32_to_cpu +# undef be16_to_cpu + +# define revert4bytes(x) \ + ((unsigned long int)((((unsigned long int)(x) & ULONG_C(0x000000ff)) << 24) | \ + (((unsigned long int)(x) & ULONG_C(0x0000ff00)) << 8) | \ + (((unsigned long int)(x) & ULONG_C(0x00ff0000)) >> 8) | \ + (((unsigned long int)(x) & ULONG_C(0xff000000)) >> 24))) +# define revert2bytes(x) \ + ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \ + (((unsigned short int)(x) & 0xff00) >> 8))) + +#if MY_BIG_ENDIAN == 1 +# define cpu_to_le32(x) revert4bytes(x) +# define cpu_to_le16(x) revert2bytes(x) +# define le32_to_cpu(x) cpu_to_le32(x) +# define le16_to_cpu(x) cpu_to_le16(x) +# define cpu_to_be32(x) (x) +# define cpu_to_be16(x) (x) +# define be32_to_cpu(x) (x) +# define be16_to_cpu(x) (x) +#else +# define cpu_to_be32(x) revert4bytes(x) +# define cpu_to_be16(x) revert2bytes(x) +# define be32_to_cpu(x) cpu_to_be32(x) +# define be16_to_cpu(x) cpu_to_be16(x) +# define cpu_to_le32(x) (x) +# define cpu_to_le16(x) (x) +# define le32_to_cpu(x) (x) +# define le16_to_cpu(x) (x) +#endif + +#define GET_LE_UINT_FROM_CHARP(p) ((unsigned int)((*(p+3))<<24)|((*(p+2))<<16)|((*(p+1))<<8)|(*(p))) +#define GET_BE_UINT_FROM_CHARP(p) ((unsigned int)((*(p))<<24)|((*(p+1))<<16)|((*(p+2))<<8)|(*(p+3))) + +#endif /* ifndef MYBYTE_ORDER */ diff --git a/icedax/cd_extra.c b/icedax/cd_extra.c new file mode 100644 index 0000000..fa17c5b --- /dev/null +++ b/icedax/cd_extra.c @@ -0,0 +1,417 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)cd_extra.c 1.8 02/11/21 Copyright 2000-2001 Heiko Eissfeldt */ + +/* This is an include file! */ +/**************** CD-Extra special treatment *********************************/ + +#include <ctype.h> + +static unsigned long Read_CD_Extra_File(unsigned char *Extra_buf, unsigned long sector); + +static unsigned long +Read_CD_Extra_File(unsigned char *Extra_buf, unsigned long sector) +{ + unsigned long mysec; + + /* read PVD */ + ReadCdRomData(get_scsi_p(), Extra_buf, sector+16, 1); + + /* check ISO signature */ + if (memcmp(Extra_buf, "\001CD001", 6) != 0) return 0; + + /* get path_table */ + mysec = Extra_buf[148] << 24; + mysec |= Extra_buf[149] << 16; + mysec |= Extra_buf[150] << 8; + mysec |= Extra_buf[151]; + + if (mysec <= sector) return 0; + + /* read path table */ + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + /* find cdplus subdirectory */ + { unsigned char * p = Extra_buf; + while (p+8 < Extra_buf + CD_FRAMESIZE_RAW) { + int namelength; + + namelength = p[0] | (p[1] << 8); + if (namelength == 6 && + !memcmp(p+8, "CDPLUS", 6)) break; + + p += 8 + namelength + (namelength & 1); + } + if (p+8 >= Extra_buf + CD_FRAMESIZE_RAW) return 0; + + /* get extent */ + mysec = p[2] << 24; + mysec |= p[3] << 16; + mysec |= p[4] << 8; + mysec |= p[5]; + } + + if (mysec <= sector) return 0; + + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + /* find file info.cdp */ + { unsigned char * p = Extra_buf; + while (p+33 < Extra_buf + CD_FRAMESIZE_RAW) { + int namelength; + + namelength = p[32]; + if (namelength == 10 && + !memcmp(p+33, "INFO.CDP;1", 10)) break; + + p += p[0]; + } + if (p+33 >= Extra_buf + CD_FRAMESIZE_RAW) return 0; + + /* get extent */ + mysec = p[6] << 24; + mysec |= p[7] << 16; + mysec |= p[8] << 8; + mysec |= p[9]; + } + + if (mysec <= sector) return 0; + + /* read file info.cdp */ + ReadCdRomData(get_scsi_p(), Extra_buf, mysec, 1); + + return mysec - sector; +} + +static unsigned char Extra_buffer[CD_FRAMESIZE_RAW]; + +/* + * Read the file cdplus/info.cdp from the cd extra disc. + * This file has to reside at exactly 75 sectors after start of + * the last session (according to Blue Book). + * Of course, there are a lot dubious cd extras, which don't care :-((( + * As an alternative method, we try reading through the iso9660 file system... + */ +static int Read_CD_Extra_Info(unsigned long sector); +static int Read_CD_Extra_Info(unsigned long sector) +{ + unsigned i; + static int offsets[] = { + 75 /* this is what blue book says */ + }; + + for (i = 0; i < sizeof(offsets)/sizeof(int); i++) { +#ifdef DEBUG_XTRA + fprintf(stderr, "debug: Read_CD_Extra_Info at sector %lu\n", sector+offsets[i]); +#endif + ReadCdRomData(get_scsi_p(), Extra_buffer, sector+offsets[i], 1); + + /* If we are unlucky the drive cannot handle XA sectors by default. + We try to compensate by ignoring the first eight bytes. + Of course then we lack the last 8 bytes of the sector... + */ + + if (Extra_buffer[0] == 0) + memmove(Extra_buffer, Extra_buffer +8, CD_FRAMESIZE - 8); + + /* check for cd extra */ + if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D') + return sector+offsets[i]; + + /* + * CD is not conforming to BlueBook! + * Read the file through ISO9660 file system. + */ + { + unsigned long offset = Read_CD_Extra_File(Extra_buffer, sector); + + if (offset == 0) return 0; + + if (Extra_buffer[0] == 0) + memmove(Extra_buffer, Extra_buffer +8, CD_FRAMESIZE - 8); + + /* check for cd extra */ + if (Extra_buffer[0] == 'C' && Extra_buffer[1] == 'D') + return sector+offset; + } + } + + return 0; +} + +static void Read_Subinfo(unsigned pos, unsigned length); +static void Read_Subinfo(unsigned pos, unsigned length) +{ + unsigned num_infos, num; + unsigned char *Subp, *orgSubp; + unsigned this_track = 0xff; +#ifdef DEBUG_XTRA + unsigned char *up; + unsigned char *sp; + unsigned u; + unsigned short s; +#endif + + length += 8; + length = (length + CD_FRAMESIZE_RAW-1) / CD_FRAMESIZE_RAW; + length *= CD_FRAMESIZE_RAW; + orgSubp = Subp = malloc(length); + + if (Subp == NULL) { + fprintf(stderr, "Read_Subinfo no memory(%d)\n",length); + goto errorout; + } + + ReadCdRomData(get_scsi_p(), Subp, pos, 1); + + num_infos = Subp[45]+(Subp[44] << 8); +#ifdef DEBUG_XTRA + fprintf(stderr, "subinfo version %c%c.%c%c, %d info packets\n", + Subp[8], + Subp[9], + Subp[10], + Subp[11], + num_infos); +#endif + length -= 46; + Subp += 46; + for (num = 0; num < num_infos && length > 0; num++) { + unsigned id = *Subp; + unsigned len = *(Subp +1); +#define INFOPACKETTYPES 0x44 +#ifdef INFOPACKETSTRINGS + static const char *infopacketID[INFOPACKETTYPES] = { "0", + "track identifier", + "album title", + "universal product code", + "international standard book number", + "copyright", + "track title", + "notes", + "main interpret", + "secondary interpret", + "composer", + "original composer", + "creation date", + "release date", + "publisher", + "0f", + "isrc audio track", + "isrc lyrics", + "isrc pictures", + "isrc MIDI data", + "14", "15", "16", "17", "18", "19", + "copyright state SUB_INFO", + "copyright state intro lyrics", + "copyright state lyrics", + "copyright state MIDI data", + "1e", "1f", + "intro lyrics", + "pointer to lyrics text file and length", + "22", "23", "24", "25", "26", "27", "28", + "29", "2a", "2b", "2c", "2d", "2e", "2f", + "still picture descriptor", + "31", + "32", "33", "34", "35", "36", "37", "38", + "39", "3a", "3b", "3c", "3d", "3e", "3f", + "MIDI file descriptor", + "genre code", + "tempo", + "key" + }; +#endif + + if (id >= INFOPACKETTYPES) { + fprintf(stderr, "Off=%4d, ind=%2d/%2d, unknown Id=%2u, len=%2u ", + /* this pointer difference is assumed to be small enough for an int. */ + (int)(Subp - orgSubp) + , num, num_infos, id, len); + Subp += 2 + 1; + length -= 2 + 1; + break; + } +#ifdef DEBUG_XTRA + fprintf(stderr, "info packet %d\n", id); +#endif + + switch (id) { + case 1: /* track nummer or 0 */ + this_track = 10 * (*(Subp + 2) - '0') + (*(Subp + 3) - '0'); + break; + + case 0x02: /* album title */ + if (global.disctitle == NULL) { + global.disctitle = malloc(len + 1); + if (global.disctitle != NULL) { + memcpy(global.disctitle, Subp + 2, len); + global.disctitle[len] = '\0'; + } + } + break; + case 0x03: /* media catalog number */ + if (Get_MCN()[0] == '\0' && Subp[2] != '\0' && len >= 13) { + Set_MCN( Subp + 2); + } + break; + case 0x06: /* track title */ + if (this_track > 0 && this_track < 100 + && global.tracktitle[this_track] == NULL) { + global.tracktitle[this_track] = malloc(len + 1); + if (global.tracktitle[this_track] != NULL) { + memcpy(global.tracktitle[this_track], Subp + 2, len); + global.tracktitle[this_track][len] = '\0'; + } + } + break; + case 0x05: /* copyright message */ + if (global.copyright_message == NULL) { + global.copyright_message = malloc(len + 1); + if (global.copyright_message != NULL) { + memcpy(global.copyright_message, Subp + 2, len); + global.copyright_message[len] = '\0'; + } + } + break; + case 0x08: /* creator */ + if (global.creator == NULL) { + global.creator = malloc(len + 1); + if (global.creator != NULL) { + memcpy(global.creator, Subp + 2, len); + global.creator[len] = '\0'; + } + } + break; + case 0x10: /* isrc */ + if (this_track > 0 && this_track < 100 + && Get_ISRC(this_track)[0] == '\0' && Subp[2] != '\0' + && len >= 15) { + Set_ISRC(this_track, Subp + 2); + } + break; +#if 0 + case 0x04: + case 0x07: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: +#ifdef INFOPACKETSTRINGS + fprintf(stderr, "%s: %*.*s\n",infopacketID[id], (int) len, (int) len, (Subp +2)); +#endif + break; +#ifdef DEBUG_XTRA + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: +#ifdef INFOPACKETSTRINGS + fprintf(stderr, "%s %scopyrighted\n", infopacketID[id], *(Subp + 2) == 0 ? "not " : ""); +#endif + break; + + case 0x21: + fprintf(stderr, "lyrics file beginning at sector %u", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2)); + if (len == 8) + fprintf(stderr, ", having length: %u\n", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6)); + else + fputs("\n", stderr); + break; + + case 0x30: + sp = Subp + 2; + while (sp < Subp + 2 + len) { + /*while (len >= 10) {*/ + s = be16_to_cpu((*(sp)) | (*(sp) << 8)); + fprintf(stderr, "%04x, ", s); + sp += 2; + up = sp; + switch (s) { + case 0: + break; + case 4: + break; + case 5: + break; + case 6: + break; + } + u = GET_BE_UINT_FROM_CHARP(up); + fprintf(stderr, "%04lx, ", (long) u); + up += 4; + u = GET_BE_UINT_FROM_CHARP(up); + fprintf(stderr, "%04lx, ", (long) u); + up += 4; + sp += 8; + } + fputs("\n", stderr); + break; + + case 0x40: + fprintf(stderr, "MIDI file beginning at sector %u", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 2)); + if (len == 8) + fprintf(stderr, ", having length: %u\n", + (unsigned) GET_BE_UINT_FROM_CHARP(Subp + 6)); + else + fputs("\n", stderr); + break; + +#ifdef INFOPACKETSTRINGS + case 0x42: + fprintf(stderr, "%s: %d beats per minute\n",infopacketID[id], *(Subp + 2)); + break; + case 0x41: + if (len == 8) + fprintf(stderr, "%s: %x, %x, %x, %x, %x, %x, %x, %x\n", + infopacketID[id], + *(Subp + 2), + *(Subp + 3), + *(Subp + 4), + *(Subp + 5), + *(Subp + 6), + *(Subp + 7), + *(Subp + 8), + *(Subp + 9) + ); + else + fprintf(stderr, "%s:\n",infopacketID[id]); + break; + case 0x43: + fprintf(stderr, "%s: %x\n",infopacketID[id], *(Subp + 2)); + break; + default: + fprintf(stderr, "%s: %*.*s\n",infopacketID[id], (int) len, (int) len, (Subp +2)); +#endif +#endif +#endif + } + + if (len & 1) len++; + Subp += 2 + len; + length -= 2 + len; + } + +/* cleanup */ + + free(orgSubp); + +errorout: + return; + +} + diff --git a/icedax/cd_text.c b/icedax/cd_text.c new file mode 100644 index 0000000..6e93b13 --- /dev/null +++ b/icedax/cd_text.c @@ -0,0 +1,421 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)cd_text.c 1.5 03/12/31 Copyright 2000-2001 Heiko Eissfeldt */ + +/* This is an include file! */ +/**************** CD-Text special treatment **********************************/ + +typedef struct { + unsigned char headerfield[4]; + unsigned char textdatafield[12]; + unsigned char crcfield[2]; +} cdtextpackdata; + +static unsigned short crctab[1<<8] = { /* as calculated by initcrctab() */ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, + }; + +#define SUBSIZE 18*8 + +static unsigned short updcrc(unsigned int p_crc, register unsigned char *cp, + register size_t cnt); + +static unsigned short updcrc(unsigned int p_crc, register unsigned char *cp, + register size_t cnt) +{ + register unsigned short crc = (unsigned short)p_crc; + while( cnt-- ) { + crc = (crc<<8) ^ crctab[(crc>>(16-8)) ^ (*cp++)]; + } + return( crc ); +} + +static unsigned short calcCRC(unsigned char *buf, unsigned bsize); + +static unsigned short calcCRC(unsigned char *buf, unsigned bsize) +{ + return updcrc( 0x0, (unsigned char *)buf, bsize ); +} + +static unsigned char fliptab[8] = { + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, +}; + +static int flip_error_corr(unsigned char *b, int crc); + +static int flip_error_corr(unsigned char *b, int crc) +{ + if (crc != 0) { + int i; + for (i = 0; i < SUBSIZE; i++) { + char c; + + c = fliptab[i%8]; + b[i / 8] ^= c; + if ((crc = calcCRC(b, SUBSIZE/8)) == 0) { + return crc; + } + b[i / 8] ^= c; + } + } + return crc & 0xffff; +} + + +static int cdtext_crc_ok(cdtextpackdata *c); + +static int cdtext_crc_ok(cdtextpackdata *c) +{ + int crc; + int retval; + + c->crcfield[0] ^= 0xff; + c->crcfield[1] ^= 0xff; + crc = calcCRC(((unsigned char *)c), 18); + retval = (0 == flip_error_corr((unsigned char *)c, crc)); + c->crcfield[0] ^= 0xff; + c->crcfield[1] ^= 0xff; +#if 0 + fprintf(stderr, "%02x %02x %02x %02x ", + c->headerfield[0], c->headerfield[1], c->headerfield[2], c->headerfield[3]); + fprintf(stderr, +"%c %c %c %c %c %c %c %c %c %c %c %c " + , c->textdatafield[0] + , c->textdatafield[1] + , c->textdatafield[2] + , c->textdatafield[3] + , c->textdatafield[4] + , c->textdatafield[5] + , c->textdatafield[6] + , c->textdatafield[7] + , c->textdatafield[8] + , c->textdatafield[9] + , c->textdatafield[10] + , c->textdatafield[11] + ); + fprintf(stderr, "%02x %02x \n" + , c->crcfield[0] + , c->crcfield[1] + ); +#endif + return retval; +} + +#define DETAILED 0 + +#if DETAILED +static void dump_binary(cdtextpackdata *c); + +static void dump_binary(cdtextpackdata *c) +{ + fprintf(stderr, ": header fields %02x %02x %02x ", + c->headerfield[1], c->headerfield[2], c->headerfield[3]); + fprintf(stderr, +"%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" + , c->textdatafield[0] + , c->textdatafield[1] + , c->textdatafield[2] + , c->textdatafield[3] + , c->textdatafield[4] + , c->textdatafield[5] + , c->textdatafield[6] + , c->textdatafield[7] + , c->textdatafield[8] + , c->textdatafield[9] + , c->textdatafield[10] + , c->textdatafield[11] + ); +} +#endif + +static int process_header(cdtextpackdata *c, unsigned tracknr, int dbcc, + unsigned char *line); + +static int process_header(cdtextpackdata *c, unsigned tracknr, int dbcc, + unsigned char *line) +{ + switch ((int)c->headerfield[0]) { + + case 0x80: /* Title of album or track */ +#if DETAILED + fprintf (stderr, "Title"); +#endif + if (tracknr > 0 && tracknr < 100 + && global.tracktitle[tracknr] == NULL) { + unsigned len; + + len = strlen((char *)line); + + if (len > 0) + global.tracktitle[tracknr] = malloc(len + 1); + if (global.tracktitle[tracknr] != NULL) { + memcpy(global.tracktitle[tracknr], line, len); + global.tracktitle[tracknr][len] = '\0'; + } + } else + if (tracknr == 0 + && global.disctitle == NULL) { + unsigned len; + + len = strlen((char *)line); + + if (len > 0) + global.disctitle = malloc(len + 1); + if (global.disctitle != NULL) { + memcpy(global.disctitle, line, len); + global.disctitle[len] = '\0'; + } + } + break; + case 0x81: /* Name(s) of the performer(s) */ +#if DETAILED + fprintf(stderr, "Performer(s)"); +#endif + if (tracknr > 0 && tracknr < 100 + && global.trackcreator[tracknr] == NULL) { + unsigned len; + + len = strlen((char *)line); + + if (len > 0) + global.trackcreator[tracknr] = malloc(len + 1); + + if (global.trackcreator[tracknr] != NULL) { + memcpy(global.trackcreator[tracknr], line, len); + global.trackcreator[tracknr][len] = '\0'; + } + } else + if (tracknr == 0 + && global.creator == NULL) { + unsigned len; + + len = strlen((char *)line); + + if (len > 0) + global.creator = malloc(len + 1); + if (global.creator != NULL) { + memcpy(global.creator, line, len); + global.creator[len] = '\0'; + } + } + break; + case 0x82: /* Name(s) of the songwriter(s) */ +#if DETAILED + fprintf(stderr, "Songwriter(s)"); +#endif + break; + case 0x83: /* Name(s) of the composer(s) */ +#if DETAILED + fprintf(stderr, "Composer(s)"); +#endif + break; + case 0x84: /* Name(s) of the arranger(s) */ +#if DETAILED + fprintf(stderr, "Arranger(s)"); +#endif + break; + case 0x85: /* Message from content provider and/or artist */ +#if DETAILED + fprintf(stderr, "Message"); +#endif + break; + case 0x86: /* Disc Identification and information */ +#if DETAILED + fprintf(stderr, "Disc identification"); +#endif + if (tracknr == 0 && line[0] != '\0') { + fprintf(stderr, "Disc identification: %s\n", line); + } + break; + case 0x87: /* Genre Identification and information */ +#if DETAILED + fprintf(stderr, "Genre identification"); +#endif + break; + case 0x8e: /* UPC/EAN code or ISRC code */ +#if DETAILED + fprintf(stderr, "UPC or ISRC"); +#endif + if (tracknr > 0 && tracknr < 100) { + Set_ISRC(tracknr, line); + } else + if (tracknr == 0 && line[0] != '\0') { + Set_MCN(line); + } + break; + case 0x88: /* Table of Content information */ +#if DETAILED + fprintf(stderr, "Table of Content identification"); + dump_binary(c); +#endif + return 0; + case 0x89: /* Second Table of Content information */ +#if DETAILED + fprintf(stderr, "Second Table of Content identification"); + dump_binary(c); +#endif + return 0; + case 0x8f: /* Size information of the block */ +#if DETAILED == 0 + break; +#else + switch (tracknr) { + case 0: + fprintf(stderr, "first track is %d, last track is %d\n", + c->textdatafield[1], + c->textdatafield[2]); + if (c->textdatafield[3] & 0x80) { + fprintf(stderr, "Program Area CD Text information available\n"); + if (c->textdatafield[3] & 0x40) { + fprintf(stderr, "Program Area copy protection available\n"); + } + } + if (c->textdatafield[3] & 0x07) { + fprintf(stderr, "message information is %scopyrighted\n", + c->textdatafield[3] & 0x04 ? "": "not "); + fprintf(stderr, "Names of performer/songwriter/composer/arranger(s) are %scopyrighted\n", + c->textdatafield[3] & 0x02 ? "": "not "); + fprintf(stderr, "album and track names are %scopyrighted\n", + c->textdatafield[3] & 0x01 ? "": "not "); + } + fprintf(stderr, "%d packs with album/track names\n", c->textdatafield[4]); + fprintf(stderr, "%d packs with performer names\n", c->textdatafield[5]); + fprintf(stderr, "%d packs with songwriter names\n", c->textdatafield[6]); + fprintf(stderr, "%d packs with composer names\n", c->textdatafield[7]); + fprintf(stderr, "%d packs with arranger names\n", c->textdatafield[8]); + fprintf(stderr, "%d packs with artist or content provider messages\n", c->textdatafield[9]); + fprintf(stderr, "%d packs with disc identification information\n", c->textdatafield[10]); + fprintf(stderr, "%d packs with genre identification/information\n", c->textdatafield[11]); + break; + case 1: + fprintf(stderr, "%d packs with table of contents information\n", c->textdatafield[0]); + fprintf(stderr, "%d packs with second table of contents information\n", c->textdatafield[1]); + fprintf(stderr, "%d packs with reserved information\n", c->textdatafield[2]); + fprintf(stderr, "%d packs with reserved information\n", c->textdatafield[3]); + fprintf(stderr, "%d packs with reserved information\n", c->textdatafield[4]); + fprintf(stderr, "%d packs with closed information\n", c->textdatafield[5]); + fprintf(stderr, "%d packs with UPC/EAN ISRC information\n", c->textdatafield[6]); + fprintf(stderr, "%d packs with size information\n", c->textdatafield[7]); + fprintf(stderr, "last sequence numbers for blocks 1-8: %d %d %d %d " + ,c->textdatafield[8] + ,c->textdatafield[9] + ,c->textdatafield[10] + ,c->textdatafield[11] + ); + break; + case 2: + fprintf(stderr, "%d %d %d %d\n" + ,c->textdatafield[0] + ,c->textdatafield[1] + ,c->textdatafield[2] + ,c->textdatafield[3] + ); + fprintf(stderr, "Language codes for blocks 1-8: %d %d %d %d %d %d %d %d\n" + ,c->textdatafield[4] + ,c->textdatafield[5] + ,c->textdatafield[6] + ,c->textdatafield[7] + ,c->textdatafield[8] + ,c->textdatafield[9] + ,c->textdatafield[10] + ,c->textdatafield[11] + ); + break; + } + fprintf(stderr, "Blocksize"); + dump_binary(c); + return 0; +#if !defined DEBUG_CDTEXT + default: +#else + } +#endif + fprintf(stderr, ": header fields %02x %02x %02x ", + c->headerfield[1], c->headerfield[2], c->headerfield[3]); +#endif /* DETAILED */ + +#if !defined DEBUG_CDTEXT + } +#if DETAILED + if (tracknr == 0) { + fprintf(stderr, " for album : ->"); + } else { + fprintf(stderr, " for track %2u: ->", tracknr); + } + fputs ((char *) line, stderr); + fputs ("<-", stderr); +#endif + + if (dbcc != 0) { +#else + { +#endif + /* EMPTY */ +#if DETAILED + fprintf(stderr, +" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x" + , c->textdatafield[0] + , c->textdatafield[1] + , c->textdatafield[2] + , c->textdatafield[3] + , c->textdatafield[4] + , c->textdatafield[5] + , c->textdatafield[6] + , c->textdatafield[7] + , c->textdatafield[8] + , c->textdatafield[9] + , c->textdatafield[10] + , c->textdatafield[11] + ); +#endif + } + return 0; +} diff --git a/icedax/cdda2mp3 b/icedax/cdda2mp3 new file mode 120000 index 0000000..4a59876 --- /dev/null +++ b/icedax/cdda2mp3 @@ -0,0 +1 @@ +cdda2ogg
\ No newline at end of file diff --git a/icedax/cdda2mp3.new b/icedax/cdda2mp3.new new file mode 100644 index 0000000..ee51829 --- /dev/null +++ b/icedax/cdda2mp3.new @@ -0,0 +1,60 @@ +#!/bin/sh +# Demo script for processing all audio tracks with a mp3 encoder +# This variant creates temporary wav files. There is another +# variant of this script (cdda2mp3), which uses a named pipe +# instead. This variant needs more disk space than the other one. +# +# usage: cdda2mp3.new <name prefix for all mp3 files> +# +# list_audio_tracks is a (symbolic) link to cdda2wav +# and used to generate a list of audio track numbers and start +# sectors, which in turn are used in a loop to spawn cdda2wav +# and the post processor on a track by track basis. + +# +# feedback needed!!!!!!!!!!!!!!!!! +# + +# specify the audio track listing program and its options +LAT=list_audio_tracks +LAT_OPTIONS= + +# specify the sampling program and its options +# do not specify the track option here! +CDDA2WAV=cdda2wav +CDDA2WAV_OPTS='-Owav -H -P0 -q' + +# for normal use, comment out the next line with a # +#DEBUG='-d1' + +# specify the post processing program and its options +MP_CODER=l3enc +#MP_OPTIONS='2>/dev/null 1>/dev/null' +MP_OPTIONS='-br 128000' +#MP_OPTIONS='-hq' + +WAVFILE=$$".wav" + +FILEPREFIX=${1:-audiotrack} + +# clean up wav file on exit, abort, ... +trap "rm -rf $WAVFILE" 0 2 3 4 6 7 8 10 11 12 13 15 + +# feed track numbers and start sectors into loop +$LAT $LAT_OPTIONS | while read TRACK STARTSECTOR; +do + $CDDA2WAV $CDDA2WAV_OPTS -t$TRACK $DEBUG $WAVFILE +# echo n | $MP_CODER $WAVFILE $FILEPREFIX$TRACK.mp3 $MP_OPTIONS + $MP_CODER $WAVFILE $FILEPREFIX$TRACK.mp3 $MP_OPTIONS + + # check result code + RES=$? + if [ $RES = 0 ] ; then + echo File $FILEPREFIX$TRACK.mp3 finished successfully. + rm $WAVFILE + else + echo File $FILEPREFIX$TRACK.mp3 failed \(result $RES\). Aborted. >&2 + break + fi +done + diff --git a/icedax/cdda2ogg b/icedax/cdda2ogg new file mode 100755 index 0000000..0838384 --- /dev/null +++ b/icedax/cdda2ogg @@ -0,0 +1,82 @@ +#! /bin/sh +# Script for processing all audio tracks with an ogg or mp3 decoder +# based on a news article by Tom Kludy +# This variant uses named pipes in order to save space. +# usage: cdda2ogg <name prefix for all ogg/mp3 files> + +# specify the sampling program and its options +# do not specify the track option here! +CDDA2WAV=${CDDA2WAV:-icedax} +CDDA2WAV_OPTS=${CDDA2WAV_OPTS:-'-H -P0 -q'} + +# for normal use, comment out the next line +#DEBUG='-d1' + +# the post processor is fed through a pipe to avoid space waste +# specify the post processing program and its options +case $0 in + *ogg|*OGG|*Ogg) + # ensure the right suffix for suffixes later + suffix=ogg + missmsg="Encoder not found. Install one first! (eg. vorbis-tools)" + MP_CODER=${MP_CODER:-oggenc} + outopt="-o" + ;; + *mp3|*MP3|*mpeg3|*MPEG3|*Mp3) + suffix=mp3 + missmsg="Encoder not found. Install one first! (eg. lame)" + MP_CODER=${MP_CODER:-lame} + outopt="" + ;; + *) + echo Unknown target file type: $suffix. Valid names for this application are: cdda2mp3, cdda2ogg. + exit 1 + ;; +esac + +MP_OPTIONS=${MP_OPTIONS:-''} + +MP_CODER=$(which $MP_CODER 2>/dev/null) +if [ ! -x "$MP_CODER" ] ; then + echo $missmsg + exit 1 +fi + +CDDA_DEVICE=${CDDA_DEVICE:-/dev/cdrw} +export CDDA_DEVICE + +FILEPREFIX=${1:-audiotrack} + +if [ -e /etc/default/cdda2$suffix ]; then + . /etc/default/cdda2$suffix +fi + +if [ -z "$LIST" ] ; then + echo Looking for available tracks... + # could use list_audio_tracks instead but that would need an extra filter as + # well, and this way we do not depend on that symlink + LIST="$( $CDDA2WAV -J -vtoc -H 2>&1 | sed -e 's/^[^\ ].*//; s/\.([^)]*)/ /g;s/,//g;')" + if [ -z "$LIST" ] ; then + echo "ERROR: No valid audio tracks detected" + exit 1 + fi +fi + +echo Fetching `echo $LIST | wc -w` tracks from $CDDA_DEVICE, encoding with $MP_CODER. +echo Cancel with Ctrl-C, watch out for error messages. + +for TRACK in $LIST ; do + NAME="`printf "%02d" $TRACK`-$FILEPREFIX.$suffix" + echo + echo "############ Starting with Track Nr. $TRACK -> $NAME ############" + $CDDA2WAV $CDDA2WAV_OPTS -t$TRACK $DEBUG - | \ + $MP_CODER $MP_OPTIONS - $outopt "$NAME" + + # check result code + RES=$? + if [ $RES != 0 ] ; then + echo File $NAME failed \(result $RES\). Aborted. >&2 + break + fi +done + diff --git a/icedax/cdda2ogg.1 b/icedax/cdda2ogg.1 new file mode 100644 index 0000000..63ac041 --- /dev/null +++ b/icedax/cdda2ogg.1 @@ -0,0 +1,114 @@ +'\" +.TH "cdda2ogg" "1" +.SH "NAME" +cdda2ogg, cdda2mp3 \(em extract audio CD audio tracks and encode them +.SH "SYNOPSIS" +.PP +.B cdda2ogg +.PP +.B cdda2mp3 +.SH "DESCRIPTION" +.PP +.B cdda2ogg is a simple script that uses the +.B icedax <fileprefix> +command to extract all audio tracks with the +.B icedax <fileprefix> +command and encode them using the +.B ogg123 +respective +.I <censored> +MP3 +encoder. The scripts are not intended to be full-featured music archiving +programs, but only for quick storing of few audio data. +It does not use databases like CDDB or have any extra features. You may look +at +.B icedax +if you need them. +.PP +.B ogg123 +is provided by the +.B vorbis-tools +which needs to be installed separately. +See +.B www.ogg.org +for more information. + +.SH "CONFIGURATION" +.PP +.B cdda2ogg +and +.B cdda2mp3 +have predefined values for reading and labeling of the target files. +You can overwrite them with following environment variables: + +.IP "CDDA_DEVICE" 10 +Source device specification to get the data from. + +.IP "LIST" 10 +List of track numbers to be read, separated by spaces. + +.IP "CDDA2WAV" 10 +Defines the command to run the cdda2wav program + +.IP "CDDA2WAV_OPTS" 10 +Miscellaneous options passed to +.IR $CDDA2WAV . + +.IP "MP_CODER" 10 +The encoder program. + +.IP "MP_OPTIONS" 10 +Additional options passed to +.IR $MP_CODER . + +.IP "FILEPREFIX" 10 +The base part of the filename of resulting audio files. This can also be specified as the first argument to the script. + +.PP +See cdda2ogg (cdda2mp3) script file to get the default values +.PP +System administrator can also set default values by creating of a shell +include file, defining the variables for the POSIX shell, and storing them as +/etc/default/cdda2ogg (resp. cdda2mp3). +.SH "EXAMPLES" +.PP +.B CDDA_DEVICE=/dev/cdrom1 cdda2ogg +.br +just stores every track in this device in audiotrackNUMBER.ogg +.PP +.PP +.B LIST="1 5 7" cdda2ogg PartsOfBestOfFoo +.br +stores the selected tracks from the default cdrom device as 01-PartsOfBestOfFoo.ogg, 05-PartsOfBestOfFoo.ogg, 07-PartsOfBestOfFoo.ogg. + +.SH "SEE ALSO" +.BR icedax (1) +.SH "AUTHOR" +.PP +This manpage describes the program implementation of +.B +cdda2ogg +as shipped by the cdrkit distribution. See +.B +http://alioth.debian.org/projects/debburn/ +for details. It is a spinoff from the original program distributed by the cdrtools project. However, the cdrtools developers are not involved in the development of this spinoff and therefore shall not be made responsible for any problem caused by it. Do not try to get support for this program by contacting the original authors. +.PP +If you have support questions, send them to +.PP +.B +debburn-devel@lists.alioth.debian.org +.br +.PP +If you have definitely found a bug, send a mail to this list or to +.PP +.B +submit@bugs.debian.org +.br +.PP +writing at least a short description into the Subject and "Package: cdrkit" into the first line of the mail body. +.PP +This manual page was written by Eduard Bloch +(blade@debian.org) for the +.B "Debian GNU/Linux system (but may be used by others). Permission is granted +to copy, distribute and/or modify this document under the terms of the GNU +General Public License, Version 2 as published by the Free Software Foundation. diff --git a/icedax/cdda2ogg.mk1 b/icedax/cdda2ogg.mk1 new file mode 100644 index 0000000..575933b --- /dev/null +++ b/icedax/cdda2ogg.mk1 @@ -0,0 +1,18 @@ +#ident @(#)Makefile.man 1.1 00/03/21 +########################################################################### +# Sample makefile for installing manual pages +########################################################################### +SRCROOT= .. +RULESDIR= RULES +include $(SRCROOT)/$(RULESDIR)/rules.top +########################################################################### + +MANDIR= man +TARGETMAN= cdda2ogg +MANSECT= $(MANSECT_CMD) +MANSUFFIX= $(MANSUFF_CMD) +MANFILE= cdda2ogg.1 + +########################################################################### +include $(SRCROOT)/$(RULESDIR)/rules.man +########################################################################### diff --git a/icedax/config.h b/icedax/config.h new file mode 100644 index 0000000..d08162e --- /dev/null +++ b/icedax/config.h @@ -0,0 +1,63 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)config.h 1.7 03/10/06 Copyright 1998-2003 Heiko Eissfeldt */ +/* + * a central configuration file + */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <mconfig.h> + +#if __STDC__-0 != 0 || (defined PROTOTYPES && defined STDC_HEADERS) +#define UINT_C(a) (a##u) +#define ULONG_C(a) (a##ul) +#define USHORT_C(a) (a##uh) +#define CONCAT(a,b) a##b +#else +#define UINT_C(a) ((unsigned) a) +#define ULONG_C(a) ((unsigned long) a) +#define USHORT_C(a) ((unsigned short) a) +#define CONCAT(a,b) a/**/b +#endif + +#include "lconfig.h" + +/* temporary until a autoconf check is present */ +#ifdef __BEOS__ +#define HAVE_AREAS 1 +#endif + +#if defined HAVE_FORK && (defined (HAVE_SMMAP) || defined(HAVE_USGSHM) || defined(HAVE_DOSALLOCSHAREDMEM) || defined (HAVE_AREAS)) +#define HAVE_FORK_AND_SHAREDMEM +#undef FIFO +#define FIFO +#else +#undef FIFO +#endif +#if !defined HAVE_MEMMOVE +#define memmove(dst, src, size) movebytes((src), (dst), (size)) +#endif diff --git a/icedax/configure b/icedax/configure new file mode 100755 index 0000000..bbbb61f --- /dev/null +++ b/icedax/configure @@ -0,0 +1,1390 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -cc=* | --cc=* ) + CC="$ac_optarg" ; echo using $CC as compiler ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=cdda2wav.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:556: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + + +CDRTOOLS_VERSION=`sed -n -f ../../version.sed <../../../cdrecord/cdrecord.c` + + + +case "$host_os" in + solaris*|sunos*) +echo $ac_n "checking for sched_get_priority_max in -lposix4""... $ac_c" 1>&6 +echo "configure:584: checking for sched_get_priority_max in -lposix4" >&5 +ac_lib_var=`echo posix4'_'sched_get_priority_max | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lposix4 $LIBS" +cat > conftest.$ac_ext <<EOF +#line 592 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char sched_get_priority_max(); + +int main() { +sched_get_priority_max() +; return 0; } +EOF +if { (eval echo configure:603: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo posix4 | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lposix4 $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +;; +esac +echo $ac_n "checking for _oss_ioctl in -lossaudio""... $ac_c" 1>&6 +echo "configure:633: checking for _oss_ioctl in -lossaudio" >&5 +ac_lib_var=`echo ossaudio'_'_oss_ioctl | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lossaudio $LIBS" +cat > conftest.$ac_ext <<EOF +#line 641 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _oss_ioctl(); + +int main() { +_oss_ioctl() +; return 0; } +EOF +if { (eval echo configure:652: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo ossaudio | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lossaudio $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +EXTRALIBS="$LIBS" + + + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:685: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 700 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:706: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 717 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:723: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 734 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:740: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_hdr in sys/cdio.h sys/cdrio.h sundev/srreg.h sys/audioio.h sun/audioio.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:768: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 773 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:778: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in soundcard.h sys/soundcard.h linux/soundcard.h machine/soundcard.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:808: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 813 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:818: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in sys/asoundlib.h windows.h mmsystem.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:848: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 853 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:858: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +for ac_hdr in os2.h os2me.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:888: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 893 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:898: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +case "${ac_cv_header_sys_cdio_h}""${ac_cv_header_sundev_srreg_h}" in + *yes*) +HAVE_SUN_IOCTL=1 +;; + *) +HAVE_SUN_IOCTL= +;; +esac + + +case "${ac_cv_header_sys_audioio_h}""${ac_cv_header_sun_audioio_h}" in + *yes*) +HAVE_SUNSOUND=1 +;; + *) +HAVE_SUNSOUND= +;; +esac + + +case "${ac_cv_header_machine_soundcard_h}""${ac_cv_header_sys_soundcard_h}""${ac_cv_header_linux_soundcard_h}" in + *yes*) +HAVE_OSS=1 +;; + *) +HAVE_OSS= +;; +esac + + + + +case "${ac_cv_header_windows_h}""${ac_cv_header_mmsystem_h}" in + *yesyes*) +HAVE_WINSOUND=1 +;; + *) +HAVE_WINSOUND= +;; +esac + + +case "${ac_cv_header_os2_h}""${ac_cv_header_os2me_h}" in + *yesyes*) +HAVE_OS2SOUND=1 +;; + *) +HAVE_OS2SOUND= +;; +esac + + +for ac_func in strtoul +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:980: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 985 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1008: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir + +trap 'rm -fr `echo "local.cnf lconfig.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@CDRTOOLS_VERSION@%$CDRTOOLS_VERSION%g +s%@EXTRALIBS@%$EXTRALIBS%g +s%@CPP@%$CPP%g +s%@HAVE_SUN_IOCTL@%$HAVE_SUN_IOCTL%g +s%@HAVE_SUNSOUND@%$HAVE_SUNSOUND%g +s%@HAVE_OSS@%$HAVE_OSS%g +s%@HAVE_SYS_ASOUNDLIB_H@%$HAVE_SYS_ASOUNDLIB_H%g +s%@HAVE_WINSOUND@%$HAVE_WINSOUND%g +s%@HAVE_OS2SOUND@%$HAVE_OS2SOUND%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"local.cnf"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="lconfig.h" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/icedax/configure.in b/icedax/configure.in new file mode 100644 index 0000000..5229ef9 --- /dev/null +++ b/icedax/configure.in @@ -0,0 +1,88 @@ +dnl @(#)configure.in 1.8 06/02/15 Copyright 1998-2003 Heiko Eißfeldt +dnl Process this file with autoconf to produce a configure script. +AC_INIT(cdda2wav.c) +AC_CONFIG_HEADER(lconfig.h) + +dnl get canonical host +AC_CANONICAL_HOST + +dnl extract cdrtools version from the cdrecord.c file +CDRTOOLS_VERSION=`sed -n -f ../../version.sed <../../../cdrecord/cdrecord.c` +AC_SUBST(CDRTOOLS_VERSION) + +dnl set object extension needed for AC_CHECK_HEADERS by autoconf 2.57 +dnl _AC_COMPILER_OBJEXT + +dnl check for posix4 library on Solaris or SunOS +case "$host_os" in + solaris*|sunos*) +AC_CHECK_LIB(posix4, sched_get_priority_max) +;; +esac +AC_CHECK_LIB(ossaudio, _oss_ioctl) + +EXTRALIBS="$LIBS" + +AC_SUBST(EXTRALIBS) + +dnl check header files +AC_CHECK_HEADERS(sys/cdio.h sys/cdrio.h sundev/srreg.h sys/audioio.h sun/audioio.h) +AC_CHECK_HEADERS(soundcard.h sys/soundcard.h linux/soundcard.h machine/soundcard.h) +AC_CHECK_HEADERS(sys/asoundlib.h windows.h mmsystem.h) +AC_CHECK_HEADERS(os2.h os2me.h) + +case "${ac_cv_header_sys_cdio_h}""${ac_cv_header_sundev_srreg_h}" in + *yes*) +HAVE_SUN_IOCTL=1 +;; + *) +HAVE_SUN_IOCTL= +;; +esac +AC_SUBST(HAVE_SUN_IOCTL) + +case "${ac_cv_header_sys_audioio_h}""${ac_cv_header_sun_audioio_h}" in + *yes*) +HAVE_SUNSOUND=1 +;; + *) +HAVE_SUNSOUND= +;; +esac +AC_SUBST(HAVE_SUNSOUND) + +case "${ac_cv_header_machine_soundcard_h}""${ac_cv_header_sys_soundcard_h}""${ac_cv_header_linux_soundcard_h}" in + *yes*) +HAVE_OSS=1 +;; + *) +HAVE_OSS= +;; +esac +AC_SUBST(HAVE_OSS) + +AC_SUBST(HAVE_SYS_ASOUNDLIB_H) + +case "${ac_cv_header_windows_h}""${ac_cv_header_mmsystem_h}" in + *yesyes*) +HAVE_WINSOUND=1 +;; + *) +HAVE_WINSOUND= +;; +esac +AC_SUBST(HAVE_WINSOUND) + +case "${ac_cv_header_os2_h}""${ac_cv_header_os2me_h}" in + *yesyes*) +HAVE_OS2SOUND=1 +;; + *) +HAVE_OS2SOUND= +;; +esac +AC_SUBST(HAVE_OS2SOUND) + +dnl Checks for library functions. +AC_CHECK_FUNCS(strtoul) +AC_OUTPUT(local.cnf) diff --git a/icedax/exitcodes.h b/icedax/exitcodes.h new file mode 100644 index 0000000..b75b171 --- /dev/null +++ b/icedax/exitcodes.h @@ -0,0 +1,37 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)exitcodes.h 1.1 02/11/21 Copyright 2002 Heiko Eissfeldt */ +/* header file for system wide exit codes. */ +#ifndef exitcodes_h +#define exitcodes_h + +#define NO_ERROR 0 +#define SYNTAX_ERROR 1 +#define PERM_ERROR 2 +#define READ_ERROR 3 +#define WRITE_ERROR 4 +#define SOUND_ERROR 5 +#define STAT_ERROR 6 +#define SIGPIPE_ERROR 7 +#define SETSIG_ERROR 8 +#define SHMMEM_ERROR 9 +#define NOMEM_ERROR 10 +#define MEDIA_ERROR 11 +#define DEVICEOPEN_ERROR 12 +#define RACE_ERROR 13 +#define DEVICE_ERROR 14 +#define INTERNAL_ERROR 15 +#define SEMAPHORE_ERROR 16 +#define SETUPSCSI_ERROR 17 +#define PIPE_ERROR 18 +#endif diff --git a/icedax/global.h b/icedax/global.h new file mode 100644 index 0000000..fc80c78 --- /dev/null +++ b/icedax/global.h @@ -0,0 +1,133 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)global.h 1.11 04/07/29 Copyright 1998-2004 Heiko Eissfeldt */ +/* Global Variables */ + +#ifdef MD5_SIGNATURES +#include "md5.h" +#endif +#ifdef USE_PARANOIA +#include "cdda_paranoia.h" +#endif + +typedef struct index_list +{ + struct index_list *next; + int frameoffset; +} +index_list; + +typedef struct global +{ + + char *dev_name; /* device name */ + char *aux_name; /* device name */ + char fname_base[200]; + + int have_forked; + int parent_died; + int audio; + struct soundfile *audio_out; + int cooked_fd; + int no_file; + int no_infofile; + int no_cddbfile; + int quiet; + int verbose; + int scsi_silent; + int scsi_verbose; + int scanbus; + int scandevs; + int multiname; + int sh_bits; + int Remainder; + int SkippedSamples; + int OutSampleSize; + int need_big_endian; + int need_hostorder; + int channels; + unsigned long iloop; + unsigned long nSamplesDoneInTrack; + unsigned overlap; + int useroverlap; + unsigned nsectors; + unsigned buffers; + unsigned shmsize; + long pagesize; + int in_lendian; + int outputendianess; + int findminmax; + int maxamp[2]; + int minamp[2]; + unsigned speed; + int userspeed; + int ismono; + int findmono; + int swapchannels; + int deemphasize; + int gui; + long playback_rate; + int target; /* SCSI Id to be used */ + int lun; /* SCSI Lun to be used */ + UINT4 cddb_id; + int cddbp; + char * cddbp_server; + char * cddbp_port; + unsigned cddb_revision; + int cddb_year; + char cddb_genre[60]; + int illleadout_cd; + int reads_illleadout; + unsigned char *cdindex_id; + unsigned char *creator; + unsigned char *copyright_message; + unsigned char *disctitle; + unsigned char *tracktitle[100]; + unsigned char *trackcreator[100]; + index_list *trackindexlist[100]; + + int paranoia_selected; +#ifdef USE_PARANOIA + cdrom_paranoia *cdp; + + struct paranoia_parms_t + { + Ucbit disable_paranoia:1; + Ucbit disable_extra_paranoia:1; + Ucbit disable_scratch_detect:1; + Ucbit disable_scratch_repair:1; + int retries; + int overlap; + int mindynoverlap; + int maxdynoverlap; + } + paranoia_parms; +#endif + + unsigned md5blocksize; +#ifdef MD5_SIGNATURES + int md5count; + MD5_CTX context; + unsigned char MD5_result[16]; +#endif + +#ifdef ECHO_TO_SOUNDCARD + int soundcard_fd; +#endif + int echo; + + int just_the_toc; +} +global_t; + +extern global_t global; diff --git a/icedax/icedax.1 b/icedax/icedax.1 new file mode 100644 index 0000000..d9daddb --- /dev/null +++ b/icedax/icedax.1 @@ -0,0 +1,1025 @@ +'\" t +.\" @(#)icedax.1 1.14 02/12/09 Copyright 1998,1999,2000 Heiko Eissfeldt +.if t .ds a \v'-0.55m'\h'0.00n'\z.\h'0.40n'\z.\v'0.55m'\h'-0.40n'a +.if t .ds o \v'-0.55m'\h'0.00n'\z.\h'0.45n'\z.\v'0.55m'\h'-0.45n'o +.if t .ds u \v'-0.55m'\h'0.00n'\z.\h'0.40n'\z.\v'0.55m'\h'-0.40n'u +.if t .ds A \v'-0.77m'\h'0.25n'\z.\h'0.45n'\z.\v'0.77m'\h'-0.70n'A +.if t .ds O \v'-0.77m'\h'0.25n'\z.\h'0.45n'\z.\v'0.77m'\h'-0.70n'O +.if t .ds U \v'-0.77m'\h'0.30n'\z.\h'0.45n'\z.\v'0.77m'\h'-0.75n'U +.if t .ds s \\(*b +.if t .ds S SS +.if n .ds a ae +.if n .ds o oe +.if n .ds u ue +.if n .ds s sz +.if t .ds m \\(*m +.if n .ds m micro +.TH ICEDAX 1 +.SH NAME +icedax \- a sampling utility that dumps CD audio data into wav sound +files +.SH SYNOPSIS +.B icedax +.RB [ -c +.IR chans ] +.RB [ -s ] +.RB [ -m ] +.RB [ -b +.IR bits ] +.RB [ -r +.IR rate ] +.RB [ -a +.IR divider ] +.RB [ -t +.IR track [ +endtrack ]] +.RB [ -i +.IR index ] +.RB [ -o +.IR offset ] +.RB [ -d +.IR duration ] +.RB [ -x ] +.RB [ -q ] +.RB [ -w ] +.RB [ -v +.IR optlist ] +.RB [ -V ] +.RB [ -Q ] +.RB [ -J ] +.RB [ -L +.IR cddbmode ] +.RB [ -R ] +.RB [ -P +.IR sectors ] +.RB [ -F ] +.RB [ -G ] +.RB [ -T ] +.RB [ -e ] +.RB [ -p +.IR percentage ] +.RB [ -n +.IR sectors ] +.RB [ -l +.IR buffers ] +.RB [ -N ] +.RB [ -J ] +.RB [ -H ] +.RB [ -g ] +.RB [ -B ] +.RB [ -D +.IR device ] +.RB [ -A +.IR auxdevice ] +.RB [ -I +.IR interface ] +.RB [ -O +.IR audiotype ] +.RB [ -C +.IR input-endianess ] +.RB [ -E +.IR output-endianess ] +.RB [ -M +.IR count ] +.RB [ -S +.IR speed ] +.RB [ -paranoia ] +.RB [ cddbp-server=servername ] +.RB [ cddbp-port=portnumber ] +.RI [ filename(s) +or +.IR directories ] +.SH DESCRIPTION +.B icedax +stands for InCrEdible Digital Audio eXtractor. It can retrieve audio tracks +.RB ( CDDA ) +from CDROM drives +that are +capable of reading audio data digitally to the host +(see README for a list of drives). + +.SH OPTIONS +.TP +.BI dev= device +.TP +.BI \-D " device +.TP +.BI \-device " device +uses +.B device +as the source for CDDA reading. For example +.B /dev/cdrom +or +.B Bus,ID,Lun. +The device specification can also have influence on the selection of the driver interface (eg. on Linux). +See the +.B \-I +option for details. +.sp +The setting of the environment variable +.B CDDA_DEVICE +is overridden by this option. +.TP +.BI \-A " auxdevice +.TP +.BI \-auxdevice " auxdevice +uses +.B auxdevice +as CDROM drive for ioctl usage. +.TP +.BI \-I " interface +.TP +.BI \-interface " interface +specifies the interface for CDROM access: +.B generic_scsi +or (on Linux, and FreeBSD systems) +.BR cooked_ioctl . +.sp +Using the +.B cooked_ioctl +is not recommended as this makes +.B icedax +mainly depend on the audio extraction quality of the operating system +which is usually extremely bad. +.TP +.BI \-c " channels --channels" +uses +.B 1 +for mono, or +.B 2 +for stereo recording, +or +.B s +for stereo recording with both channels swapped. +.TP +.B \-s " --stereo" +sets to stereo recording. +.TP +.B \-m " --mono" +sets to mono recording. +.TP +.B \-x " --max" +sets maximum (CD) quality. +.TP +.BI \-b " bits --bits-per-sample" +sets bits per sample per channel: +.BR 8 , +.B 12 +or +.BR 16 . +.TP +.BI \-r " rate --rate" +sets rate in samples per second. Possible values are listed with the +.B \-R +option. +.TP +.BI \-a " divider --divider" +sets rate to 44100Hz / divider. Possible values are listed with the +.B \-R +option. +.TP +.B \-R " --dump-rates" +shows a list of all sample rates and their dividers. +.TP +.B \-P " sectors --set-overlap" +sets the initial number of overlap +.I sectors +for jitter correction. +.TP +.BI \-n " sectors --sectors-per-request" +reads +.I sectors +per request. +.TP +.BI \-l " buffers --buffers-in-ring" +uses a ring buffer with +.I buffers +total. +.TP +.BI \-t " track+endtrack --track" +selects the start track and optionally the end track. +.TP +.BI \-i " index --index" +selects the start index. +.TP +.BI \-o " offset --offset" +starts +.I offset +sectors behind start track (one sector equivalents 1/75 seconds). +.TP +.B \-O " audiotype --output-format" +can be +.I wav +(for wav files) or +.I aiff +(for apple/sgi aiff files) or +.I aifc +(for apple/sgi aifc files) or +.I au +or +.I sun +(for sun .au PCM files) or +.I cdr +or +.I raw +(for headerless files to be used for cd writers). +.TP +.BI \-C " endianess --cdrom-endianess" +sets endianess of the input samples to 'little', 'big' or 'guess' to override defaults. +.TP +.BI \-E " endianess --output-endianess" +sets endianess of the output samples to 'little' or 'big' to override defaults. +.TP +.BI \-d " duration --duration" +sets recording time in seconds or frames. +Frames (sectors) are indicated by a 'f' suffix (like 75f for 75 sectors). +.B 0 +sets the time for whole track. +.TP +.B \-B " --bulk --alltracks" +copies each track into a separate file. +.TP +.B \-w " --wait" +waits for signal, then start recording. +.TP +.B \-F " --find-extremes" +finds extreme amplitudes in samples. +.TP +.B \-G " --find-mono" +finds if input samples are in mono. +.TP +.B \-T " --deemphasize" +undo the effect of pre-emphasis in the input samples. +.TP +.B \-e " --echo" +copies audio data to sound device e.g. +.BR /dev/dsp . +.TP +.B \-p " percentage --set-pitch" +changes pitch of audio data copied to sound device. +.TP +.B \-v " itemlist --verbose-level" +prints verbose information about the CD. +.B Level +is a list of comma separated suboptions. Each suboption controls the type of information to be reported. +.TS H +allbox; +c cw(1i) +r l. +Suboption Description +disable no information is given, warnings appear however +all all information is given +toc show table of contents +summary show a summary of the recording parameters +indices determine and display index offsets +catalog retrieve and display the media catalog number MCN +trackid T{ +.na +retrieve and display all International Standard Recording Codes ISRC +T} +sectors T{ +.na +show the table of contents in start sector notation +T} +titles T{ +.na +show the table of contents with track titles (when available) +T} +.TE +.TP +.B \-N " --no-write" +does not write to a file, it just reads (for debugging purposes). +.TP +.B \-J " --info-only" +does not write to a file, it just gives information about the disc. +.TP +.B \-L " cddb mode --cddb" +does a cddbp album- and track title lookup based on the cddb id. +The parameter cddb mode defines how multiple entries shall be handled. +.TS H +allbox; +c cw(4i) +r l. +Parameter Description +0 T{ +.na +interactive mode. The user selects the entry to use. +T} +1 T{ +.na +first fit mode. The first entry is taken unconditionally. +T} +.TE +.TP +.B " cddbp-server=servername" +sets the server to be contacted for title lookups. +.TP +.B " cddbp-port=portnumber" +sets the port number to be used for title lookups. +.TP +.B \-H " --no-infofile" +does not write an info file and a cddb file. +.TP +.B \-g " --gui" +formats the output to be better parsable by gui frontends. +.TP +.B \-M " count --md5" +enables calculation of MD-5 checksum for 'count' bytes from a beginning of a +track. +.TP +.B \-S " speed --speed" +sets the cdrom device to one of the selectable speeds for reading. +.TP +.B \-q " --quiet" +quiet operation, no screen output. +.TP +.B \-V " --verbose-SCSI" +enable SCSI command logging to the console. This is mainly used for debugging. +.TP +.B \-Q " --silent-SCSI" +suppress SCSI command error reports to the console. This is mainly used for guis. +.TP +.B \-scanbus +Scan all SCSI devices on all SCSI busses and print the inquiry +strings. This option may be used to find SCSI address of the +CD/DVD-Recorder on a system. +The numbers printed out as labels are computed by: +.B "bus * 100 + target +.TP +.B \-\-devices +Like \-scanbus but works in a more native way, respecting the device name +specification on the current operating system. See +.B wodim(1) +for details. +.TP +.B \-paranoia +use the paranoia library instead of icedax's routines for reading. +.TP +.B \-h " --help" +display version of icedax on standard output. +.TP +Defaults depend on the +.B Makefile +and +.B environment variable +settings (currently +.B CDDA_DEVICE +). +.SH "ENVIRONMENT VARIABLES" +.B CDDA_DEVICE +is used to set the device name. The device naming is compatible with the one +used by the wodim tool. +.TP +.B CDDBP_SERVER +is used for cddbp title lookups when supplied. +.TP +.B CDDBP_PORT +is used for cddbp title lookups when supplied. +.TP +.B RSH +If the +.B RSH +environment variable is present, the remote connection will not be created via +.BR rcmd (3) +but by calling the program pointed to by +.BR RSH . +Use e.g. +.BR RSH= /usr/bin/ssh +to create a secure shell connection. +.sp +Note that this forces +.B icedax +to create a pipe to the +.B rsh(1) +program and disallows +.B icedax +to directly access the network socket to the remote server. +This makes it impossible to set up performance parameters and slows down +the connection compared to a +.B root +initiated +.B rcmd(3) +connection. +.TP +.B RSCSI +If the +.B RSCSI +environment variable is present, the remote SCSI server will not be the program +.B /opt/schily/sbin/rscsi +but the program pointed to by +.BR RSCSI . +Note that the remote SCSI server program name will be ignored if you log in +using an account that has been created with a remote SCSI server program as +login shell. +.SH "RETURN VALUES" +.B icedax +uses the following exit codes to indicate various degrees of success: +.TS H +allbox; +c cw(1i) +r l. +Exitcode Description +0 no errors encountered, successful operation. +1 usage or syntax error. icedax got inconsistent arguments. +2 permission (un)set errors. permission changes failed. +3 read errors on the cdrom/burner device encountered. +4 T{ +.na +write errors while writing one of the output files encountered. +T} +5 errors with soundcard handling (initialization/write). +6 T{ +.na +errors with stat() system call on the read device (cooked ioctl). +T} +7 pipe communication errors encountered (in forked mode). +8 signal handler installation errors encountered. +9 allocation of shared memory failed (in forked mode). +10 dynamic heap memory allocation failed. +11 errors on the audio cd medium encountered. +12 device open error in ioctl handling detected. +13 race condition in ioctl interface handling detected. +14 error in ioctl() operation encountered. +15 internal error encountered. Please report back!!! +16 T{ +.na +error in semaphore operation encountered (install / request). +T} +17 could not get the scsi transfer buffer. +18 T{ +.na +could not create pipes for process communication (in forked mode). +T} +.TE +.SH "DISCUSSION" +.B icedax +is able to read parts of an +.B audio +CD or +.B multimedia +CDROM (containing audio parts) directly digitally. These parts can be +written to a file, a pipe, or to a sound device. +.PP +.B icedax +stands for +.B CDDA +to +.B WAV +(where +.B CDDA +stands for compact disc digital audio and +.B WAV +is a sound sample format introduced by MS Windows). It +allows copying +.B CDDA +audio data from the CDROM drive into a file in +.B WAV +or other formats. +.PP +The latest versions try to get higher real-time scheduling priorities to ensure +smooth (uninterrupted) operation. These priorities are available for super users +and are higher than those of 'normal' processes. Thus delays are minimized. +.PP +If your CDROM is on device +.B DEV +and it is loaded with an audio CD, you may simply invoke +.B icedax dev=DEV +and it will create the sound file +.B audio.wav +recording the whole track beginning with track 1 in stereo at 16 bit at 44100 +Hz sample rate, if your file system has enough space free. Otherwise +recording time will be limited. For details see files +.B README +and +.B README.INSTALL +. +.SH "HINTS ON OPTIONS" +.IP "Options" +Most of the options are used to control the format of the WAV file. In +the following text all of them are described. +.IP "Select Device" +.BI \-D " device" +selects the CDROM drive device to be used. +The specifier given should correspond to the selected interface (see below). +.B CHANGE! +For the cooked_ioctl interface this is the cdrom device descriptor as before. +.B The SCSI devices used with the generic SCSI interface however are now +.B addressed with their SCSI-Bus, SCSI-Id, and SCSI-Lun instead of the generic +.B SCSI device descriptor!!! +One example for a SCSI CDROM drive on bus 0 with SCSI ID 3 and lun 0 is -D0,3,0. +.IP "Select Auxiliary device" +.BI \-A " auxdevice" +is necessary for CD-Extra handling. For Non-SCSI-CDROM drives this is the +same device as given by -D (see above). For SCSI-CDROM drives it is the +CDROM drive (SCSI) device (i.e. +.B /dev/sr0 +) corresponding to the SCSI device (i.e. +.B 0,3,0 +). It has to match the device used for sampling. +.IP "Select Interface" +.BI \-I " interface" +selects the CDROM drive interface. For SCSI drives use generic_scsi +(cooked_ioctl may not yet be available for all devices): +.B generic_scsi +and +.BR cooked_ioctl . +The first uses the generic SCSI interface, the latter uses the ioctl of +the CDROM driver. The latter variant works only when the kernel driver supports +.B CDDA +reading. This entry has to match the selected CDROM device (see above). +.IP "Enable echo to soundcard" +.B \-e +copies audio data to the sound card while recording, so you hear it nearly +simultaneously. The soundcard gets the same data that is recorded. This +is time critical, so it works best with the +.B \-q +option. To use +.B icedax +as a pseudo CD player without recording in a file you could use +.B "icedax \-q \-e \-t2 \-d0 \-N" +to play the whole second track. This feature reduces the recording speed +to at most onefold speed. You cannot make better recordings than your sound card +can play (since the same data is used). +.IP "Change pitch of echoed audio" +.B "\-p percentage" +changes the pitch of all audio echoed to a sound card. Only the copy +to the soundcard is affected, the recorded audio samples in a file +remain the same. +Normal pitch, which is the default, is given by 100%. +Lower percentages correspond to lower pitches, i.e. +-p 50 transposes the audio output one octave lower. +See also the script +.B pitchplay +as an example. This option was contributed by Raul Sobon. +.IP "Select mono or stereo recording" +.B \-m +or +.B "\-c 1" +selects mono recording (both stereo channels are mixed), +.B \-s +or +.B "\-c 2" +or +.B "\-c s" +selects stereo recording. Parameter s +will swap both sound channels. +.IP "Select maximum quality" +.B \-x +will set stereo, 16 bits per sample at 44.1 KHz (full CD quality). Note +that other format options given later can change this setting. +.IP "Select sample quality" +.B "\-b 8" +specifies 8 bit (1 Byte) for each sample in each channel; +.B "\-b 12" +specifies 12 bit (2 Byte) for each sample in each channel; +.B "\-b 16" +specifies 16 bit (2 Byte) for each sample in each channel (Ensure that +your sample player or sound card is capable of playing 12-bit or 16-bit +samples). Selecting 12 or 16 bits doubles file size. 12-bit samples are +aligned to 16-bit samples, so they waste some disk space. +.IP "Select sample rate" +.BI \-r " samplerate" +selects a sample rate. +.I samplerate +can be in a range between 44100 and 900. Option +.B \-R +lists all available rates. +.IP "Select sample rate divider" +.BI \-a " divider" +selects a sample rate divider. +.I divider +can be minimally 1 and maximally 50.5 and everything between in steps of 0.5. +Option +.B \-R +lists all available rates. +.IP +To make the sound smoother at lower sampling rates, +.B icedax +sums over +.I n +samples (where +.I n +is the specific dividend). So for 22050 Hertz output we have to sum over +2 samples, for 900 Hertz we have to sum over 49 samples. This cancels +higher frequencies. Standard sector size of an audio CD (ignoring +additional information) is 2352 Bytes. In order to finish summing +for an output sample at sector boundaries the rates above have to be +chosen. Arbitrary sampling rates in high quality would require some +interpolation scheme, which needs much more sophisticated programming. +.IP "List a table of all sampling rates" +.BI \-R +shows a list of all sample rates and their dividers. Dividers can range +from 1 to 50.5 in steps of 0.5. +.IP "Select start track and optionally end track" +.BI \-t " n+m" +selects +.B n +as the start track and optionally +.B m +as the last track of a range to be recorded. +These tracks must be from the table of contents. This sets +the track where recording begins. Recording can advance through the +following tracks as well (limited by the optional end track or otherwise +depending on recording time). Whether one file or different files are +then created depends on the +.B \-B +option (see below). +.IP "Select start index" +.BI \-i " n" +selects the index to start recording with. Indices other than 1 will +invoke the index scanner, which will take some time to find the correct +start position. An offset may be given additionally (see below). +.IP "Set recording time" +.B \-d " n" +sets recording time to +.I n +seconds or set recording time for whole track if +.I n +is zero. In order to specify the duration in frames (sectors) also, the +argument can have an appended 'f'. Then the numerical argument is to be +taken as frames (sectors) rather than seconds. +Please note that if track ranges are being used they define the recording +time as well thus overriding any +.BR \-d " option" +specified times. +.IP +Recording time is defined as the time the generated sample will play (at +the defined sample rate). Since it's related to the amount of generated +samples, it's not the time of the sampling process itself (which can be +less or more). It's neither strictly coupled with the time information on +the audio CD (shown by your hifi CD player). +Differences can occur by the usage of the +.B \-o +option (see below). Notice that recording time will be shortened, unless +enough disk space exists. Recording can be aborted at anytime by +pressing the break character (signal SIGQUIT). + .IP "Record all tracks of a complete audio CD in separate files" +.B \-B +copies each track into a separate file. A base name can be given. File names +have an appended track number and an extension corresponding to the audio +format. To record all audio tracks of a CD, use a sufficient high duration +(i.e. -d99999). +.IP "Set start sector offset" +.BI \-o " sectors" +increments start sector of the track by +.IR sectors . +By this option you are able to skip a certain amount at the beginning of +a track so you can pick exactly the part you want. Each sector runs for 1/75 +seconds, so you have very fine control. If your offset is so high that +it would not fit into the current track, a warning message is issued +and the offset is ignored. Recording time is not reduced. (To skip +introductory quiet passages automagically, use the +.B \-w +option see below.) +.IP "Wait for signal option" +.B \-w +Turning on this option will suppress all silent output at startup, +reducing possibly file size. +.B icedax +will watch for any signal in the output signal and switches on writing +to file. +.IP "Find extreme samples" +.B \-F +Turning on this option will display the most negative and the most positive +sample value found during recording for both channels. This can be useful +for readjusting the volume. The values shown are not reset at track +boundaries, they cover the complete sampling process. They are taken from +the original samples and have the same format (i.e. they are independent +of the selected output format). +.IP "Find if input samples are in mono" +.B \-G +If this option is given, input samples for both channels will be compared. At +the end of the program the result is printed. Differences in the channels +indicate stereo, otherwise when both channels are equal it will indicate mono. +.IP "Undo the pre-emphasis in the input samples" +.B \-T +Some older audio CDs are recorded with a modified frequency response called +pre-emphasis. This is found mostly in classical recordings. The correction +can be seen in the flags of the Table Of Contents often. But there are +recordings, that show this setting only in the subchannels. If this option +is given, the index scanner will be started, which reads the q-subchannel +of each track. If pre-emphasis is indicated in the q-subchannel of a track, +but not in the TOC, pre-emphasis will be assumed to be present, and +subsequently a reverse filtering is done for this track before the samples +are written into the audio file. +.IP "Set audio format" +.B \-O " audiotype" +can be +.I wav +(for wav files) or +.I au +or +.I sun +(for sun PCM files) or +.I cdr +or +.I raw +(for headerless files to be used for cd writers). +All file samples are coded in linear pulse code modulation (as done +in the audio compact disc format). This holds for all audio formats. +Wav files are compatible to Wind*ws sound files, they have lsb,msb byte order +as being used on the audio cd. The default filename extension is '.wav'. +Sun type files are not like the older common logarithmically coded .au files, +but instead as mentioned above linear PCM is used. The byte order is msb,lsb +to be compatible. The default filename extension is '.au'. +The AIFF and the newer variant AIFC from the Apple/SGI world store their samples +in bigendian format (msb,lsb). In AIFC no compression is used. +Finally the easiest 'format', +the cdr aka raw format. It is done per default in msb,lsb byte order to satisfy +the order wanted by most cd writers. Since there is no header information in this +format, the sample parameters can only be identified by playing the samples +on a soundcard or similar. The default filename extension is '.cdr' or '.raw'. +.IP "Select cdrom drive reading speed" +.B \-S " speed" +allows to switch the cdrom drive to a certain level of speed in order to +reduce read errors. The argument is transfered verbatim to the drive. +Details depend very much on the cdrom drives. +An argument of 0 for example is often the default speed of the drive, +a value of 1 often selects single speed. +.IP "Enable MD5 checksums" +.B \-M " count" +enables calculation of MD-5 checksum for 'count' bytes from the beginning of a +track. This was introduced for quick comparisons of tracks. +.IP "Use Monty's libparanoia for reading of sectors" +.B \-paranoia +selects an alternate way of extracting audio sectors. Monty's library is used +with the following default options: +.sp +PARANOIA_MODE_FULL, but without PARANOIA_MODE_NEVERSKIP +.sp +for details see Monty's libparanoia documentation. +In this case the option +.B \-P +has no effect. +.IP "Do linear or overlapping reading of sectors" +(This applies unless option +.B \-paranoia +is used.) +.B \-P " sectors" +sets the given number of sectors for initial overlap sampling for jitter +correction. Two cases are to be distinguished. For nonzero values, +some sectors are read twice to enable icedax's jitter correction. +If an argument of zero is given, no overlap sampling will be used. +For nonzero overlap sectors icedax dynamically adjusts the setting during +sampling (like cdparanoia does). +If no match can be found, icedax retries the read with an increased overlap. +If the amount of jitter is lower than the current overlapped samples, icedax +reduces the overlap setting, resulting in a higher reading speed. +The argument given has to be lower than the total number of sectors per request +(see option +.I -n +below). +Icedax will check this setting and issues a error message otherwise. +The case of zero sectors is nice on low load situations or errorfree (perfect) +cdrom drives and perfect (not scratched) audio cds. +.IP "Set the transfer size" +.B \-n " sectors" +will set the transfer size to the specified sectors per request. +.IP "Set number of ring buffer elements" +.B \-l " buffers" +will allocate the specified number of ring buffer elements. +.IP "Set endianess of input samples" +.B \-C " endianess" +will override the default settings of the input format. +Endianess can be set explicitly to "little" or "big" or to the automatic +endianess detection based on voting with "guess". +.IP "Set endianess of output samples" +.B \-E " endianess" +(endianess can be "little" or "big") will override the default settings +of the output format. +.IP "Verbose option" +.B \-v " itemlist" +prints more information. A list allows selection of different +information items. +.sp +.B "disable" +keeps quiet +.sp +.B "toc" +displays the table of contents +.sp +.B "summary" +displays a summary of recording parameters +.sp +.B "indices" +invokes the index scanner and displays start positions of indices +.sp +.B "catalog" +retrieves and displays a media catalog number +.sp +.B "trackid" +retrieves and displays international standard recording codes +.sp +.B "sectors" +displays track start positions in absolute sector notation +.sp +To combine several requests just list the suboptions separated with commas. +.IP "The table of contents" +The display will show the table of contents with number of tracks and +total time (displayed in +.IR mm : ss . hh +format, +.IR mm =minutes, +.IR ss =seconds, +.IR hh "=rounded 1/100 seconds)." +The following list displays track number and track time for each entry. +The summary gives a line per track describing the type of the track. +.sp +.ce 1 +.B "track preemphasis copypermitted tracktype chans" +.sp +The +.B track +column holds the track number. +.B preemphasis +shows if that track has been given a non linear frequency response. +NOTE: You can undo this effect with the +.B \-T +option. +.B "copy-permitted" +indicates if this track is allowed to copy. +.B "tracktype" +can be data or audio. On multimedia CDs (except hidden track CDs) +both of them should be present. +.B "channels" +is defined for audio tracks only. There can be two or four channels. +.IP "No file output" +.B \-N +this debugging option switches off writing to a file. +.IP "No infofile generation" +.B \-H +this option switches off creation of an info file and a cddb file. +.IP "Generation of simple output for gui frontends" +.B \-g +this option switches on simple line formatting, which is needed to support +gui frontends (like xcd-roast). +.IP "Verbose SCSI logging" +.B \-V +this option switches on logging of SCSI commands. This will produce +a lot of output (when SCSI devices are being used). +This is needed for debugging purposes. The format +is the same as being used with the cdrecord program from J\*org Schilling or +the wodim tool. See there for details. +.IP "Quiet option" +.B \-q +suppresses all screen output except error messages. +That reduces cpu time resources. +.IP "Just show information option" +.B \-J +does not write a file, it only prints information about the disc (depending +on the +.B \-v +option). This is just for information purposes. +.SH "CDDBP support" +.IP "Lookup album and track titles option" +.B \-L " cddbp mode" +Icedax tries to retrieve performer, album-, and track titles from a cddbp +server. The default server right now is 'freedb.freedb.org'. +It is planned to have more control over the server handling later. +The parameter defines how multiple entries are handled: +.PP +0 interactive mode, the user chooses one of the entries. +.PP +1 take the first entry without asking. +.IP "Set server for title lookups" +.B cddbp-server " servername" +When using \-L or --cddb, the server being contacted can be set with +this option. +.IP "Set portnumber for title lookups" +.B cddbp-port " portnumber" +When using \-L or --cddb, the server port being contacted can be set with +this option. +.SH "HINTS ON USAGE" +Don't create samples you cannot read. First check your sample player +software and sound card hardware. I experienced problems with very low +sample rates (stereo <= 1575 Hz, mono <= 3675 Hz) when trying to play +them with standard WAV players for sound blaster (maybe they are not +legal in +.B WAV +format). Most CD-Writers insist on audio samples in a bigendian format. +Now icedax supports the +.B \-E " endianess" +option to control the endianess of the written samples. +.PP +If your hardware is fast enough to run icedax +uninterrupted and your CD drive is one of the 'perfect' ones, you will +gain speed when switching all overlap sampling off with the +.B \-P " 0" +option. Further fine tuning can be done with the +.B \-n " sectors" +option. You can specify how much sectors should be requested in one go. +.PP +Icedax supports +.B pipes +now. Use a filename of +.B \- +to let icedax output its samples to standard output. +.PP +Conversion to other sound formats can be done using the +.B sox +program package (although the use of +.B sox -x +to change the byte order of samples should be no more necessary; see option +.B \-E +to change the output byteorder). +.PP +If you want to sample more than one track into +different files in one run, this is currently possible with the +.B \-B +option. When recording time exceeds the track limit a new file will +be opened for the next track. +.SH FILES +Icedax can generate a lot of files for various purposes. +.sp +Audio files: +.sp +There are audio files containing samples with default extensions +.wav, .au, .aifc, .aiff, and .cdr according to the selected sound format. +These files are not generated when option (-N) is given. Multiple files may +be written when the bulk copy option (-B) is used. Individual file names +can be given as arguments. If the number of file names given is sufficient +to cover all included audio tracks, the file names will be used verbatim. +Otherwise, if there are less file names than files needed to write the +included tracks, the part of the file name before the extension is extended +with '_dd' where dd represents the current track number. +.sp +Cddb and Cdindex files: +.sp +If icedax detects cd-extra or cd-text (album/track) title information, +then .cddb and .cdindex files are generated unless suppressed by the +option -H. They contain suitable formatted entries for submission to +audio cd track title databases in the internet. The CDINDEX and CDDB(tm) +systems are currently supported. For more information please visit +www.musicbrainz.org and www.freedb.com. +.sp +Inf files: +.sp +The inf files are describing the sample files and the part from the audio cd, +it was taken from. They are a means to transfer information to a cd burning +program like wodim. For example, if the original audio cd had pre-emphasis +enabled, and icedax -T did remove the pre-emphasis, then the inf file has +pre-emphasis not set (since the audio file does not have it anymore), while +the .cddb and the .cdindex have pre-emphasis set as the original does. +.SH WARNING +.B IMPORTANT: +it is prohibited to sell copies of copyrighted material by noncopyright +holders. This program may not be used to circumvent copyrights. +The user acknowledges this constraint when using the software. +.SH BUGS +Generation of md5 checksums is currently broken. +.sp +Performance may not be optimal on slower systems. +.sp +The index scanner may give timeouts. +.sp +The resampling (rate conversion code) uses polynomial interpolation, which +is not optimal. +.sp +Icedax should use threads. +.sp +Icedax currently cannot sample hidden audio tracks (track 1 index 0). +.SH ACKNOWLEDGEMENTS +Thanks goto Project MODE (http://www.mode.net/) and Fraunhofer Institut f\*ur +integrierte Schaltungen (FhG-IIS) (http://www.iis.fhg.de/) for financial +support. +Plextor Europe and Ricoh Japan provided cdrom disk drives and cd burners +which helped a lot to develop this software. +Rammi has helped a lot with the debugging and showed a lot of stamina when +hearing 100 times the first 16 seconds of the first track of the Krupps CD. +Libparanoia contributed by Monty (Christopher Montgomery) xiphmont@mit.edu. +.SH AUTHOR +Heiko Eissfeldt heiko@colossus.escape.de +.PP +This manpage describes the program implementation of +.B +icedax +as shipped by the cdrkit distribution. See +.B +http://alioth.debian.org/projects/debburn/ +for details. It is a spinoff from the original program cdda2wav as distributed +in the cdrtools package [1]. However, the cdrtools developers are not involved +in the development of this spinoff and therefore shall not be made responsible +for any problem caused by it. Do not try to get support for this program by +contacting the original authors. +.PP +If you have support questions, send them to +.PP +.B +debburn-devel@lists.alioth.debian.org +.br +.PP +If you have definitely found a bug, send a mail to this list or to +.PP +.B +submit@bugs.debian.org +.br +.PP +writing at least a short description into the Subject and "Package: cdrkit" into the first line of the mail body. + +.SH DATE +26 Sep 2006 + +.SH SOURCES +.PP +.br +[1] Cdrtools 2.01.01a08 from May 2006, http://cdrecord.berlios.de + diff --git a/icedax/icedax.c b/icedax/icedax.c new file mode 100644 index 0000000..9ac5ee0 --- /dev/null +++ b/icedax/icedax.c @@ -0,0 +1,3059 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)cdda2wav.c 1.64 06/02/19 Copyright 1998-2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */ +#undef DEBUG_BUFFER_ADDRESSES +#undef GPROF +#undef DEBUG_FORKED +#undef DEBUG_CLEANUP +#undef DEBUG_DYN_OVERLAP +#undef DEBUG_READS +#define DEBUG_ILLLEADOUT 0 /* 0 disables, 1 enables */ +/* + * Copyright: GNU Public License 2 applies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +/* + * parts (C) Peter Widow + * parts (C) Thomas Niederreiter + * parts (C) RSA Data Security, Inc. + * + * last changes: + * 18.12.93 - first version, OK + * 01.01.94 - generalized & clean up HE + * 10.06.94 - first linux version HE + * 12.06.94 - wav header alignment problem fixed HE + * 12.08.94 - open the cdrom device O_RDONLY makes more sense :-) + * no more floating point math + * change to sector size 2352 which is more common + * sub-q-channel information per kernel ioctl requested + * doesn't work as well as before + * some new options (-max -i) + * 01.02.95 - async i/o via semaphores and shared memory + * 03.02.95 - overlapped reading on sectors + * 03.02.95 - generalized sample rates. all integral divisors are legal + * 04.02.95 - sun format added + * more divisors: all integral halves >= 1 allowed + * floating point math needed again + * 06.02.95 - bugfix for last track and not d0 + * tested with photo-cd with audio tracks + * tested with xa disk + * 29.01.96 - new options for bulk transfer + * 01.06.96 - tested with enhanced cd + * 01.06.96 - tested with cd-plus + * 02.06.96 - support pipes + * 02.06.96 - support raw format + * 04.02.96 - security hole fixed + * 22.04.97 - large parts rewritten + * 28.04.97 - make file names DOS compatible + * 01.09.97 - add speed control + * 20.10.97 - add find mono option + * Jan/Feb 98 - conversion to use Joerg Schillings SCSI library + * see ChangeLog + */ + +#include "config.h" + +#include <unixstd.h> +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <schily.h> +#include <signal.h> +#include <math.h> +#include <fctldefs.h> +#include <timedefs.h> +#if defined (HAVE_LIMITS_H) +#include <limits.h> +#endif +#if defined (HAVE_SYS_IOCTL_H) +#include <sys/ioctl.h> +#endif +#include <errno.h> +#include <statdefs.h> +#include <waitdefs.h> +#if defined (HAVE_SETPRIORITY) +#include <sys/resource.h> +#endif +#include <vadefs.h> + +#include <usal/scsitransp.h> + +#ifdef HAVE_AREAS +#include <be/kernel/OS.h> +#endif + +#include "mytype.h" +#include "sndconfig.h" + +#include "semshm.h" /* semaphore functions */ +#include "sndfile.h" +#include "wav.h" /* wav file header structures */ +#include "sun.h" /* sun audio file header structures */ +#include "raw.h" /* raw file handling */ +#include "aiff.h" /* aiff file handling */ +#include "aifc.h" /* aifc file handling */ +#ifdef USE_LAME +#include "mp3.h" /* mp3 file handling */ +#endif +#include "interface.h" /* low level cdrom interfacing */ +#include "icedax.h" +#include "resample.h" +#include "toc.h" +#include "setuid.h" +#include "ringbuff.h" +#include "global.h" +#include "exitcodes.h" +#ifdef USE_PARANOIA +#include "cdda_paranoia.h" +#endif +#include "defaults.h" + +static void RestrictPlaybackRate(long newrate); +static void output_indices(FILE *fp, index_list *p, unsigned trackstart); +static int write_info_file(char *fname_baseval, unsigned int track, + unsigned long SamplesDone, int numbered); +static void CloseAudio(int channels_val, unsigned long nSamples, + struct soundfile *audio_out); +static void CloseAll(void); +static void OpenAudio(char *fname, double rate, long nBitsPerSample, + long channels_val, unsigned long expected_bytes, + struct soundfile*audio_out); +static void set_offset(myringbuff *p, int offset); +static int get_offset(myringbuff *p); +static void usage(void); +static void init_globals(void); +static int is_fifo(char *filename); + + +/* Rules: + * unique parameterless options first, + * unique parametrized option names next, + * ambigious parameterless option names next, + * ambigious string parametrized option names last + */ +static const char *opts = "paranoia,paraopts&,version,help,h,\ +no-write,N,dump-rates,R,bulk,B,alltracks,verbose-scsi+,V+,\ +find-extremes,F,find-mono,G,no-infofile,H,\ +deemphasize,T,info-only,J,silent-scsi,Q,\ +cddbp-server*,cddbp-port*,\ +scanbus,devices,device*,dev*,D*,auxdevice*,A*,interface*,I*,output-format*,O*,\ +output-endianess*,E*,cdrom-endianess*,C*,speed#,S#,\ +playback-realtime#L,p#L,md5#,M#,set-overlap#,P#,sound-device*,K*,\ +cddb#,L#,channels*,c*,bits-per-sample#,b#,rate#,r#,gui,g,\ +divider*,a*,track*,t*,index#,i#,duration*,d*,offset#,o#,\ +sectors-per-request#,n#,verbose-level&,v&,buffers-in-ring#,l#,\ +stereo,s,mono,m,wait,w,echo,e,quiet,q,max,x\ +"; + + +#ifdef NEED_O_BINARY +#include <io.h> /* for setmode() prototype */ +#endif + +/* global variables */ +global_t global; + +/* static variables */ +static unsigned long nSamplesDone = 0; + +static int child_pid = -2; + +static unsigned long *nSamplesToDo; +static unsigned int current_track; +static int bulk = 0; + +unsigned int get_current_track(void); + +unsigned int get_current_track() +{ + return current_track; +} + +static void RestrictPlaybackRate(long newrate) +{ + global.playback_rate = newrate; + + if ( global.playback_rate < 25 ) global.playback_rate = 25; /* filter out insane values */ + if ( global.playback_rate > 250 ) global.playback_rate = 250; + + if ( global.playback_rate < 100 ) + global.nsectors = (global.nsectors*global.playback_rate)/100; +} + + +long SamplesNeeded(long amount, long undersampling_val) +{ + long retval = ((undersampling_val * 2 + Halved)*amount)/2; + if (Halved && (*nSamplesToDo & 1)) + retval += 2; + return retval; +} + +static int argc2; +static int argc3; +static char **argv2; + +static void reset_name_iterator(void); +static void reset_name_iterator() +{ + argv2 -= argc3 - argc2; + argc2 = argc3; +} + +static char *get_next_name(void); +static char *get_next_name() +{ + if (argc2 > 0) { + argc2--; + return (*argv2++); + } else { + return NULL; + } +} + +static char *cut_extension(char *fname); + +static char *cut_extension(char *fname) +{ + char *pp; + + pp = strrchr(fname, '.'); + + if (pp == NULL) { + pp = fname + strlen(fname); + } + *pp = '\0'; + + return pp; +} + +#ifdef INFOFILES +static void output_indices(FILE *fp, index_list *p, unsigned trackstart) +{ + int ci; + + fprintf(fp, "Index=\t\t"); + + if (p == NULL) { + fprintf(fp, "0\n"); + return; + } + + for (ci = 1; p != NULL; ci++, p = p->next) { + int frameoff = p->frameoffset; + + if (p->next == NULL) + fputs("\nIndex0=\t\t", fp); +#if 0 + else if ( ci > 8 && (ci % 8) == 1) + fputs("\nIndex =\t\t", fp); +#endif + if (frameoff != -1) + fprintf(fp, "%d ", frameoff - trackstart); + else + fprintf(fp, "-1 "); + } + fputs("\n", fp); +} + +/* + * write information before the start of the sampling process + * + * + * uglyfied for Joerg Schillings ultra dumb line parser + */ +static int write_info_file(char *fname_baseval, unsigned int track, + unsigned long int SamplesDone, int numbered) +{ + FILE *info_fp; + char fname[200]; + char datetime[30]; + time_t utc_time; + struct tm *tmptr; + + /* write info file */ + if (!strcmp(fname_baseval,"-")) return 0; + + strncpy(fname, fname_baseval, sizeof(fname) -1); + fname[sizeof(fname) -1] = 0; + if (numbered) + sprintf(cut_extension(fname), "_%02u.inf", track); + else + strcpy(cut_extension(fname), ".inf"); + + info_fp = fopen (fname, "w"); + if (!info_fp) + return -1; + +#if 0 +#ifdef MD5_SIGNATURES + if (global.md5blocksize) + MD5Final (global.MD5_result, &global.context); +#endif +#endif + + utc_time = time(NULL); + tmptr = localtime(&utc_time); + if (tmptr) { + strftime(datetime, sizeof(datetime), "%x %X", tmptr); + } else { + strncpy(datetime, "unknown", sizeof(datetime)); + } + fprintf(info_fp, "#created by icedax %s %s\n#\n", VERSION + , datetime + ); + fprintf(info_fp, +"CDINDEX_DISCID=\t'%s'\n" , global.cdindex_id); + fprintf(info_fp, +"CDDB_DISCID=\t0x%08lx\n\ +MCN=\t\t%s\n\ +ISRC=\t\t%15.15s\n\ +#\n\ +Albumperformer=\t'%s'\n\ +Performer=\t'%s'\n\ +Albumtitle=\t'%s'\n" + , (unsigned long) global.cddb_id + , Get_MCN() + , Get_ISRC(track) + , global.creator != NULL ? global.creator : (const unsigned char *)"" + , global.trackcreator[track] != NULL ? global.trackcreator[track] : + (global.creator != NULL ? global.creator : (const unsigned char *)"") + , global.disctitle != NULL ? global.disctitle : (const unsigned char *)"" + ); + fprintf(info_fp, + "Tracktitle=\t'%s'\n" + , global.tracktitle[track] ? global.tracktitle[track] : (const unsigned char *)"" + ); + fprintf(info_fp, "Tracknumber=\t%u\n" + , track + ); + fprintf(info_fp, + "Trackstart=\t%ld\n" + , Get_AudioStartSector(track) + ); + fprintf(info_fp, + "# track length in sectors (1/75 seconds each), rest samples\nTracklength=\t%ld, %d\n" + , SamplesDone/588L,(int)(SamplesDone%588)); + fprintf(info_fp, + "Pre-emphasis=\t%s\n" + , Get_Preemphasis(track) && (global.deemphasize == 0) ? "yes" : "no"); + fprintf(info_fp, + "Channels=\t%d\n" + , Get_Channels(track) ? 4 : global.channels == 2 ? 2 : 1); + { int cr = Get_Copyright(track); + fputs("Copy_permitted=\t", info_fp); + switch (cr) { + case 0: + fputs("once (copyright protected)\n", info_fp); + break; + case 1: + fputs("no (SCMS first copy)\n", info_fp); + break; + case 2: + fputs("yes (not copyright protected)\n", info_fp); + break; + default: + fputs("unknown\n", info_fp); + } + } + fprintf(info_fp, + "Endianess=\t%s\n" + , global.need_big_endian ? "big" : "little" + ); + fprintf(info_fp, "# index list\n"); + output_indices(info_fp, global.trackindexlist[track], + Get_AudioStartSector(track)); +#if 0 +/* MD5 checksums in info files are currently broken. + * for on-the-fly-recording the generation of info files has been shifted + * before the recording starts, so there is no checksum at that point. + */ +#ifdef MD5_SIGNATURES + fprintf(info_fp, + "#(blocksize) checksum\nMD-5=\t\t(%d) %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n" + , global.md5blocksize + , global.MD5_result[0] + , global.MD5_result[1] + , global.MD5_result[2] + , global.MD5_result[3] + , global.MD5_result[4] + , global.MD5_result[5] + , global.MD5_result[6] + , global.MD5_result[7] + , global.MD5_result[8] + , global.MD5_result[9] + , global.MD5_result[10] + , global.MD5_result[11] + , global.MD5_result[12] + , global.MD5_result[13] + , global.MD5_result[14] + , global.MD5_result[15]); +#endif +#endif + fclose(info_fp); + return 0; +} +#endif + +static void CloseAudio(int channels_val, unsigned long nSamples, + struct soundfile *audio_out) +{ + /* define length */ + audio_out->ExitSound( global.audio, (nSamples-global.SkippedSamples)*global.OutSampleSize*channels_val ); + + close (global.audio); + global.audio = -1; +} + +static unsigned int track = 1; + +/* On terminating: + * define size-related entries in audio file header, update and close file */ +static void CloseAll() +{ + WAIT_T chld_return_status; + int amiparent; + + /* terminate child process first */ + amiparent = child_pid > 0; + + if (global.iloop > 0) { + /* set to zero */ + global.iloop = 0; + } + +#if defined HAVE_FORK_AND_SHAREDMEM +# ifdef DEBUG_CLEANUP + fprintf(stderr, "%s terminating, \n", amiparent ? + "Parent (READER)" : "Child (WRITER)"); +#endif +#else +# ifdef DEBUG_CLEANUP + fprintf(stderr, "icedax single process terminating, \n"); +# endif +#endif + + if (amiparent || child_pid < 0) { + /* switch to original mode and close device */ + EnableCdda (get_scsi_p(), 0, 0); + } + + if (!amiparent) { + /* do general clean up */ + + if (global.audio>=0) { + if (bulk) { + /* finish sample file for this track */ + CloseAudio(global.channels, + global.nSamplesDoneInTrack, global.audio_out); + } else { + /* finish sample file for this track */ + CloseAudio(global.channels, + (unsigned int) *nSamplesToDo, global.audio_out); + } + } + + /* tell minimum and maximum amplitudes, if required */ + if (global.findminmax) { + fprintf(stderr, + "Right channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n", + global.minamp[0], global.maxamp[0]); + fprintf(stderr, + "Left channel: minimum amplitude :%d/-32768, maximum amplitude :%d/32767\n", + global.minamp[1], global.maxamp[1]); + } + + /* tell mono or stereo recording, if required */ + if (global.findmono) { + fprintf(stderr, "Audio samples are originally %s.\n", global.ismono ? "mono" : "stereo"); + } + + return; /* end of child or single process */ + } + + + if (global.have_forked == 1) { +#ifdef DEBUG_CLEANUP + fprintf(stderr, "Parent wait for child death, \n"); +#endif + + /* wait for child to terminate */ + if (0 > wait(&chld_return_status)) { + perror(""); + } else { + if (WIFEXITED(chld_return_status)) { + if (WEXITSTATUS(chld_return_status)) { + fprintf(stderr, "\nW Child exited with %d\n", WEXITSTATUS(chld_return_status)); + } + } + if (WIFSIGNALED(chld_return_status)) { + fprintf(stderr, "\nW Child exited due to signal %d\n", WTERMSIG(chld_return_status)); + } + if (WIFSTOPPED(chld_return_status)) { + fprintf(stderr, "\nW Child is stopped due to signal %d\n", WSTOPSIG(chld_return_status)); + } + } + +#ifdef DEBUG_CLEANUP + fprintf(stderr, "\nW Parent child death, state:%d\n", chld_return_status); +#endif + } + +#ifdef GPROF + rename("gmon.out", "gmon.child"); +#endif +} + + +/* report a usage error and exit */ +#ifdef PROTOTYPES +static void usage2 (const char *szMessage, ...) +#else +static void usage2(const char *szMessage, va_dcl va_alist) +#endif +{ + va_list marker; + +#ifdef PROTOTYPES + va_start(marker, szMessage); +#else + va_start(marker); +#endif + + vfprintf(stderr, szMessage, marker); + + va_end(marker); + fprintf(stderr, "\nPlease use -help or consult the man page for help.\n"); + + exit (1); +} + + +/* report a fatal error, clean up and exit */ +#ifdef PROTOTYPES +void FatalError (const char *szMessage, ...) +#else +void FatalError(const char *szMessage, va_dcl va_alist) +#endif +{ + va_list marker; + +#ifdef PROTOTYPES + va_start(marker, szMessage); +#else + va_start(marker); +#endif + + vfprintf(stderr, szMessage, marker); + + va_end(marker); + + if (child_pid >= 0) { + if (child_pid == 0) { + pid_t ppid; + /* + * Kill the parent too if we are not orphaned. + */ + ppid = getppid(); + if (ppid > 1) + kill(ppid, SIGINT); + } else { + kill(child_pid, SIGINT); + } + } + exit (1); +} + + +/* open the audio output file and prepare the header. + * the header will be defined on terminating (when the size + * is known). So hitting the interrupt key leaves an intact + * file. + */ +static void OpenAudio(char *fname, double rate, long nBitsPerSample, + long channels_val, unsigned long expected_bytes, + struct soundfile *audio_out) +{ + if (global.audio == -1) { + + global.audio = open (fname, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY +#ifdef SYNCHRONOUS_WRITE + | O_SYNC +#endif + , 0666); + if (global.audio == -1) { + if (errno == EAGAIN && is_fifo(fname)) { + FatalError ("Could not open fifo %s. Probably no fifo reader present.\n", fname); + } + perror("open audio sample file"); + FatalError ("Could not open file %s\n", fname); + } + } + global.SkippedSamples = 0; + any_signal = 0; + audio_out->InitSound( global.audio, channels_val, (unsigned long)rate, nBitsPerSample, expected_bytes ); + +#ifdef MD5_SIGNATURES + if (global.md5blocksize) + MD5Init (&global.context); + global.md5count = global.md5blocksize; +#endif +} + +#include "scsi_cmds.h" + +static int RealEnd(SCSI *usalp, UINT4 *buff); + +static int RealEnd(SCSI *usalp, UINT4 *buff) +{ + if (usal_cmd_err(usalp) != 0) { + int c,k,q; + + k = usal_sense_key(usalp); + c = usal_sense_code(usalp); + q = usal_sense_qual(usalp); + if ((k == 0x05 /* ILLEGAL_REQUEST */ && + c == 0x21 /* lba out of range */ && + q == 0x00) || + (k == 0x05 /* ILLEGAL_REQUEST */ && + c == 0x63 /*end of user area encountered on this track*/ && + q == 0x00) || + (k == 0x08 /* BLANK_CHECK */ && + c == 0x64 /* illegal mode for this track */ && + q == 0x00)) { + return 1; + } + } + + if (usal_getresid(usalp) > 16) return 1; + + { + unsigned char *p; + /* Look into the subchannel data */ + buff += CD_FRAMESAMPLES; + p = (unsigned char *)buff; + if (p[0] == 0x21 && p[1] == 0xaa) { + return 1; + } + } + return 0; +} + +static void set_offset(myringbuff *p, int offset) +{ +#ifdef DEBUG_SHM + fprintf(stderr, "Write offset %d at %p\n", offset, &p->offset); +#endif + p->offset = offset; +} + + +static int get_offset(myringbuff *p) +{ +#ifdef DEBUG_SHM + fprintf(stderr, "Read offset %d from %p\n", p->offset, &p->offset); +#endif + return p->offset; +} + + +static void usage() +{ + fputs( +"usage: icedax [OPTIONS ...] [trackfilenames ...]\n\ +OPTIONS:\n\ + [-c chans] [-s] [-m] [-b bits] [-r rate] [-a divider] [-S speed] [-x]\n\ + [-t track[+endtrack]] [-i index] [-o offset] [-d duration] [-F] [-G]\n\ + [-q] [-w] [-v vopts] [-R] [-P overlap] [-B] [-T] [-C input-endianess]\n\ + [-e] [-n sectors] [-N] [-J] [-L cddbp-mode] [-H] [-g] [-l buffers] [-D cd-device]\n\ + [-I interface] [-K sound-device] [-O audiotype] [-E output-endianess]\n\ + [-A auxdevice] [-paranoia] [-cddbp-server=name] [-cddbp-port=port] [-version]\n", stderr); + fputs("\ + (-D) dev=device set the cdrom or scsi device (as Bus,Id,Lun).\n\ + (-A) auxdevice=device set the aux device (typically /dev/cdrom).\n\ + (-K) sound-device=device set the sound device to use for -e (typically /dev/dsp).\n\ + (-I) interface=interface specify the interface for cdrom access.\n\ + (generic_scsi or cooked_ioctl).\n\ + (-c) channels=channels set 1 for mono, 2 or s for stereo (s: channels swapped).\n\ + (-s) -stereo select stereo recording.\n\ + (-m) -mono select mono recording.\n\ + (-x) -max select maximum quality (stereo/16-bit/44.1 KHz).\n\ + (-b) bits=bits set bits per sample per channel (8, 12 or 16 bits).\n\ + (-r) rate=rate set rate in samples per second. -R gives all rates\n\ + (-a) divider=divider set rate to 44100Hz / divider. -R gives all rates\n\ + (-R) -dump-rates dump a table with all available sample rates\n\ + (-S) speed=speedfactor set the cdrom drive to a given speed during reading\n\ + (-P) set-overlap=sectors set amount of overlap sampling (default is 0)\n\ + (-n) sectors-per-request=secs read 'sectors' sectors per request.\n\ + (-l) buffers-in-ring=buffers use a ring buffer with 'buffers' elements.\n\ + (-t) track=track[+end track] select start track (option. end track).\n\ + (-i) index=index select start index.\n\ + (-o) offset=offset start at 'offset' sectors behind start track/index.\n\ + one sector equivalents 1/75 second.\n\ + (-O) output-format=audiotype set to wav, au (sun), cdr (raw), aiff or aifc format.\n\ + (-C) cdrom-endianess=endian set little, big or guess input sample endianess.\n\ + (-E) output-endianess=endian set little or big output sample endianess.\n\ + (-d) duration=seconds set recording time in seconds or 0 for whole track.\n\ + (-w) -wait wait for audio signal, then start recording.\n\ + (-F) -find-extremes find extrem amplitudes in samples.\n\ + (-G) -find-mono find if input samples are mono.\n\ + (-T) -deemphasize undo pre-emphasis in input samples.\n\ + (-e) -echo echo audio data to sound device (see -K) SOUND_DEV.\n\ + (-v) verbose-level=optlist controls verbosity (for a list use -vhelp).\n\ + (-N) -no-write do not create audio sample files.\n\ + (-J) -info-only give disc information only.\n\ + (-L) cddb=cddbpmode do cddbp title lookups.\n\ + resolve multiple entries according to cddbpmode: 0=interactive, 1=first entry\n\ + (-H) -no-infofile no info file generation.\n\ + (-g) -gui generate special output suitable for gui frontends.\n\ + (-Q) -silent-scsi do not print status of erreneous scsi-commands.\n\ + -scanbus scan the SCSI bus and exit\n\ + --devices scan for system devices and print with native names\n\ + (-M) md5=count calculate MD-5 checksum for blocks of 'count' bytes.\n\ + (-q) -quiet quiet operation, no screen output.\n\ + (-p) playback-realtime=perc play (echo) audio pitched at perc percent (50%-200%).\n\ + (-V) -verbose-scsi each option increases verbosity for SCSI commands.\n\ + (-h) -help show this help screen.\n\ + (-B) -alltracks, -bulk record each track into a seperate file.\n\ + -paranoia use the lib paranoia for reading.\n\ + -paraopts=opts set options for lib paranoia (see -paraopts=help).\n\ + -cddbp-server=servername set the cddbp server to use for title lookups.\n\ + -cddbp-port=portnumber set the cddbp port to use for title lookups.\n\ + -version print version information.\n\ +\n\ +Please note: some short options will be phased out soon (disappear)!\n\ +\n\ +parameters: (optional) one or more file names or - for standard output.\n\ +", stderr); + fputs("Version ", stderr); + fputs(VERSION, stderr); + fprintf(stderr, "\n\ +defaults %s, %d bit, %d.%02d Hz, track 1, no offset, one track,\n", + CHANNELS-1?"stereo":"mono", BITS_P_S, + 44100 / UNDERSAMPLING, + (4410000 / UNDERSAMPLING) % 100); + fprintf(stderr, "\ + type %s '%s', don't wait for signal, not quiet,\n", + AUDIOTYPE, FILENAME); + fprintf(stderr, "\ + use %s, device %s, aux %s\n", + DEF_INTERFACE, CD_DEVICE, AUX_DEVICE); + exit( SYNTAX_ERROR ); +} + +static void init_globals() +{ +#ifdef HISTORICAL_JUNK + global.dev_name = CD_DEVICE; /* device name */ +#endif + global.aux_name = AUX_DEVICE;/* auxiliary cdrom device */ + strncpy(global.fname_base, FILENAME, sizeof(global.fname_base));/* auxiliary cdrom device */ + global.have_forked = 0; /* state variable for clean up */ + global.parent_died = 0; /* state variable for clean up */ + global.audio = -1; /* audio file desc */ + global.cooked_fd = -1; /* cdrom file desc */ + global.no_file = 0; /* flag no_file */ + global.no_infofile = 0; /* flag no_infofile */ + global.no_cddbfile = 0; /* flag no_cddbfile */ + global.quiet = 0; /* flag quiet */ + global.verbose = SHOW_TOC + SHOW_SUMMARY + SHOW_STARTPOSITIONS + SHOW_TITLES; /* verbose level */ + global.scsi_silent = 0; + global.scsi_verbose = 0; /* SCSI verbose level */ + global.scanbus = 0; + global.scandevs = 0; + global.multiname = 0; /* multiple file names given */ + global.sh_bits = 0; /* sh_bits: sample bit shift */ + global.Remainder= 0; /* remainder */ + global.iloop = 0; /* todo counter */ + global.SkippedSamples = 0; /* skipped samples */ + global.OutSampleSize = 0; /* output sample size */ + global.channels = CHANNELS; /* output sound channels */ + global.nSamplesDoneInTrack = 0; /* written samples in current track */ + global.buffers = 4; /* buffers to use */ + global.nsectors = NSECTORS; /* sectors to read in one request */ + global.overlap = 1; /* amount of overlapping sectors */ + global.useroverlap = -1; /* amount of overlapping sectors user override */ + global.need_hostorder = 0; /* processing needs samples in host endianess */ + global.in_lendian = -1; /* input endianess from SetupSCSI() */ + global.outputendianess = NONE; /* user specified output endianess */ + global.findminmax = 0; /* flag find extrem amplitudes */ +#ifdef HAVE_LIMITS_H + global.maxamp[0] = INT_MIN; /* maximum amplitude */ + global.maxamp[1] = INT_MIN; /* maximum amplitude */ + global.minamp[0] = INT_MAX; /* minimum amplitude */ + global.minamp[1] = INT_MAX; /* minimum amplitude */ +#else + global.maxamp[0] = -32768; /* maximum amplitude */ + global.maxamp[1] = -32768; /* maximum amplitude */ + global.minamp[0] = 32767; /* minimum amplitude */ + global.minamp[1] = 32767; /* minimum amplitude */ +#endif + global.speed = DEFAULT_SPEED; /* use default */ + global.userspeed = -1; /* speed user override */ + global.findmono = 0; /* flag find if samples are mono */ + global.ismono = 1; /* flag if samples are mono */ + global.swapchannels = 0; /* flag if channels shall be swapped */ + global.deemphasize = 0; /* flag undo pre-emphasis in samples */ + global.playback_rate = 100; /* new fancy selectable sound output rate */ + global.gui = 0; /* flag plain formatting for guis */ + global.cddb_id = 0; /* disc identifying id for CDDB database */ + global.cddb_revision = 0; /* entry revision for CDDB database */ + global.cddb_year = 0; /* disc identifying year for CDDB database */ + global.cddb_genre[0] = '\0'; /* disc identifying genre for CDDB database */ + global.cddbp = 0; /* flag if titles shall be looked up from CDDBP */ + global.cddbp_server = 0; /* user supplied CDDBP server */ + global.cddbp_port = 0; /* user supplied CDDBP port */ + global.illleadout_cd = 0; /* flag if illegal leadout is present */ + global.reads_illleadout = 0; /* flag if cdrom drive reads cds with illegal leadouts */ + global.disctitle = NULL; + global.creator = NULL; + global.copyright_message = NULL; + memset(global.tracktitle, 0, sizeof(global.tracktitle)); + memset(global.trackindexlist, 0, sizeof(global.trackindexlist)); + + global.just_the_toc = 0; +#ifdef USE_PARANOIA + global.paranoia_parms.disable_paranoia = + global.paranoia_parms.disable_extra_paranoia = + global.paranoia_parms.disable_scratch_detect = + global.paranoia_parms.disable_scratch_repair = 0; + global.paranoia_parms.retries = 20; + global.paranoia_parms.overlap = -1; + global.paranoia_parms.mindynoverlap = -1; + global.paranoia_parms.maxdynoverlap = -1; +#endif +} + +#if !defined (HAVE_STRCASECMP) || (HAVE_STRCASECMP != 1) +#include <ctype.h> +static int strcasecmp(const char *s1, const char *s2); +static int strcasecmp(const char *s1, const char *s2) +{ + if (s1 && s2) { + while (*s1 && *s2 && (tolower(*s1) - tolower(*s2) == 0)) { + s1++; + s2++; + } + if (*s1 == '\0' && *s2 == '\0') return 0; + if (*s1 == '\0') return -1; + if (*s2 == '\0') return +1; + return tolower(*s1) - tolower(*s2); + } + return -1; +} +#endif + +static int is_fifo(char *filename) +{ +#if defined S_ISFIFO + struct stat statstruct; + + if (stat(filename, &statstruct)) { + /* maybe the output file does not exist. */ + if (errno == ENOENT) + return 0; + else comerr("Error during stat for output file\n"); + } else { + if (S_ISFIFO(statstruct.st_mode)) { + return 1; + } + } + return 0; +#else + return 0; +#endif +} + + +#if !defined (HAVE_STRTOUL) || (HAVE_STRTOUL != 1) +static unsigned int strtoul(const char *s1, char **s2, int base); +static unsigned int strtoul(const char *s1, char **s2, int base) +{ + long retval; + + if (base == 10) { + /* strip zeros in front */ + while (*s1 == '0') + s1++; + } + if (s2 != NULL) { + *s2 = astol(s1, &retval); + } else { + (void) astol(s1, &retval); + } + + return (unsigned long) retval; +} +#endif + +static unsigned long SectorBurst; +#if (SENTINEL > CD_FRAMESIZE_RAW) +error block size for overlap check has to be < sector size +#endif + + +static void +switch_to_realtime_priority(void); + +#ifdef HAVE_SYS_PRIOCNTL_H + +#include <sys/priocntl.h> +#include <sys/rtpriocntl.h> +static void switch_to_realtime_priority() +{ + pcinfo_t info; + pcparms_t param; + rtinfo_t rtinfo; + rtparms_t rtparam; + int pid; + + pid = getpid(); + + /* get info */ + strcpy(info.pc_clname, "RT"); + if (-1 == priocntl(P_PID, pid, PC_GETCID, (void *)&info)) { + errmsg("Cannot get priority class id priocntl(PC_GETCID)\n"); + goto prio_done; + } + + memmove(&rtinfo, info.pc_clinfo, sizeof(rtinfo_t)); + + /* set priority not to the max */ + rtparam.rt_pri = rtinfo.rt_maxpri - 2; + rtparam.rt_tqsecs = 0; + rtparam.rt_tqnsecs = RT_TQDEF; + param.pc_cid = info.pc_cid; + memmove(param.pc_clparms, &rtparam, sizeof(rtparms_t)); + priv_on(); + needroot(0); + if (-1 == priocntl(P_PID, pid, PC_SETPARMS, (void *)¶m)) + errmsg("Cannot set priority class parameters priocntl(PC_SETPARMS)\n"); +prio_done: + priv_off(); + dontneedroot(); +} +#else +#if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING -0 >= 0 +#define USE_POSIX_PRIORITY_SCHEDULING +#endif +#ifdef USE_POSIX_PRIORITY_SCHEDULING +#include <sched.h> + +static void switch_to_realtime_priority() +{ +#ifdef _SC_PRIORITY_SCHEDULING + if (sysconf(_SC_PRIORITY_SCHEDULING) == -1) { + errmsg("WARNING: RR-scheduler not available, disabling.\n"); + } else +#endif + { + int sched_fifo_min, sched_fifo_max; + struct sched_param sched_parms; + + sched_fifo_min = sched_get_priority_min(SCHED_FIFO); + sched_fifo_max = sched_get_priority_max(SCHED_FIFO); + sched_parms.sched_priority = sched_fifo_max - 1; + priv_on(); + needroot(0); + if (-1 == sched_setscheduler(getpid(), SCHED_FIFO, &sched_parms) + && global.quiet != 1) + errmsg("cannot set posix realtime scheduling policy\n"); + priv_off(); + dontneedroot(); + } +} +#else +#if defined(__CYGWIN32__) + +/* + * NOTE: Base.h from Cygwin-B20 has a second typedef for BOOL. + * We define BOOL to make all local code use BOOL + * from Windows.h and use the hidden __SBOOL for + * our global interfaces. + * + * NOTE: windows.h from Cygwin-1.x includes a structure field named sample, + * so me may not define our own 'sample' or need to #undef it now. + * With a few nasty exceptions, Microsoft assumes that any global + * defines or identifiers will begin with an Uppercase letter, so + * there may be more of these problems in the future. + * + * NOTE: windows.h defines interface as an alias for struct, this + * is used by COM/OLE2, I guess it is class on C++ + * We man need to #undef 'interface' + */ +#define BOOL WBOOL /* This is the Win BOOL */ +#define format __format /* Avoid format parameter hides global ... */ +#include <windows.h> +#undef format +#undef interface + +static void switch_to_realtime_priority() +{ + /* set priority class */ + if (FALSE == SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)) { + fprintf(stderr, "No realtime priority possible.\n"); + return; + } + + /* set thread priority */ + if (FALSE == SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) { + fprintf(stderr, "Could not set realtime priority.\n"); + } +} +#else +static void switch_to_realtime_priority() +{ +} +#endif +#endif +#endif + +/* SCSI cleanup */ +int on_exitscsi(void *status); + +int on_exitscsi(void *status) +{ + exit((intptr_t)status); + return 0; +} + +/* wrapper for signal handler exit needed for Mac-OS-X */ +static void exit_wrapper(int status); + +static void exit_wrapper(int status) +{ +#if defined DEBUG_CLEANUP + fprintf( stderr, "Exit(%d) for %s\n", status, child_pid == 0 ? "Child" : "Parent"); + fflush(stderr); +#endif + + if (child_pid != 0) { + SCSI *usalp = get_scsi_p(); + if (usalp->running) { + usalp->cb_fun = on_exitscsi; + usalp->cb_arg = (void *) (uintptr_t) status; + } else { + on_exitscsi((void *) (intptr_t) status); + } + } else { + exit(status); + } +} + +/* signal handler for process communication */ +static void set_nonforked(int status); + +/* ARGSUSED */ +static void set_nonforked(int status) +{ + global.parent_died = 1; +#if defined DEBUG_CLEANUP +fprintf( stderr, "SIGPIPE received from %s\n.", child_pid == 0 ? "Child" : "Parent"); +#endif + if (child_pid == 0) { + pid_t ppid; + /* + * Kill the parent too if we are not orphaned. + */ + ppid = getppid(); + if (ppid > 1) + kill(ppid, SIGINT); + } else { + kill(child_pid, SIGINT); + } + exit(SIGPIPE_ERROR); +} + + + +#ifdef USE_PARANOIA +static struct paranoia_statistics +{ + long c_sector; + long v_sector; + int last_heartbeatstate; + long lasttime; + char heartbeat; + int minoverlap; + int curoverlap; + int maxoverlap; + int slevel; + int slastlevel; + int stimeout; + int rip_smile_level; + unsigned verifies; + unsigned reads; + unsigned fixup_edges; + unsigned fixup_atoms; + unsigned readerrs; + unsigned skips; + unsigned overlaps; + unsigned scratchs; + unsigned drifts; + unsigned fixup_droppeds; + unsigned fixup_dupeds; +} *para_stat; + + +static void paranoia_reset(void); +static void paranoia_reset() +{ + para_stat->c_sector = 0; + para_stat->v_sector = 0; + para_stat->last_heartbeatstate = 0; + para_stat->lasttime = 0; + para_stat->heartbeat = ' '; + para_stat->minoverlap = 0x7FFFFFFF; + para_stat->curoverlap = 0; + para_stat->maxoverlap = 0; + para_stat->slevel = 0; + para_stat->slastlevel = 0; + para_stat->stimeout = 0; + para_stat->rip_smile_level = 0; + para_stat->verifies = 0; + para_stat->reads = 0; + para_stat->readerrs = 0; + para_stat->fixup_edges = 0; + para_stat->fixup_atoms = 0; + para_stat->fixup_droppeds = 0; + para_stat->fixup_dupeds = 0; + para_stat->drifts = 0; + para_stat->scratchs = 0; + para_stat->overlaps = 0; + para_stat->skips = 0; +} + +static void paranoia_callback(long inpos, int function); + +static void paranoia_callback(long inpos, int function) +{ + struct timeval thistime; + long test; + + switch (function) { + case -2: + para_stat->v_sector = inpos / CD_FRAMEWORDS; + return; + case -1: + para_stat->last_heartbeatstate = 8; + para_stat->heartbeat = '*'; + para_stat->slevel = 0; + para_stat->v_sector = inpos / CD_FRAMEWORDS; + break; + case PARANOIA_CB_VERIFY: + if (para_stat->stimeout >= 30) { + if (para_stat->curoverlap > CD_FRAMEWORDS) { + para_stat->slevel = 2; + } else { + para_stat->slevel = 1; + } + } + para_stat->verifies++; + break; + case PARANOIA_CB_READ: + if (inpos / CD_FRAMEWORDS > para_stat->c_sector) { + para_stat->c_sector = inpos / CD_FRAMEWORDS; + } + para_stat->reads++; + break; + case PARANOIA_CB_FIXUP_EDGE: + if (para_stat->stimeout >= 5) { + if (para_stat->curoverlap > CD_FRAMEWORDS) { + para_stat->slevel = 2; + } else { + para_stat->slevel = 1; + } + } + para_stat->fixup_edges++; + break; + case PARANOIA_CB_FIXUP_ATOM: + if (para_stat->slevel < 3 || para_stat->stimeout > 5) { + para_stat->slevel = 3; + } + para_stat->fixup_atoms++; + break; + case PARANOIA_CB_READERR: + para_stat->slevel = 6; + para_stat->readerrs++; + break; + case PARANOIA_CB_SKIP: + para_stat->slevel = 8; + para_stat->skips++; + break; + case PARANOIA_CB_OVERLAP: + para_stat->curoverlap = inpos; + if (inpos > para_stat->maxoverlap) + para_stat->maxoverlap = inpos; + if (inpos < para_stat->minoverlap) + para_stat->minoverlap = inpos; + para_stat->overlaps++; + break; + case PARANOIA_CB_SCRATCH: + para_stat->slevel = 7; + para_stat->scratchs++; + break; + case PARANOIA_CB_DRIFT: + if (para_stat->slevel < 4 || para_stat->stimeout > 5) { + para_stat->slevel = 4; + } + para_stat->drifts++; + break; + case PARANOIA_CB_FIXUP_DROPPED: + para_stat->slevel = 5; + para_stat->fixup_droppeds++; + break; + case PARANOIA_CB_FIXUP_DUPED: + para_stat->slevel = 5; + para_stat->fixup_dupeds++; + break; + } + + gettimeofday(&thistime, NULL); + /* now in tenth of seconds. */ + test = thistime.tv_sec * 10 + thistime.tv_usec / 100000; + + if (para_stat->lasttime != test + || function == -1 + || para_stat->slastlevel != para_stat->slevel) { + + if (function == -1 + || para_stat->slastlevel != para_stat->slevel) { + + static const char hstates[] = " .o0O0o."; + + para_stat->lasttime = test; + para_stat->stimeout++; + + para_stat->last_heartbeatstate++; + if (para_stat->last_heartbeatstate > 7) { + para_stat->last_heartbeatstate = 0; + } + para_stat->heartbeat = hstates[para_stat->last_heartbeatstate]; + + if (function == -1) { + para_stat->heartbeat = '*'; + } + } + + if (para_stat->slastlevel != para_stat->slevel) { + para_stat->stimeout = 0; + } + para_stat->slastlevel = para_stat->slevel; + } + + if (para_stat->slevel < 8) { + para_stat->rip_smile_level = para_stat->slevel; + } else { + para_stat->rip_smile_level = 0; + } +} +#endif + +static long lSector; +static long lSector_p2; +static double rate = 44100.0 / UNDERSAMPLING; +static int bits = BITS_P_S; +static char fname[200]; +static const char *audio_type; +static long BeginAtSample; +static unsigned long SamplesToWrite; +static unsigned minover; +static unsigned maxover; + +static unsigned long calc_SectorBurst(void); +static unsigned long calc_SectorBurst() +{ + unsigned long SectorBurstVal; + + SectorBurstVal = min(global.nsectors, + (global.iloop + CD_FRAMESAMPLES-1) / CD_FRAMESAMPLES); + if ( lSector+(int)SectorBurst-1 >= lSector_p2 ) + SectorBurstVal = lSector_p2 - lSector; + return SectorBurstVal; +} + +/* if PERCENTAGE_PER_TRACK is defined, the percentage message will reach + * 100% every time a track end is reached or the time limit is reached. + * + * Otherwise if PERCENTAGE_PER_TRACK is not defined, the percentage message + * will reach 100% once at the very end of the last track. + */ +#define PERCENTAGE_PER_TRACK + +static int do_read(myringbuff *p, unsigned *total_unsuccessful_retries); +static int do_read(myringbuff *p, unsigned *total_unsuccessful_retries) +{ + unsigned char *newbuf; + int offset; + unsigned int added_size; + + /* how many sectors should be read */ + SectorBurst = calc_SectorBurst(); + +#ifdef USE_PARANOIA + if (global.paranoia_selected) { + int i; + + for (i = 0; i < SectorBurst; i++) { + void *dp; + + dp = paranoia_read_limited(global.cdp, paranoia_callback, + global.paranoia_parms.retries); +/* + { + char *err; + char *msg; + err = cdda_errors(global.cdp); + msg = cdda_messages(global.cdp); + if (err) { + fputs(err, stderr); + free(err); + } + if (msg) { + fputs(msg, stderr); + free(msg); + } + } +*/ + if (dp != NULL) { + memcpy(p->data + i*CD_FRAMESAMPLES, dp, + CD_FRAMESIZE_RAW); + } else { + fputs("E unrecoverable error!", stderr); + exit(READ_ERROR); + } + } + newbuf = (unsigned char *)p->data; + offset = 0; + set_offset(p,offset); + added_size = SectorBurst * CD_FRAMESAMPLES; + global.overlap = 0; + handle_inputendianess(p->data, added_size); + } else +#endif + { + unsigned int retry_count; +#define MAX_READRETRY 12 + + retry_count = 0; + do { + SCSI *usalp = get_scsi_p(); + int retval; +#ifdef DEBUG_READS +fprintf(stderr, "reading from %lu to %lu, overlap %u\n", lSector, lSector + SectorBurst -1, global.overlap); +#endif + +#ifdef DEBUG_BUFFER_ADDRESSES +fprintf(stderr, "%p %l\n", p->data, global.pagesize); +if (((unsigned)p->data) & (global.pagesize -1) != 0) { + fprintf(stderr, "Address %p is NOT page aligned!!\n", p->data); +} +#endif + + if (global.reads_illleadout != 0 && lSector > Get_StartSector(LastTrack())) { + int singles = 0; + UINT4 bufferSub[CD_FRAMESAMPLES + 24]; + + /* we switch to single sector reads, + * in order to handle the remaining sectors. */ + usalp->silent++; + do { + ReadCdRomSub( usalp, bufferSub, lSector+singles, 1 ); + *eorecording = RealEnd( usalp, bufferSub ); + if (*eorecording) { + break; + } + memcpy(p->data+singles*CD_FRAMESAMPLES, bufferSub, CD_FRAMESIZE_RAW); + singles++; + } while (singles < SectorBurst); + usalp->silent--; + + if ( *eorecording ) { + patch_real_end(lSector+singles); + SectorBurst = singles; +#if DEBUG_ILLLEADOUT +fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu, end=%lu -->\n", +global.iloop, *nSamplesToDo, lSector+singles); +#endif + + *nSamplesToDo -= global.iloop - SectorBurst*CD_FRAMESAMPLES; + global.iloop = SectorBurst*CD_FRAMESAMPLES; +#if DEBUG_ILLLEADOUT +fprintf(stderr, "iloop=%11lu, nSamplesToDo=%11lu\n\n", +global.iloop, *nSamplesToDo); +#endif + + } + } else { + retval = ReadCdRom( usalp, p->data, lSector, SectorBurst ); + } + handle_inputendianess(p->data, SectorBurst * CD_FRAMESAMPLES); + if (NULL == + (newbuf = synchronize( p->data, SectorBurst*CD_FRAMESAMPLES, + *nSamplesToDo-global.iloop ))) { + /* could not synchronize! + * Try to invalidate the cdrom cache. + * Increase overlap setting, if possible. + */ + /*trash_cache(p->data, lSector, SectorBurst);*/ + if (global.overlap < global.nsectors - 1) { + global.overlap++; + lSector--; + SectorBurst = calc_SectorBurst(); +#ifdef DEBUG_DYN_OVERLAP +fprintf(stderr, "using increased overlap of %u\n", global.overlap); +#endif + } else { + lSector += global.overlap - 1; + global.overlap = 1; + SectorBurst = calc_SectorBurst(); + } + } else + break; + } while (++retry_count < MAX_READRETRY); + + if (retry_count == MAX_READRETRY && newbuf == NULL && global.verbose != 0) { + (*total_unsuccessful_retries)++; + } + + if (newbuf) { + offset = newbuf - ((unsigned char *)p->data); + } else { + offset = global.overlap * CD_FRAMESIZE_RAW; + } + set_offset(p,offset); + + /* how much has been added? */ + added_size = SectorBurst * CD_FRAMESAMPLES - offset/4; + + if (newbuf && *nSamplesToDo != global.iloop) { + minover = min(global.overlap, minover); + maxover = max(global.overlap, maxover); + + + /* should we reduce the overlap setting ? */ + if (offset > CD_FRAMESIZE_RAW && global.overlap > 1) { +#ifdef DEBUG_DYN_OVERLAP +fprintf(stderr, "decreasing overlap from %u to %u (jitter %d)\n", global.overlap, global.overlap-1, offset - (global.overlap)*CD_FRAMESIZE_RAW); +#endif + global.overlap--; + SectorBurst = calc_SectorBurst(); + } + } + } + if (global.iloop >= added_size) { + global.iloop -= added_size; + } else { + global.iloop = 0; + } + + lSector += SectorBurst - global.overlap; + +#if defined PERCENTAGE_PER_TRACK && defined HAVE_FORK_AND_SHAREDMEM + { + int as; + while ((as = Get_StartSector(current_track+1)) != -1 + && lSector >= as) { + current_track++; + } + } +#endif + + return offset; +} + +static void +print_percentage(unsigned *poper, int c_offset); + +static void print_percentage(unsigned *poper, int c_offset) +{ + unsigned per; +#ifdef PERCENTAGE_PER_TRACK + /* Thomas Niederreiter wants percentage per track */ + unsigned start_in_track = max(BeginAtSample, + Get_AudioStartSector(current_track)*CD_FRAMESAMPLES); + + per = min(BeginAtSample + (long)*nSamplesToDo, + Get_StartSector(current_track+1)*CD_FRAMESAMPLES) + - (long)start_in_track; + + per = (BeginAtSample+nSamplesDone + - start_in_track + )/(per/100); + +#else + per = global.iloop ? (nSamplesDone)/(*nSamplesToDo/100) : 100; +#endif + + if (global.overlap > 0) { + fprintf(stderr, "\r%2d/%2d/%2d/%7d %3d%%", + minover, maxover, global.overlap, + c_offset - global.overlap*CD_FRAMESIZE_RAW, + per); + } else if (*poper != per) { + fprintf(stderr, "\r%3d%%", per); + } + *poper = per; + fflush(stderr); +} + +static unsigned long do_write(myringbuff *p); +static unsigned long do_write(myringbuff *p) +{ + int current_offset; + unsigned int InSamples; + static unsigned oper = 200; + + current_offset = get_offset(p); + + /* how many bytes are available? */ + InSamples = global.nsectors*CD_FRAMESAMPLES - current_offset/4; + /* how many samples are wanted? */ + InSamples = min((*nSamplesToDo-nSamplesDone),InSamples); + + /* when track end is reached, close current file and start a new one */ + while ((nSamplesDone < *nSamplesToDo) && (InSamples != 0)) { + long unsigned int how_much = InSamples; + + long int left_in_track; + left_in_track = Get_StartSector(current_track+1)*CD_FRAMESAMPLES + - (int)(BeginAtSample+nSamplesDone); + + if (*eorecording != 0 && current_track == cdtracks+1 && + (*total_segments_read) == (*total_segments_written)+1) { + /* limit, if the actual end of the last track is + * not known from the toc. */ + left_in_track = InSamples; + } + +if (left_in_track < 0) { + fprintf(stderr, "internal error: negative left_in_track:%ld, current_track=%d\n",left_in_track, current_track); +} + + if (bulk) { + how_much = min(how_much, (unsigned long) left_in_track); + } + +#ifdef MD5_SIGNATURES + if (global.md5count) { + MD5Update (&global.context, ((unsigned char *)p->data) +current_offset, min(global.md5count,how_much)); + global.md5count -= min(global.md5count,how_much); + } +#endif + if ( SaveBuffer ( p->data + current_offset/4, + how_much, + &nSamplesDone) ) { + if (global.have_forked == 1) { + pid_t ppid; + /* + * Kill the parent too if we are not orphaned. + */ + ppid = getppid(); + if (ppid > 1) + kill(ppid, SIGINT); + } + exit(WRITE_ERROR); + } + + global.nSamplesDoneInTrack += how_much; + SamplesToWrite -= how_much; + + /* move residual samples upto buffer start */ + if (how_much < InSamples) { + memmove( + (char *)(p->data) + current_offset, + (char *)(p->data) + current_offset + how_much*4, + (InSamples - how_much) * 4); + } + + if ((unsigned long) left_in_track <= InSamples || SamplesToWrite == 0) { + /* the current portion to be handled is + the end of a track */ + + if (bulk) { + /* finish sample file for this track */ + CloseAudio(global.channels, + global.nSamplesDoneInTrack, global.audio_out); + } else if (SamplesToWrite == 0) { + /* finish sample file for this track */ + CloseAudio(global.channels, + (unsigned int) *nSamplesToDo, global.audio_out); + } + + if (global.verbose) { +#ifdef USE_PARANOIA + double f; +#endif + print_percentage(&oper, current_offset); + fputc(' ', stderr); +#ifndef THOMAS_SCHAU_MAL + if ((unsigned long)left_in_track > InSamples) { + fputs(" incomplete", stderr); + } +#endif + if (global.tracktitle[current_track] != NULL) { + fprintf( stderr, + " track %2u '%s' recorded", + current_track, + global.tracktitle[current_track]); + } else { + fprintf( stderr, + " track %2u recorded", + current_track); + } +#ifdef USE_PARANOIA + oper = para_stat->readerrs + para_stat->skips + + para_stat->fixup_edges + para_stat->fixup_atoms + + para_stat->fixup_droppeds + para_stat->fixup_dupeds + + para_stat->drifts; + f = (100.0 * oper) / (((double)global.nSamplesDoneInTrack)/588.0); + + if (para_stat->readerrs) { + fprintf(stderr, " with audible hard errors"); + } else if ((para_stat->skips) > 0) { + fprintf(stderr, " with %sretry/skip errors", + f < 2.0 ? "":"audible "); + } else if (oper > 0) { + oper = f; + + fprintf(stderr, " with "); + if (oper < 2) + fprintf(stderr, "minor"); + else if (oper < 10) + fprintf(stderr, "medium"); + else if (oper < 67) + fprintf(stderr, "noticable audible"); + else if (oper < 100) + fprintf(stderr, "major audible"); + else + fprintf(stderr, "extreme audible"); + fprintf(stderr, " problems"); + } else { + fprintf(stderr, " successfully"); + } + if (f >= 0.1) + fprintf(stderr, " (%.1f%% problem sectors)", f); +#else + fprintf(stderr, " successfully"); +#endif + + if (waitforsignal == 1) { + fprintf(stderr, ". %d silent samples omitted", global.SkippedSamples); + } + fputs("\n", stderr); + + if (global.reads_illleadout && *eorecording == 1) { + fprintf(stderr, "Real lead out at: %ld sectors\n", + (*nSamplesToDo+BeginAtSample)/CD_FRAMESAMPLES); + } +#ifdef USE_PARANOIA + if (global.paranoia_selected) { + oper = 200; /* force new output */ + print_percentage(&oper, current_offset); + if (para_stat->minoverlap == 0x7FFFFFFF) + para_stat->minoverlap = 0; + fprintf(stderr, " %u rderr, %u skip, %u atom, %u edge, %u drop, %u dup, %u drift\n" + ,para_stat->readerrs + ,para_stat->skips + ,para_stat->fixup_atoms + ,para_stat->fixup_edges + ,para_stat->fixup_droppeds + ,para_stat->fixup_dupeds + ,para_stat->drifts); + oper = 200; /* force new output */ + print_percentage(&oper, current_offset); + fprintf(stderr, " %u overlap(%.4g .. %.4g)\n", + para_stat->overlaps, + (float)para_stat->minoverlap / (2352.0/2.0), + (float)para_stat->maxoverlap / (2352.0/2.0)); + paranoia_reset(); + } +#endif + } + + global.nSamplesDoneInTrack = 0; + if ( bulk && SamplesToWrite > 0 ) { + if ( !global.no_file ) { + char *tmp_fname; + + /* build next filename */ + tmp_fname = get_next_name(); + if (tmp_fname != NULL) { + strncpy(global.fname_base, + tmp_fname, + sizeof global.fname_base); + global.fname_base[ + sizeof(global.fname_base)-1] = + '\0'; + } + + tmp_fname = cut_extension(global.fname_base); + tmp_fname[0] = '\0'; + + if (global.multiname == 0) { + sprintf(fname, "%s_%02u.%s", + global.fname_base, + current_track+1, + audio_type); + } else { + sprintf(fname, "%s.%s", + global.fname_base, + audio_type); + } + + OpenAudio( fname, rate, bits, global.channels, + (Get_AudioStartSector(current_track+1) - + Get_AudioStartSector(current_track)) + *CD_FRAMESIZE_RAW, + global.audio_out); + } /* global.nofile */ + } /* if ( bulk && SamplesToWrite > 0 ) */ + current_track++; + + } /* left_in_track <= InSamples */ + InSamples -= how_much; + + } /* end while */ + if (!global.quiet && *nSamplesToDo != nSamplesDone) { + print_percentage(&oper, current_offset); + } + return nSamplesDone; +} + +#define PRINT_OVERLAP_INIT \ + if (global.verbose) { \ + if (global.overlap > 0) \ + fprintf(stderr, "overlap:min/max/cur, jitter, percent_done:\n / / / 0%%"); \ + else \ + fputs("percent_done:\n 0%", stderr); \ + } + +#if defined HAVE_FORK_AND_SHAREDMEM +static void forked_read(void); + +/* This function does all audio cdrom reads + * until there is nothing more to do + */ +static void forked_read() +{ + unsigned total_unsuccessful_retries = 0; + +#if !defined(HAVE_SEMGET) || !defined(USE_SEMAPHORES) + init_child(); +#endif + + minover = global.nsectors; + + PRINT_OVERLAP_INIT + while (global.iloop) { + + do_read(get_next_buffer(), &total_unsuccessful_retries); + + define_buffer(); + + } /* while (global.iloop) */ + + if (total_unsuccessful_retries) { + fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries); + } +} + +static void forked_write(void); + +static void forked_write() +{ + + /* don't need these anymore. Good security policy says we get rid + of them ASAP */ + priv_off(); + neverneedroot(); + neverneedgroup(); + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) +#else + init_parent(); +#endif + + for (;nSamplesDone < *nSamplesToDo;) { + if (*eorecording == 1 && (*total_segments_read) == (*total_segments_written)) break; + + /* get oldest buffers */ + + nSamplesDone = do_write(get_oldest_buffer()); + + drop_buffer(); + + } /* end for */ + +} +#endif + +/* This function implements the read and write calls in one loop (in case + * there is no fork/thread_create system call). + * This means reads and writes have to wait for each other to complete. + */ +static void nonforked_loop(void); + +static void nonforked_loop() +{ + unsigned total_unsuccessful_retries = 0; + + minover = global.nsectors; + + PRINT_OVERLAP_INIT + while (global.iloop) { + + do_read(get_next_buffer(), &total_unsuccessful_retries); + + do_write(get_oldest_buffer()); + + } + + if (total_unsuccessful_retries) { + fprintf(stderr,"%u unsuccessful matches while reading\n",total_unsuccessful_retries); + } + +} + +void verbose_usage(void); + +void verbose_usage() +{ + fputs("\ + help lists all verbose options.\n\ + disable disables verbose mode.\n\ + all enables all verbose options.\n\ + toc display the table of contents.\n\ + summary display a summary of track parameters.\n\ + indices retrieve/display index positions.\n\ + catalog retrieve/display media catalog number.\n\ + trackid retrieve/display international standard recording code.\n\ + sectors display the start sectors of each track.\n\ + titles display any known track titles.\n\ +", stderr); +} + +#ifdef USE_PARANOIA +void paranoia_usage(void); + +void paranoia_usage() +{ + fputs("\ + help lists all paranoia options.\n\ + disable disables paranoia mode. Paranoia is still being used.\n\ + no-verify switches verify off, and overlap on.\n\ + retries=amount set the number of maximum retries per sector.\n\ + overlap=amount set the number of sectors used for statical paranoia overlap.\n\ + minoverlap=amt set the min. number of sectors used for dynamic paranoia overlap.\n\ + maxoverlap=amt set the max. number of sectors used for dynamic paranoia overlap.\n\ +", stderr); +} +#endif + +int +handle_verbose_opts(char *optstr, long *flagp); + +int handle_verbose_opts(char *optstr, long *flagp) +{ + char *ep; + char *np; + int optlen; + + *flagp = 0; + while (*optstr) { + if ((ep = strchr(optstr, ',')) != NULL) { + optlen = ep - optstr; + np = ep + 1; + } else { + optlen = strlen(optstr); + np = optstr + optlen; + } + if (strncmp(optstr, "toc", optlen) == 0) { + *flagp |= SHOW_TOC; + } + else if (strncmp(optstr, "summary", optlen) == 0) { + *flagp |= SHOW_SUMMARY; + } + else if (strncmp(optstr, "indices", optlen) == 0) { + *flagp |= SHOW_INDICES; + } + else if (strncmp(optstr, "catalog", optlen) == 0) { + *flagp |= SHOW_MCN; + } + else if (strncmp(optstr, "trackid", optlen) == 0) { + *flagp |= SHOW_ISRC; + } + else if (strncmp(optstr, "sectors", optlen) == 0) { + *flagp |= SHOW_STARTPOSITIONS; + } + else if (strncmp(optstr, "titles", optlen) == 0) { + *flagp |= SHOW_TITLES; + } + else if (strncmp(optstr, "all", optlen) == 0) { + *flagp |= SHOW_MAX; + } + else if (strncmp(optstr, "disable", optlen) == 0) { + *flagp = 0; + } + else if (strncmp(optstr, "help", optlen) == 0) { + verbose_usage(); + exit(NO_ERROR); + } + else { + char *endptr; + unsigned arg = strtoul(optstr, &endptr, 10); + if (optstr != endptr + && arg <= SHOW_MAX) { + *flagp |= arg; + fprintf(stderr, "Warning: numerical parameters for -v are no more supported in the next releases!\n"); + } + else { + fprintf(stderr, "unknown option %s\n", optstr); + verbose_usage(); + exit(SYNTAX_ERROR); + } + } + optstr = np; + } + return 1; +} + + +int +handle_paranoia_opts(char *optstr, long *flagp); + +int handle_paranoia_opts(char *optstr, long *flagp) +{ +#ifdef USE_PARANOIA + char *ep; + char *np; + int optlen; + + while (*optstr) { + if ((ep = strchr(optstr, ',')) != NULL) { + optlen = ep - optstr; + np = ep + 1; + } else { + optlen = strlen(optstr); + np = optstr + optlen; + } + if (strncmp(optstr, "retries=", min(8,optlen)) == 0) { + char *eqp = strchr(optstr, '='); + int rets; + + astoi(eqp+1, &rets); + if (rets >= 0) { + global.paranoia_parms.retries = rets; + } + } + else if (strncmp(optstr, "overlap=", min(8, optlen)) == 0) { + char *eqp = strchr(optstr, '='); + int rets; + + astoi(eqp+1, &rets); + if (rets >= 0) { + global.paranoia_parms.overlap = rets; + } + } + else if (strncmp(optstr, "minoverlap=", min(11, optlen)) == 0) { + char *eqp = strchr(optstr, '='); + int rets; + + astoi(eqp+1, &rets); + if (rets >= 0) { + global.paranoia_parms.mindynoverlap = rets; + } + } + else if (strncmp(optstr, "maxoverlap=", min(11, optlen)) == 0) { + char *eqp = strchr(optstr, '='); + int rets; + + astoi(eqp+1, &rets); + if (rets >= 0) { + global.paranoia_parms.maxdynoverlap = rets; + } + } + else if (strncmp(optstr, "no-verify", optlen) == 0) { + global.paranoia_parms.disable_extra_paranoia = 1; + } + else if (strncmp(optstr, "disable", optlen) == 0) { + global.paranoia_parms.disable_paranoia = 1; + } + else if (strncmp(optstr, "help", optlen) == 0) { + paranoia_usage(); + exit(NO_ERROR); + } + else { + fprintf(stderr, "unknown option %s\n", optstr); + paranoia_usage(); + exit(SYNTAX_ERROR); + } + optstr = np; + } + return 1; +#else + fputs("lib paranoia support is not configured!\n", stderr); + return 0; +#endif +} + + +/* and finally: the MAIN program */ +int main(int argc, char *argv[]) +{ + long lSector_p1; + long sector_offset = 0; + unsigned long endtrack = 1; + double rectime = DURATION; + int cd_index = -1; + double int_part; + int littleendian = -1; + char *int_name; + static char *user_sound_device = ""; + char * env_p; + int tracks_included; + int moreargs; + + int_name = DEF_INTERFACE; + audio_type = AUDIOTYPE; + save_args(argc, argv); + + /* init global variables */ + init_globals(); +{ + int am_i_cdda2wav; + /* When being invoked as list_audio_tracks, just dump a list of + audio tracks. */ + am_i_cdda2wav = !(strlen(argv[0]) >= sizeof("list_audio_tracks")-1 + && !strcmp(argv[0]+strlen(argv[0])+1-sizeof("list_audio_tracks"),"list_audio_tracks")); + if (!am_i_cdda2wav) global.verbose = SHOW_JUSTAUDIOTRACKS; +} + /* Control those set-id privileges... */ + initsecurity(); + + env_p = getenv("CDDA_DEVICE"); + if (env_p != NULL) { + global.dev_name = env_p; + } + + env_p = getenv("CDDBP_SERVER"); + if (env_p != NULL) { + global.cddbp_server = env_p; + } + + env_p = getenv("CDDBP_PORT"); + if (env_p != NULL) { + global.cddbp_port = env_p; + } + +{ + int cac; + char *const*cav; + + BOOL version = FALSE; + BOOL help = FALSE; + char *channels = NULL; + int irate = -1; + char *divider = NULL; + char *trackspec = NULL; + char *duration = NULL; + + char *oendianess = NULL; + char *cendianess = NULL; + int cddbp = -1; + BOOL stereo = FALSE; + BOOL mono = FALSE; + BOOL domax = FALSE; + BOOL dump_rates = FALSE; + int userverbose = -1; + long paraopts = 0; + + cac = argc; + cav = argv; + cac--; + cav++; + if (getargs(&cac, &cav, opts + , &global.paranoia_selected + , handle_paranoia_opts, ¶opts + , &version + , &help, &help + + , &global.no_file, &global.no_file + , &dump_rates, &dump_rates + , &bulk, &bulk, &bulk + , &global.scsi_verbose, &global.scsi_verbose + + , &global.findminmax, &global.findminmax + , &global.findmono, &global.findmono + , &global.no_infofile, &global.no_infofile + + , &global.deemphasize, &global.deemphasize + , &global.just_the_toc, &global.just_the_toc + , &global.scsi_silent, &global.scsi_silent + + , &global.cddbp_server, &global.cddbp_port + , &global.scanbus + , &global.scandevs + , &global.dev_name, &global.dev_name, &global.dev_name + , &global.aux_name, &global.aux_name + , &int_name, &int_name + , &audio_type, &audio_type + + , &oendianess, &oendianess + , &cendianess, &cendianess + , &global.userspeed, &global.userspeed + + , &global.playback_rate, &global.playback_rate + , &global.md5blocksize, &global.md5blocksize + , &global.useroverlap, &global.useroverlap + , &user_sound_device, &user_sound_device + + , &cddbp, &cddbp + , &channels, &channels + , &bits, &bits + , &irate, &irate + , &global.gui, &global.gui + + , ÷r, ÷r + , &trackspec, &trackspec + , &cd_index, &cd_index + , &duration, &duration + , §or_offset, §or_offset + + , &global.nsectors, &global.nsectors + , handle_verbose_opts, &userverbose + , handle_verbose_opts, &userverbose + , &global.buffers, &global.buffers + + , &stereo, &stereo + , &mono, &mono + , &waitforsignal, &waitforsignal + , &global.echo, &global.echo + , &global.quiet, &global.quiet + , &domax, &domax + + ) < 0) { + errmsgno(EX_BAD, "Bad Option: %s.\n", cav[0]); + fputs ("use 'icedax -help' to get more information.\n", stderr); + exit (SYNTAX_ERROR); + } + if (getfiles(&cac, &cav, opts) == 0) + /* No more file type arguments */; + moreargs = cav - argv; + if (version) { + fprintf(stderr, "icedax " CDRKIT_VERSION "\n"); + exit(EXIT_SUCCESS); + } + if (help) { + usage(); + } + if (!global.scanbus) + cdr_defaults(&global.dev_name, NULL, NULL, NULL); + if (dump_rates) { /* list available rates */ + int ii; + + fputs("\ +Available rates are:\n\ +Rate Divider Rate Divider Rate Divider Rate Divider\n\ +" , stderr ); + for (ii = 1; ii <= 44100 / 880 / 2; ii++) { + long i2 = ii; + fprintf(stderr, "%7.1f %2ld %7.1f %2ld.5 ", + 44100.0/i2, i2, 44100.0/(i2+0.5), i2); + i2 += 25; + fprintf(stderr, "%7.1f %2ld %7.1f %2ld.5\n", + 44100.0/i2, i2, 44100.0/(i2+0.5), i2); + i2 -= 25; + } + exit(NO_ERROR); + } + if (channels) { + if (*channels == 's') { + global.channels = 2; + global.swapchannels = 1; + } else { + global.channels = strtol(channels, NULL, 10); + } + } + if (irate >= 0) { + rate = irate; + } + if (divider) { + double divider_d; + divider_d = strtod(divider , NULL); + if (divider_d > 0.0) { + rate = 44100.0 / divider_d; + } else { + fputs("E option -divider requires a nonzero, positive argument.\nSee -dump-rates.", stderr); + exit(SYNTAX_ERROR); + } + } + if (trackspec) { + char * endptr; + char * endptr2; + track = strtoul(trackspec, &endptr, 10 ); + endtrack = strtoul(endptr, &endptr2, 10 ); + if (endptr2 == endptr) { + endtrack = track; + } else if (track == endtrack) { + bulk = -1; + } + } + if (duration) { + char *end_ptr = NULL; + rectime = strtod(duration, &end_ptr ); + if (*end_ptr == 'f') { + rectime = rectime / 75.0; + /* TODO: add an absolute end of recording. */ +#if 0 + } else if (*end_ptr == 'F') { + rectime = rectime / 75.0; +#endif + } else if (*end_ptr != '\0') { + rectime = -1.0; + } + } + if (oendianess) { + if (strcasecmp(oendianess, "little") == 0) { + global.outputendianess = LITTLE; + } else if (strcasecmp(oendianess, "big") == 0) { + global.outputendianess = BIG; + } else { + usage2("wrong parameter '%s' for option -E", oendianess); + } + } + if (cendianess) { + if (strcasecmp(cendianess, "little") == 0) { + littleendian = 1; + } else if (strcasecmp(cendianess, "big") == 0) { + littleendian = 0; + } else if (strcasecmp(cendianess, "guess") == 0) { + littleendian = -2; + } else { + usage2("wrong parameter '%s' for option -C", cendianess); + } + } + if (cddbp >= 0) { + global.cddbp = 1 + cddbp; + } + if (stereo) { + global.channels = 2; + } + if (mono) { + global.channels = 1; + global.need_hostorder = 1; + } + if (global.echo) { +#ifdef ECHO_TO_SOUNDCARD + if (global.playback_rate != 100) { + RestrictPlaybackRate( global.playback_rate ); + } + global.need_hostorder = 1; +#else + fprintf(stderr, "There is no sound support compiled into %s.\n",argv[0]); + global.echo = 0; +#endif + } + if (global.quiet) { + global.verbose = 0; + } + if (domax) { + global.channels = 2; bits = 16; rate = 44100; + } + if (global.findminmax) { + global.need_hostorder = 1; + } + if (global.deemphasize) { + global.need_hostorder = 1; + } + if (global.just_the_toc) { + global.verbose = SHOW_MAX; + bulk = 1; + } + if (global.gui) { +#ifdef Thomas_will_es + global.no_file = 1; + global.no_infofile = 1; + global.verbose = SHOW_MAX; +#endif + global.no_cddbfile = 1; + } + if (global.no_file) { + global.no_infofile = 1; + global.no_cddbfile = 1; + } + if (global.no_infofile) { + global.no_cddbfile = 1; + } + if (global.md5blocksize) { +#ifdef MD5_SIGNATURES + fputs("MD5 signatures are currently broken! Sorry\n", stderr); +#else + fputs("MD5 signatures are currently broken! Sorry\n", stderr); +#endif + } + if (user_sound_device) { +#ifndef ECHO_TO_SOUNDCARD + fputs("There is no sound support configured!\n", stderr); +#endif + } + if (global.paranoia_selected) { + global.useroverlap = 0; + } + if (userverbose >= 0) { + global.verbose = userverbose; + } +} + + /* check all parameters */ + if (global.buffers < 1) { + usage2("Incorrect buffer setting: %d", global.buffers); + } + + if (global.nsectors < 1) { + usage2("Incorrect nsectors setting: %d", global.nsectors); + } + + if (global.verbose < 0 || global.verbose > SHOW_MAX) { + usage2("Incorrect verbose level setting: %d",global.verbose); + } + if (global.verbose == 0) global.quiet = 1; + + if ( rectime < 0.0 ) { + usage2("Incorrect recording time setting: %d.%02d", + (int)rectime, (int)(rectime*100+0.5) % 100); + } + + if ( global.channels != 1 && global.channels != 2 ) { + usage2("Incorrect channel setting: %d",global.channels); + } + + if ( bits != 8 && bits != 12 && bits != 16 ) { + usage2("Incorrect bits_per_sample setting: %d",bits); + } + + if ( rate < 827.0 || rate > 44100.0 ) { + usage2("Incorrect sample rate setting: %d.%02d", + (int)rate, ((int)rate*100) % 100); + } + + int_part = (double)(long) (2*44100.0 / rate); + + if (2*44100.0 / rate - int_part >= 0.5 ) { + int_part += 1.0; + fprintf( stderr, "Nearest available sample rate is %d.%02d Hertz\n", + 2*44100 / (int)int_part, + (2*4410000 / (int)int_part) % 100); + } + Halved = ((int) int_part) & 1; + rate = 2*44100.0 / int_part; + undersampling = (int) int_part / 2.0; + samples_to_do = undersampling; + + if (!strcmp((char *)int_name,"generic_scsi")) + interface = GENERIC_SCSI; + else if (!strcmp((char *)int_name,"cooked_ioctl")) + interface = COOKED_IOCTL; + else { + usage2("Incorrect interface setting: %s",int_name); + } + + /* check * init audio file */ + if (!strncmp(audio_type,"wav",3)) { + global.audio_out = &wavsound; + } else if (!strncmp(audio_type, "sun", 3) || !strncmp(audio_type, "au", 2)) { + /* Enhanced compatibility */ + audio_type = "au"; + global.audio_out = &sunsound; + } else if (!strncmp(audio_type, "cdr", 3) || + !strncmp(audio_type, "raw", 3)) { + global.audio_out = &rawsound; + } else if (!strncmp(audio_type, "aiff", 4)) { + global.audio_out = &aiffsound; + } else if (!strncmp(audio_type, "aifc", 4)) { + global.audio_out = &aifcsound; +#ifdef USE_LAME + } else if (!strncmp(audio_type, "mp3", 3)) { + global.audio_out = &mp3sound; + if (!global.quiet) { + unsigned char Lame_version[20]; + + fetch_lame_version(Lame_version); + fprintf(stderr, "Using LAME version %s.\n", Lame_version); + } + if (bits < 9) { + bits = 16; + fprintf(stderr, "Warning: sample size forced to 16 bit for MP3 format.\n"); + } +#endif /* USE_LAME */ + } else { + usage2("Incorrect audio type setting: %3s", audio_type); + } + + if (bulk == -1) bulk = 0; + + global.need_big_endian = global.audio_out->need_big_endian; + if (global.outputendianess != NONE) + global.need_big_endian = global.outputendianess == BIG; + + if (global.no_file) global.fname_base[0] = '\0'; + + if (!bulk) { + strcat(global.fname_base, "."); + strcat(global.fname_base, audio_type); + } + + /* If we need to calculate with samples or write them to a soundcard, + * we need a conversion to host byte order. + */ + if (global.channels != 2 + || bits != 16 + || rate != 44100) + global.need_hostorder = 1; + + /* Bad hack!! + * Remove for release 2.0 + * this is a bug compatibility feature. + */ + if (global.gui && global.verbose == SHOW_TOC) + global.verbose |= SHOW_STARTPOSITIONS | SHOW_SUMMARY | SHOW_TITLES; + + /* + * all options processed. + * Now a file name per track may follow + */ + argc2 = argc3 = argc - moreargs; + argv2 = argv + moreargs; + if ( moreargs < argc ) { + if (!strcmp(argv[moreargs],"-")) { +#ifdef NEED_O_BINARY + setmode(fileno(stdout), O_BINARY); +#endif + global.audio = dup (fileno(stdout)); + strncpy( global.fname_base, "standard_output", sizeof(global.fname_base) ); + global.fname_base[sizeof(global.fname_base)-1]=0; + } else if (!is_fifo(argv[moreargs])) { + /* we do have at least one argument */ + global.multiname = 1; + } + } + +#define SETSIGHAND(PROC, SIG, SIGNAME) if (signal(SIG, PROC) == SIG_ERR) \ + { fprintf(stderr, "cannot set signal %s handler\n", SIGNAME); exit(SETSIG_ERROR); } + SETSIGHAND(exit_wrapper, SIGINT, "SIGINT") + SETSIGHAND(exit_wrapper, SIGQUIT, "SIGQUIT") + SETSIGHAND(exit_wrapper, SIGTERM, "SIGTERM") + SETSIGHAND(exit_wrapper, SIGHUP, "SIGHUP") + + SETSIGHAND(set_nonforked, SIGPIPE, "SIGPIPE") + + /* setup interface and open cdrom device */ + /* request sychronization facilities and shared memory */ + SetupInterface( ); + + /* use global.useroverlap to set our overlap */ + if (global.useroverlap != -1) + global.overlap = global.useroverlap; + + /* check for more valid option combinations */ + + if (global.nsectors < 1+global.overlap) { + fprintf( stderr, "Warning: Setting #nsectors to minimum of %d, due to jitter correction!\n", global.overlap+1); + global.nsectors = global.overlap+1; + } + + if (global.overlap > 0 && global.buffers < 2) { + fprintf( stderr, "Warning: Setting #buffers to minimum of 2, due to jitter correction!\n"); + global.buffers = 2; + } + + /* Value of 'nsectors' must be defined here */ + + global.shmsize = 0; +#ifdef USE_PARANOIA + while (global.shmsize < sizeof (struct paranoia_statistics)) + global.shmsize += global.pagesize; +#endif + global.shmsize += 10*global.pagesize; /* XXX Der Speicherfehler ist nicht in libparanoia sondern in cdda2wav :-( */ + global.shmsize += HEADER_SIZE + ENTRY_SIZE_PAGE_AL * global.buffers; + +#if defined (HAVE_FORK_AND_SHAREDMEM) + /* + * The (void *) cast is to avoid a GCC warning like: + * warning: dereferencing type-punned pointer will break strict-aliasing rules + * which does not apply to this code. (void *) introduces a compatible + * intermediate type in the cast list. + */ + he_fill_buffer = request_shm_sem(global.shmsize, (unsigned char **)(void *)&he_fill_buffer); + if (he_fill_buffer == NULL) { + fprintf( stderr, "no shared memory available!\n"); + exit(SHMMEM_ERROR); + } +#else /* do not have fork() and shared memory */ + he_fill_buffer = malloc(global.shmsize); + if (he_fill_buffer == NULL) { + fprintf( stderr, "no buffer memory available!\n"); + exit(NOMEM_ERROR); + } +#endif +#ifdef USE_PARANOIA + { + int i = 0; + + para_stat = (struct paranoia_statistics *)he_fill_buffer; + while (i < sizeof (struct paranoia_statistics)) { + i += global.pagesize; + he_fill_buffer += global.pagesize; + global.shmsize -= global.pagesize; + } + } +#endif + + if (global.verbose != 0) + fprintf(stderr, + "%u bytes buffer memory requested, %d buffers, %d sectors\n", + global.shmsize, global.buffers, global.nsectors); + + /* initialize pointers into shared memory segment */ + last_buffer = he_fill_buffer + 1; + total_segments_read = (unsigned long *) (last_buffer + 1); + total_segments_written = total_segments_read + 1; + child_waits = (int *) (total_segments_written + 1); + parent_waits = child_waits + 1; + in_lendian = parent_waits + 1; + eorecording = in_lendian + 1; + *total_segments_read = *total_segments_written = 0; + nSamplesToDo = (unsigned long *)(eorecording + 1); + *eorecording = 0; + *in_lendian = global.in_lendian; + + set_total_buffers(global.buffers, sem_id); + + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) + atexit ( free_sem ); +#endif + + /* + * set input endian default + */ + if (littleendian != -1) + *in_lendian = littleendian; + + /* get table of contents */ + cdtracks = ReadToc(); + if (cdtracks == 0) { + fprintf(stderr, "No track in table of contents! Aborting...\n"); + exit(MEDIA_ERROR); + } + + calc_cddb_id(); + calc_cdindex_id(); + +#if 1 + Check_Toc(); +#endif + + if (ReadTocText != NULL && FirstAudioTrack () != -1) { + ReadTocText(get_scsi_p()); + handle_cdtext(); + } + if ( global.verbose == SHOW_JUSTAUDIOTRACKS ) { + unsigned int z; + + for (z = 0; z < cdtracks; z++) + if (Get_Datatrack(z) == 0) + printf("%02d\t%06ld\n", Get_Tracknumber(z), Get_AudioStartSector(z)); + exit(NO_ERROR); + } + + if ( global.verbose != 0 ) { + fputs( "#icedax version ", stderr ); + fputs( VERSION, stderr ); +#if defined USE_POSIX_PRIORITY_SCHEDULING || defined HAVE_SYS_PRIOCNTL_H + fputs( ", real time sched.", stderr ); +#endif +#if defined ECHO_TO_SOUNDCARD + fputs( ", soundcard", stderr ); +#endif +#if defined USE_PARANOIA + fputs( ", libparanoia", stderr ); +#endif + fputs( " support\n", stderr ); + } + + FixupTOC(cdtracks + 1); + +#if 0 + if (!global.paranoia_selected) { + fprintf(stderr, "NICE\n"); + /* try to get some extra kicks */ + priv_on(); + needroot(0); +#if defined HAVE_SETPRIORITY + setpriority(PRIO_PROCESS, 0, -20); +#else +# if defined(HAVE_NICE) && (HAVE_NICE == 1) + nice(-20); +# endif +#endif + priv_off(); + dontneedroot(); + } +#endif + + /* switch cdrom to audio mode */ + EnableCdda (get_scsi_p(), 1, CD_FRAMESIZE_RAW); + + atexit ( CloseAll ); + + DisplayToc(); + if ( FirstAudioTrack () == -1 ) { + if (no_disguised_audiotracks()) { + FatalError ( "This disk has no audio tracks\n" ); + } + } + + Read_MCN_ISRC(); + + /* check if start track is in range */ + if ( track < 1 || track > cdtracks ) { + usage2("Incorrect start track setting: %d",track); + } + + /* check if end track is in range */ + if ( endtrack < track || endtrack > cdtracks ) { + usage2("Incorrect end track setting: %ld",endtrack); + } + + do { + lSector = Get_AudioStartSector ( track ); + lSector_p1 = Get_EndSector ( track ) + 1; + + if ( lSector < 0 ) { + if ( bulk == 0 ) { + FatalError ( "Track %d not found\n", track ); + } else { + fprintf(stderr, "Skipping data track %d...\n", track); + if (endtrack == track) endtrack++; + track++; + } + } + } while (bulk != 0 && track <= cdtracks && lSector < 0); + + if ((global.illleadout_cd == 0 || global.reads_illleadout != 0) && cd_index != -1) { + if (global.verbose && !global.quiet) { + global.verbose |= SHOW_INDICES; + } + sector_offset += ScanIndices( track, cd_index, bulk ); + } else { + cd_index = 1; + if (global.deemphasize || (global.verbose & SHOW_INDICES)) { + ScanIndices( track, cd_index, bulk ); + } + } + + lSector += sector_offset; + /* check against end sector of track */ + if ( lSector >= lSector_p1 ) { + fprintf(stderr, "W Sector offset %lu exceeds track size (ignored)\n", sector_offset ); + lSector -= sector_offset; + } + + if ( lSector < 0L ) { + fputs( "Negative start sector! Set to zero.\n", stderr ); + lSector = 0L; + } + + lSector_p2 = Get_LastSectorOnCd( track ); + if (bulk == 1 && track == endtrack && rectime == 0.0) + rectime = 99999.0; + if ( rectime == 0.0 ) { + /* set time to track time */ + *nSamplesToDo = (lSector_p1 - lSector) * CD_FRAMESAMPLES; + rectime = (lSector_p1 - lSector) / 75.0; + if (CheckTrackrange( track, endtrack) == 1) { + lSector_p2 = Get_EndSector ( endtrack ) + 1; + + if (lSector_p2 >= 0) { + rectime = (lSector_p2 - lSector) / 75.0; + *nSamplesToDo = (long)(rectime*44100.0 + 0.5); + } else { + fputs( "End track is no valid audio track (ignored)\n", stderr ); + } + } else { + fputs( "Track range does not consist of audio tracks only (ignored)\n", stderr ); + } + } else { + /* Prepare the maximum recording duration. + * It is defined as the biggest amount of + * adjacent audio sectors beginning with the + * specified track/index/offset. */ + + if ( rectime > (lSector_p2 - lSector) / 75.0 ) { + rectime = (lSector_p2 - lSector) / 75.0; + lSector_p1 = lSector_p2; + } + + /* calculate # of samples to read */ + *nSamplesToDo = (long)(rectime*44100.0 + 0.5); + } + + global.OutSampleSize = (1+bits/12); + if (*nSamplesToDo/undersampling == 0L) { + usage2("Time interval is too short. Choose a duration greater than %d.%02d secs!", + undersampling/44100, (int)(undersampling/44100) % 100); + } + if ( moreargs < argc ) { + if (!strcmp(argv[moreargs],"-") || is_fifo(argv[moreargs])) { + /* + * pipe mode + */ + if (bulk == 1) { + fprintf(stderr, "W Bulk mode is disabled while outputting to a %spipe\n", + is_fifo(argv[moreargs]) ? "named " : ""); + bulk = 0; + } + global.no_cddbfile = 1; + } + } + if (global.no_infofile == 0) { + global.no_infofile = 1; + if (global.channels == 1 || bits != 16 || rate != 44100) { + fprintf(stderr, "W Sample conversions disable generation of info files!\n"); + } else if (waitforsignal == 1) { + fprintf(stderr, "W Option -w 'wait for signal' disables generation of info files!\n"); + } else if (sector_offset != 0) { + fprintf(stderr, "W Using an start offset (option -o) disables generation of info files!\n"); + } else if (!bulk && + !((lSector == Get_AudioStartSector(track)) && + ((long)(lSector + rectime*75.0 + 0.5) == Get_EndSector(track) + 1))) { + fprintf(stderr, "W Duration is not set for complete tracks (option -d), this disables generation\n of info files!\n"); + } else { + global.no_infofile = 0; + } + } + + SamplesToWrite = *nSamplesToDo*2/(int)int_part; + + { + int first = FirstAudioTrack(); + tracks_included = Get_Track( + (unsigned) (lSector + *nSamplesToDo/CD_FRAMESAMPLES -1)) + - max((int)track,first) +1; + } + + if (global.multiname != 0 && moreargs + tracks_included > argc) { + global.multiname = 0; + } + + if ( !waitforsignal ) { + +#ifdef INFOFILES + if (!global.no_infofile) { + int i; + + for (i = track; i < (int)track + tracks_included; i++) { + unsigned minsec, maxsec; + char *tmp_fname; + + /* build next filename */ + + tmp_fname = get_next_name(); + if (tmp_fname != NULL) + strncpy( global.fname_base, tmp_fname, sizeof(global.fname_base)-8 ); + global.fname_base[sizeof(global.fname_base)-1]=0; + minsec = max(lSector, Get_AudioStartSector(i)); + maxsec = min(lSector + rectime*75.0 + 0.5, 1+Get_EndSector(i)); + if ((int)minsec == Get_AudioStartSector(i) && + (int)maxsec == 1+Get_EndSector(i)) { + write_info_file(global.fname_base,i,(maxsec-minsec)*CD_FRAMESAMPLES, bulk && global.multiname == 0); + } else { + fprintf(stderr, + "Partial length copy for track %d, no info file will be generated for this track!\n", i); + } + if (!bulk) break; + } + reset_name_iterator(); + } +#endif + + } + + if (global.just_the_toc) exit(NO_ERROR); + +#ifdef ECHO_TO_SOUNDCARD + if (user_sound_device[0] != '\0') { + set_snd_device(user_sound_device); + } + init_soundcard(rate, bits); +#endif /* ECHO_TO_SOUNDCARD */ + + if (global.userspeed > -1) + global.speed = global.userspeed; + + if (global.speed != 0 && SelectSpeed != NULL) { + SelectSpeed(get_scsi_p(), global.speed); + } + + current_track = track; + + if ( !global.no_file ) { + { + char *myfname; + + myfname = get_next_name(); + + if (myfname != NULL) { + strncpy( global.fname_base, myfname, sizeof(global.fname_base)-8 ); + global.fname_base[sizeof(global.fname_base)-1]=0; + } + } + + /* strip audio_type extension */ + { + char *cp = global.fname_base; + + cp = strrchr(cp, '.'); + if (cp == NULL) { + cp = global.fname_base + strlen(global.fname_base); + } + *cp = '\0'; + } + if (bulk && global.multiname == 0) { + sprintf(fname, "%s_%02u.%s",global.fname_base,current_track,audio_type); + } else { + sprintf(fname, "%s.%s",global.fname_base,audio_type); + } + + OpenAudio( fname, rate, bits, global.channels, + (unsigned)(SamplesToWrite*global.OutSampleSize*global.channels), + global.audio_out); + } + + global.Remainder = (75 % global.nsectors)+1; + + global.sh_bits = 16 - bits; /* shift counter */ + + global.iloop = *nSamplesToDo; + if (Halved && (global.iloop&1)) + global.iloop += 2; + + BeginAtSample = lSector * CD_FRAMESAMPLES; + +#if 1 + if ( (global.verbose & SHOW_SUMMARY) && !global.just_the_toc && + (global.reads_illleadout == 0 || + lSector+*nSamplesToDo/CD_FRAMESAMPLES + <= (unsigned) Get_AudioStartSector(cdtracks-1))) { + + fprintf(stderr, "samplefile size will be %lu bytes.\n", + global.audio_out->GetHdrSize() + + global.audio_out->InSizeToOutSize(SamplesToWrite*global.OutSampleSize*global.channels) ); + fprintf (stderr, "recording %d.%04d seconds %s with %d bits @ %5d.%01d Hz" + ,(int)rectime , (int)(rectime * 10000) % 10000, + global.channels == 1 ? "mono":"stereo", bits, (int)rate, (int)(rate*10)%10); + if (!global.no_file && *global.fname_base) + fprintf(stderr, " ->'%s'...", global.fname_base ); + fputs("\n", stderr); + } +#endif + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) +#else + init_pipes(); +#endif + +#ifdef USE_PARANOIA + if (global.paranoia_selected) { + long paranoia_mode; + + global.cdp = paranoia_init(get_scsi_p(), global.nsectors); + + if (global.paranoia_parms.overlap >= 0) { + int overlap = global.paranoia_parms.overlap; + + if (overlap > global.nsectors - 1) + overlap = global.nsectors - 1; + paranoia_overlapset(global.cdp, overlap); + } + /* + * Default to a minimum of dynamic overlapping == 0.5 sectors. + * If we don't do this, we get the default from libparanoia + * which is approx. 0.1. + */ + if (global.paranoia_parms.mindynoverlap < 0) + paranoia_dynoverlapset(global.cdp, CD_FRAMEWORDS/2, -1); + paranoia_dynoverlapset(global.cdp, + global.paranoia_parms.mindynoverlap * CD_FRAMEWORDS, + global.paranoia_parms.maxdynoverlap * CD_FRAMEWORDS); + + paranoia_mode = PARANOIA_MODE_FULL ^ PARANOIA_MODE_NEVERSKIP; + + if (global.paranoia_parms.disable_paranoia) { + paranoia_mode = PARANOIA_MODE_DISABLE; + } + if (global.paranoia_parms.disable_extra_paranoia) { + paranoia_mode |= PARANOIA_MODE_OVERLAP; + paranoia_mode &= ~PARANOIA_MODE_VERIFY; + } + /* not yet implemented */ + if (global.paranoia_parms.disable_scratch_detect) { + paranoia_mode &= ~(PARANOIA_MODE_SCRATCH|PARANOIA_MODE_REPAIR); + } + /* not yet implemented */ + if (global.paranoia_parms.disable_scratch_repair) { + paranoia_mode &= ~PARANOIA_MODE_REPAIR; + } + + paranoia_modeset(global.cdp, paranoia_mode); + if (global.verbose) + fprintf(stderr, "using lib paranoia for reading.\n"); + paranoia_seek(global.cdp, lSector, SEEK_SET); + paranoia_reset(); + } +#endif +#if defined(HAVE_FORK_AND_SHAREDMEM) + + /* Everything is set up. Now fork and let one process read cdda sectors + and let the other one store them in a wav file */ + + /* forking */ + child_pid = fork(); + if (child_pid > 0 && global.gui > 0 && global.verbose > 0) + fprintf( stderr, "child pid is %d\n", child_pid); + + /*********************** fork **************************************/ + if (child_pid == 0) { + /* child WRITER section */ + +#ifdef HAVE_AREAS + /* Under BeOS a fork() with shared memory does not work as + * it does under System V Rel. 4. The mapping of the child + * works with copy on write semantics, so changes do not propagate + * back and forth. The existing mapping has to be deleted + * and replaced by an clone without copy on write semantics. + * This is done with clone_area(...,B_CLONE_ADDRESS,...). + * Thanks to file support.c from the postgreSQL project. + */ + area_info inf; + int32 cook = 0; + /* iterate over all mappings to find our shared memory mapping. */ + while (get_next_area_info(0, &cook, &inf) == B_OK) + { + /* check the name of the mapping. */ + if (!strcmp(inf.name, AREA_NAME)) + { + void *area_address; + area_id area_parent; + + /* kill the cow mapping. */ + area_address = inf.address; + if (B_OK != delete_area(inf.area)) + { + fprintf(stderr, "delete_area: no valid area.\n"); + exit(SHMMEM_ERROR); + } + /* get the parent mapping. */ + area_parent = find_area(inf.name); + if (area_parent == B_NAME_NOT_FOUND) + { + fprintf(stderr, "find_area: no such area name.\n"); + exit(SHMMEM_ERROR); + } + /* clone the parent mapping without cow. */ + if (B_OK > clone_area("shm_child", &area_address, B_CLONE_ADDRESS, + B_READ_AREA | B_WRITE_AREA, area_parent)) + { + fprintf(stderr,"clone_area failed\n"); + exit(SHMMEM_ERROR); + } + } + } +#endif +#ifdef __EMX__ + if (DosGetSharedMem(he_fill_buffer, 3)) { + comerr("DosGetSharedMem() failed.\n"); + } +#endif + global.have_forked = 1; + forked_write(); +#ifdef __EMX__ + DosFreeMem(he_fill_buffer); + _exit(NO_ERROR); + /* NOTREACHED */ +#endif + exit_wrapper(NO_ERROR); + /* NOTREACHED */ + } else if (child_pid > 0) { + /* parent READER section */ + + global.have_forked = 1; + switch_to_realtime_priority(); + + forked_read(); +#ifdef HAVE_AREAS + { + area_id aid; + aid = find_area(AREA_NAME); + if (aid < B_OK) { + comerrno(aid, "find_area() failed.\n"); + } + delete_area(aid); + } +#endif +#ifdef __EMX__ + DosFreeMem(he_fill_buffer); +#endif + exit_wrapper(NO_ERROR); + /* NOTREACHED */ + } else + perror("fork error."); + +#endif + /* version without fork */ + { + global.have_forked = 0; +#if 0 + if (!global.paranoia_selected) { + fprintf(stderr, "REAL\n"); + switch_to_realtime_priority(); + } +#endif + fprintf(stderr, "a nonforking version is running...\n"); + nonforked_loop(); + exit_wrapper(NO_ERROR); + /* NOTREACHED */ + } +#ifdef USE_PARANOIA + if (global.paranoia_selected) + paranoia_free(global.cdp); +#endif + + return 0; +} diff --git a/icedax/icedax.h b/icedax/icedax.h new file mode 100644 index 0000000..9795aac --- /dev/null +++ b/icedax/icedax.h @@ -0,0 +1,150 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)icedax.h 1.4 00/02/13 Copyright 1998,1999,2000 Heiko Eissfeldt */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * prototypes from cdda2wav.c + */ + +#ifdef max +#undef max +#endif +#ifdef min +#undef min +#endif +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define min(a,b) ((a) < (b) ? (a) : (b)) + + +/* verbose levels */ +#define SHOW_TOC 1 +#define SHOW_SUMMARY 2 +#define SHOW_INDICES 4 +#define SHOW_MCN 8 +#define SHOW_ISRC 16 +#define SHOW_STARTPOSITIONS 32 +#define SHOW_TITLES 64 +#define SHOW_JUSTAUDIOTRACKS 128 +#define SHOW_MAX 255 + +/* Endianess */ +#define GUESS (-2) +#define NONE (-1) +#define LITTLE 0 +#define BIG 1 + +void FatalError(const char *szMessage, ...); +void AnalyzeQchannel(unsigned frame); +long SamplesNeeded(long amount, long undersampling); +unsigned int get_current_track(void); + +#if defined (sun) && !defined(SVR4) +#define atexit(f) on_exit(f, 0) +#endif + +#ifndef _LINUX_CDROM_H +#define _LINUX_CDROM_H + +/* + * some fix numbers + */ +#define CD_MINS 74 /* max. minutes per CD, not really a limit */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ + +#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame, not transfered by the drive */ +#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ +#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ +#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ +#define CD_XA_SYNC_HEAD (CD_SYNC_SIZE+CD_XA_HEAD)/* sync bytes + header of XA frame */ + +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ +/* most drives don't deliver everything: */ +#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /* 2340 */ +#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /* 2336 */ +/* Optics drive also has a 'read all' mode: */ +#define CD_FRAMESIZE_RAWER 2646 /* bytes per frame */ + +#define CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */ +#define CD_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */ +#define CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */ +#define CD_XA_TAIL (CD_EDC_SIZE+CD_ECC_SIZE) /* "after data" part of raw XA frame */ + +#define CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */ +#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ + +#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */ +#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */ + +#define CD_FRAMESIZE_XA CD_FRAMESIZE_RAW1 /* obsolete name */ +#define CD_BLOCK_OFFSET CD_MSF_OFFSET /* obsolete name */ + +/* + * the raw frame layout: + * + * - audio (red): | audio_sample_bytes | + * | 2352 | + * + * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | + * | 12 - 4 - 2048 - 4 - 8 - 276 | + * + * - data (yellow, mode2): | sync - head - data | + * | 12 - 4 - 2336 | + * + * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | + * | 12 - 4 - 8 - 2048 - 4 - 276 | + * + * - XA data (green, mode2 form2): | sync - head - sub - data - EDC | + * | 12 - 4 - 8 - 2324 - 4 | + */ + + +/* + * CD-ROM address types (cdrom_tocentry.cdte_format) + */ +#if !defined CDROM_LBA +#define CDROM_LBA 0x01 /* "logical block": first frame is #0 */ +#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */ +#endif +/* + * bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) + */ +#define CDROM_DATA_TRACK 0x04 + +/* + * The leadout track is always 0xAA, regardless of # of tracks on disc + */ +#define CDROM_LEADOUT 0xAA + +/* + * audio states (from SCSI-2, but seen with other drives, too) + */ +#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */ +#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */ +#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */ +#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */ +#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */ +#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */ + +#ifdef FIVETWELVE +#define CDROM_MODE1_SIZE 512 +#else +#define CDROM_MODE1_SIZE 2048 +#endif /*FIVETWELVE*/ +#define CDROM_MODE2_SIZE 2336 + +#endif + diff --git a/icedax/inf2cdtext.pl b/icedax/inf2cdtext.pl new file mode 100755 index 0000000..483713f --- /dev/null +++ b/icedax/inf2cdtext.pl @@ -0,0 +1,241 @@ +#!/usr/bin/perl -w +# Copyright 2002 by Heiko Eißfeldt (Eissfeldt) +use strict; +use integer; + +# read all .inf files and generate the binary cdtext block +# for cdrecord. + +my @results; + +sub fill_packet +{ + my $ID = shift; + my $track = shift; + my $seq_nr = shift; + my $charpos = shift; + my $text = shift; + my $todo = shift; + + return if (!defined($$text)); + + my @packet = (); + push @packet, chr($ID); # track title, performer, ... + push @packet, chr($$track); + push @packet, chr($$seq_nr); + $$charpos = 15 if ($$charpos > 15); + push @packet, chr($$charpos); + + my $cp = 0; + my $tracks_inp = 0; + while (length($$text) + 1 < 12 - $cp) { + push @packet, split(//, $$text); + push @packet, chr(0); + $cp += length($$text) + 1; + $$charpos = 0; + $tracks_inp++; + + $$text = shift @$todo; + if ($#$todo < 1 && (!defined($$text) || $$text eq "") ) { + push @packet, (chr(0)) x (12 - $cp); + $$seq_nr++; + print_packet(@packet); + return; + } + $$text = "" if (!defined($$text)); + $$track++; + } + + # packet gets full + my $left = 12 - $cp; + if ($left > length($$text)) { + # title fits into packet + push @packet, split(//, $$text); + push @packet, chr(0); + $tracks_inp++; + print_packet(@packet); + + $$charpos = 0; + $$text = shift @$todo; + unless ((!defined($$text) || $$text eq "") && $#$todo < 1) { $$track++; } + $$seq_nr++; + } else { + # print current packet and more if more entries are present + push @packet, split(//, substr($$text, 0, $left)); + print_packet(@packet); + + $$text = substr($$text, $left); + $$charpos += $left; + $$seq_nr++; + } +} + +my @crctab =( + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, +); + +sub add_crc +{ + # crc with polynomial: x^16 + x^12 + x^5 + 1 + # 1,0001,0000,0010,0001 + my $packref = shift; + my $crc = 0; + + foreach (@$packref) { + $crc = ($crc << 8) ^ $crctab[ + ( ($crc >> (16-8)) ^ ord($_) ) & 0xff + ]; + $crc &= 0xffff; + } + $$packref[16] = chr((($crc >> 8) & 0xff) ^ 0xff); + $$packref[17] = chr(($crc & 0xff) ^ 0xff); +} + +sub print_packet +{ + return if ($#_ < 1); + my @packet = (@_); + add_crc(\@packet); + if ($packet[0] ne chr(0x8f)) { + printf STDERR ("%02x "x4 ." "."%c "x12 ." "."%02x "x2), map( defined($_) ? ord($_) : "___undef", @packet ); + } else { + printf STDERR ("%02x "x4 ." "."%02x "x12 ." "."%02x "x2), map( defined($_) ? ord($_) : "___undef", @packet ); + } + printf STDERR "\n"; + push @results, @packet; +} + +my $defaultperformer = $ARGV[0] || die "usage: ", $^X, " defaultperformer_name\n"; +my $prefix = $ARGV[1] || "audio"; +@ARGV = glob("${prefix}_??.inf"); +my @albumtitles; +my @tracktitles; +my @performers; +my $ISRC; +my @ISRCs; +my $MCN; + +my $performer; +while (<>) { + if (/^Performer=\s+'(.*?)'$/) { + $performer = $1; + } + if (/^Albumtitle=\s+'(.*?)'$/) { + push @albumtitles, $1; + } + if (/^Tracktitle=\s+'(.*?)'$/) { + push @tracktitles, $1; + } + if (/^ISRC=\s+(\S+?)$/) { + $ISRC = $1; + } + if (/^MCN=\s+(\S+?)$/) { + $MCN = $1; + } + if (eof) { + close ARGV; + $performer = $defaultperformer if (!defined($performer)); + push @performers, $performer; + $performer = undef; + push @ISRCs, $ISRC; + $ISRC = undef; + } +} + +# +my $seq_nr = 0; + +my @todo; +my $text; +my $track; +my $charpos; + +# build cdtext packets + +# build track titles +@todo = ($albumtitles[0], @tracktitles); +$text = shift @todo; +$track = 0; +$charpos = 0; + +while ($#todo > 1 || defined($text)) { + fill_packet(0x80, \$track, \$seq_nr, \$charpos, \$text, \@todo); +} + +my $trackpacks = $seq_nr; # store for later reference +my $last_track = $track; + +# build performer entries +#@todo = ($performer) x (1 + scalar(@tracktitles)); +@todo = ($defaultperformer, @performers); +$text = shift @todo; +$track = 0; +$charpos = 0; + +while ($#todo > 1 || defined($text)) { + fill_packet(0x81, \$track, \$seq_nr, \$charpos, \$text, \@todo); +} + +my $perfpacks = $seq_nr - $trackpacks; # store for later reference + +# build ISRC entries +@todo = ($MCN, @ISRCs); +$text = shift @todo; +$track = 0; +$charpos = 0; + +while ($#todo > 1 || defined($text)) { + $text = "" if (!defined($text)); + fill_packet(0x8e, \$track, \$seq_nr, \$charpos, \$text, \@todo); +} + +my $isrcpacks = $seq_nr - $trackpacks - $perfpacks; # store for later reference + +# build size information blocks +my $size1 = chr(0) . chr(1) . chr($last_track) . chr(0) + . chr($trackpacks) . chr($perfpacks) . chr(0) x 5; +my $size2 = chr(0) x 6 . chr($isrcpacks) . chr(3) . chr($seq_nr+2) . chr(0) x 2; +my $size3 = chr(0) x 4 . chr(9); # hard coded language 09 = english +@todo = ($size1, $size2, $size3); +$text = shift @todo; +$track = 0; +$charpos = 0; + +while ((defined($text) && $text ne "") ) { + fill_packet(0x8f, \$track, \$seq_nr, \$charpos, \$text, \@todo); +} + +# write out the results +my $size = @results + 2; +print chr($size >> 8), chr($size & 0xff), chr(0), chr(0), @results; diff --git a/icedax/interface.c b/icedax/interface.c new file mode 100644 index 0000000..ef7278a --- /dev/null +++ b/icedax/interface.c @@ -0,0 +1,1050 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)interface.c 1.40 06/02/19 Copyright 1998-2002 Heiko Eissfeldt, Copyright 2006 J. Schilling */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) 1994-1997 Heiko Eissfeldt heiko@colossus.escape.de + * + * Interface module for cdrom drive access + * + * Two interfaces are possible. + * + * 1. using 'cooked' ioctls() (Linux only) + * : available for atapi, sbpcd and cdu31a drives only. + * + * 2. using the generic scsi device (for details see SCSI Prog. HOWTO). + * NOTE: a bug/misfeature in the kernel requires blocking signal + * SIGINT during SCSI command handling. Once this flaw has + * been removed, the sigprocmask SIG_BLOCK and SIG_UNBLOCK calls + * should removed, thus saving context switches. + * + * For testing purposes I have added a third simulation interface. + * + * Version 0.8: used experiences of Jochen Karrer. + * SparcLinux port fixes + * AlphaLinux port fixes + * + */ +#if 0 +#define SIM_CD +#endif + +#include "config.h" +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <strdefs.h> +#include <errno.h> +#include <signal.h> +#include <fctldefs.h> +#include <assert.h> +#include <schily.h> +#include <device.h> + +#include <sys/ioctl.h> +#include <statdefs.h> + + +#include "mycdrom.h" +#include "lowlevel.h" +/* some include file locations have changed with newer kernels */ +#if defined (__linux__) +# if LINUX_VERSION_CODE > 0x10300 + 97 +# if LINUX_VERSION_CODE < 0x200ff +# include <linux/sbpcd.h> +# include <linux/ucdrom.h> +# endif +# if !defined(CDROM_SELECT_SPEED) +# include <linux/ucdrom.h> +# endif +# endif +#endif + +#include <usal/scsitransp.h> + +#include "mytype.h" +#include "byteorder.h" +#include "interface.h" +#include "icedax.h" +#include "semshm.h" +#include "setuid.h" +#include "ringbuff.h" +#include "toc.h" +#include "global.h" +#include "ioctl.h" +#include "exitcodes.h" +#include "scsi_cmds.h" + +#include <utypes.h> +#include <wodim.h> +#include "scsi_scan.h" + +unsigned interface; + +int trackindex_disp = 0; + +void priv_init(void); +void priv_on(void); +void priv_off(void); + +void (*EnableCdda)(SCSI *, int Switch, unsigned uSectorsize); +unsigned (*doReadToc)(SCSI *usalp); +void (*ReadTocText)(SCSI *usalp); +unsigned (*ReadLastAudio)(SCSI *usalp); +int (*ReadCdRom)(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +int (*ReadCdRomData)(SCSI *usalp, unsigned char *p, unsigned lSector, + unsigned SectorBurstVal); +int (*ReadCdRomSub)(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +subq_chnl *(*ReadSubChannels)(SCSI *usalp, unsigned lSector); +subq_chnl *(*ReadSubQ)(SCSI *usalp, unsigned char sq_format, + unsigned char track); +void (*SelectSpeed)(SCSI *usalp, unsigned speed); +int (*Play_at)(SCSI *usalp, unsigned int from_sector, unsigned int sectors); +int (*StopPlay)(SCSI *usalp); +void (*trash_cache)(UINT4 *p, unsigned lSector, unsigned SectorBurstVal); + +#if defined USE_PARANOIA +long cdda_read(void *d, void *buffer, long beginsector, long sectors); + +long cdda_read(void *d, void *buffer, long beginsector, long sectors) +{ + long ret = ReadCdRom(d, buffer, beginsector, sectors); + return ret; +} +#endif + +typedef struct string_len { + char *str; + unsigned int sl; +} mystring; + +static mystring drv_is_not_mmc[] = { + {"DEC RRD47 (C) DEC ",24}, +/* {"SONY CD-ROM CDU625 1.0",28}, */ + {NULL,0} /* must be last entry */ +}; + +static mystring drv_has_mmc_cdda[] = { + {"HITACHI CDR-7930",16}, +/* {"TOSHIBA CD-ROM XM-5402TA3605",28}, */ + {NULL,0} /* must be last entry */ +}; + +static int Is_a_Toshiba3401; + +int Toshiba3401(void); + +int Toshiba3401() +{ + return Is_a_Toshiba3401; +} + +/* hook */ +static void Dummy(void); +static void Dummy() +{ +} + +static SCSI *usalp; + +SCSI *get_scsi_p(void); + +SCSI *get_scsi_p() +{ + return usalp; +} + +#if !defined(SIM_CD) + +static void trash_cache_SCSI(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); + +static void trash_cache_SCSI(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + /* trash the cache */ + ReadCdRom(get_scsi_p(), p, find_an_off_sector(lSector, SectorBurstVal), min(global.nsectors,6)); +} + + + +static void Check_interface_for_device(struct stat *statstruct, + char *pdev_name); +static int OpenCdRom(char *pdev_name); + +static void SetupSCSI(void); + +static void SetupSCSI() +{ + unsigned char *p; + + if (interface != GENERIC_SCSI) { + /* unfortunately we have the wrong interface and are + * not able to change on the fly */ + fprintf(stderr, "The generic SCSI interface and devices are required\n"); + exit(SYNTAX_ERROR); + } + + /* do a test unit ready to 'init' the device. */ + TestForMedium(usalp); + + /* check for the correct type of unit. */ + p = Inquiry(usalp); + +#undef TYPE_ROM +#define TYPE_ROM 5 +#undef TYPE_WORM +#define TYPE_WORM 4 + if (p == NULL) { + fprintf(stderr, "Inquiry command failed. Aborting...\n"); + exit(DEVICE_ERROR); + } + + if ((*p != TYPE_ROM && *p != TYPE_WORM)) { + fprintf(stderr, "this is neither a scsi cdrom nor a worm device\n"); + exit(SYNTAX_ERROR); + } + + if (global.quiet == 0) { + fprintf(stderr, + "Type: %s, Vendor '%8.8s' Model '%16.16s' Revision '%4.4s' ", + *p == TYPE_ROM ? "ROM" : "WORM" + ,p+8 + ,p+16 + ,p+32); + } + /* generic Sony type defaults */ + density = 0x0; + accepts_fua_bit = -1; + EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy; + ReadCdRom = ReadCdda12; + ReadCdRomSub = ReadCddaSubSony; + ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadStandardData; + ReadLastAudio = ReadFirstSessionTOCSony; + SelectSpeed = SpeedSelectSCSISony; + Play_at = Play_atSCSI; + StopPlay = StopPlaySCSI; + trash_cache = trash_cache_SCSI; + ReadTocText = ReadTocTextSCSIMMC; + doReadToc = ReadTocSCSI; + ReadSubQ = ReadSubQSCSI; + ReadSubChannels = NULL; + + /* check for brands and adjust special peculiaritites */ + + /* If your drive is not treated correctly, you can adjust some things + here: + + global.in_lendian: should be to 1, if the CDROM drive or CD-Writer + delivers the samples in the native byteorder of the audio cd + (LSB first). + HP CD-Writers need it set to 0. + NOTE: If you get correct wav files when using sox with the '-x' option, + the endianess is wrong. You can use the -C option to specify + the value of global.in_lendian. + + */ + + { + int mmc_code; + + usalp->silent ++; + allow_atapi(usalp, 1); + if (*p == TYPE_ROM) { + mmc_code = heiko_mmc(usalp); + } else { + mmc_code = 0; + } + usalp->silent --; + + /* Exceptions for drives that report incorrect MMC capability */ + if (mmc_code != 0) { + /* these drives are NOT capable of MMC commands */ + mystring *pp = drv_is_not_mmc; + while (pp->str != NULL) { + if (!strncmp(pp->str, (char *)p+8,pp->sl)) { + mmc_code = 0; + break; + } + pp++; + } + } + { + /* these drives flag themselves as non-MMC, but offer CDDA reading + only with a MMC method. */ + mystring *pp = drv_has_mmc_cdda; + while (pp->str != NULL) { + if (!strncmp(pp->str, (char *)p+8,pp->sl)) { + mmc_code = 1; + break; + } + pp++; + } + } + + switch (mmc_code) { + case 2: /* SCSI-3 cdrom drive with accurate audio stream */ + /* fall through */ + case 1: /* SCSI-3 cdrom drive with no accurate audio stream */ + /* fall through */ +lost_toshibas: + global.in_lendian = 1; + if (mmc_code == 2) + global.overlap = 0; + else + global.overlap = 1; + ReadCdRom = ReadCddaFallbackMMC; + ReadCdRomSub = ReadCddaSubSony; + ReadLastAudio = ReadFirstSessionTOCMMC; + SelectSpeed = SpeedSelectSCSIMMC; + ReadTocText = ReadTocTextSCSIMMC; + doReadToc = ReadTocMMC; + ReadSubChannels = ReadSubChannelsFallbackMMC; + if (!memcmp(p+8,"SONY CD-RW CRX100E 1.0", 27)) ReadTocText = NULL; + if (!global.quiet) fprintf(stderr, "MMC+CDDA\n"); + break; + case -1: /* "MMC drive does not support cdda reading, sorry\n." */ + doReadToc = ReadTocMMC; + if (!global.quiet) fprintf(stderr, "MMC-CDDA\n"); + /* FALLTHROUGH */ + case 0: /* non SCSI-3 cdrom drive */ + if (!global.quiet) fprintf(stderr, "no MMC\n"); + ReadLastAudio = NULL; + if (!memcmp(p+8,"TOSHIBA", 7) || + !memcmp(p+8,"IBM", 3) || + !memcmp(p+8,"DEC", 3)) { + /* + * older Toshiba ATAPI drives don't identify themselves as MMC. + * The last digit of the model number is '2' for ATAPI drives. + * These are treated as MMC. + */ + if (!memcmp(p+15, " CD-ROM XM-", 11) && p[29] == '2') { + goto lost_toshibas; + } + density = 0x82; + EnableCdda = EnableCddaModeSelect; + ReadSubChannels = ReadStandardSub; + ReadCdRom = ReadStandard; + SelectSpeed = SpeedSelectSCSIToshiba; + if (!memcmp(p+15, " CD-ROM XM-3401",15)) { + Is_a_Toshiba3401 = 1; + } + global.in_lendian = 1; + } else if (!memcmp(p+8,"IMS",3) || + !memcmp(p+8,"KODAK",5) || + !memcmp(p+8,"RICOH",5) || + !memcmp(p+8,"HP",2) || + !memcmp(p+8,"PHILIPS",7) || + !memcmp(p+8,"PLASMON",7) || + !memcmp(p+8,"GRUNDIG CDR100IPW",17) || + !memcmp(p+8,"MITSUMI CD-R ",13)) { + EnableCdda = EnableCddaModeSelect; + ReadCdRom = ReadStandard; + SelectSpeed = SpeedSelectSCSIPhilipsCDD2600; + + /* treat all of these as bigendian */ + global.in_lendian = 0; + + /* no overlap reading for cd-writers */ + global.overlap = 0; + } else if (!memcmp(p+8,"NRC",3)) { + SelectSpeed = NULL; + } else if (!memcmp(p+8,"YAMAHA",6)) { + EnableCdda = EnableCddaModeSelect; + SelectSpeed = SpeedSelectSCSIYamaha; + + /* no overlap reading for cd-writers */ + global.overlap = 0; + global.in_lendian = 1; + } else if (!memcmp(p+8,"PLEXTOR",7)) { + global.in_lendian = 1; + global.overlap = 0; + ReadLastAudio = ReadFirstSessionTOCSony; + ReadTocText = ReadTocTextSCSIMMC; + doReadToc = ReadTocSony; + ReadSubChannels = ReadSubChannelsSony; + } else if (!memcmp(p+8,"SONY",4)) { + global.in_lendian = 1; + if (!memcmp(p+16, "CD-ROM CDU55E",13)) { + ReadCdRom = ReadCddaMMC12; + } + ReadLastAudio = ReadFirstSessionTOCSony; + ReadTocText = ReadTocTextSCSIMMC; + doReadToc = ReadTocSony; + ReadSubChannels = ReadSubChannelsSony; + } else if (!memcmp(p+8,"NEC",3)) { + ReadCdRom = ReadCdda10; + ReadTocText = NULL; + SelectSpeed = SpeedSelectSCSINEC; + global.in_lendian = 1; + if (!memcmp(p+29,"5022.0r",3)) /* I assume all versions of the 502 require this? */ + global.overlap = 0; /* no overlap reading for NEC CD-ROM 502 */ + } else if (!memcmp(p+8,"MATSHITA",8)) { + ReadCdRom = ReadCdda12Matsushita; + global.in_lendian = 1; + } + } /* switch (get_mmc) */ + } + + + /* look if caddy is loaded */ + if (interface == GENERIC_SCSI) { + usalp->silent++; + while (!wait_unit_ready(usalp, 60)) { + fprintf(stderr,"load cdrom please and press enter"); + getchar(); + } + usalp->silent--; + } +} + +/* Check to see if the device will support SCSI generic commands. A + * better check than simply looking at the device name. Open the + * device, issue an inquiry. If they both succeed, there's a good + * chance that the device works... */ +#if defined(__linux__) +static int check_linux_scsi_interface(char *pdev_name) +{ + SCSI *dev = NULL; + unsigned char *p = NULL; + char errstr[80]; + + dev = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0); + if (NULL == dev) + return EINVAL; + p = Inquiry(dev); + if (p) + { + usal_close(dev); + return 0; + } + usal_close(dev); + return EINVAL; +} +#endif + +/********************** General setup *******************************/ + +/* As the name implies, interfaces and devices are checked. We also + adjust nsectors, overlap, and interface for the first time here. + Any unnecessary privileges (setuid, setgid) are also dropped here. +*/ +static void Check_interface_for_device(struct stat *statstruct, char *pdev_name) +{ +#if defined(__linux__) + int is_scsi = 1; +#endif +#ifndef STAT_MACROS_BROKEN + if (!S_ISCHR(statstruct->st_mode) && + !S_ISBLK(statstruct->st_mode)) { + fprintf(stderr, "%s is not a device\n",pdev_name); + exit(SYNTAX_ERROR); + } +#endif + +/* Check what type of device we have */ +#if defined (__linux__) + if (check_linux_scsi_interface(pdev_name)) + is_scsi = 0; + if (interface == GENERIC_SCSI && !is_scsi) + { + fprintf(stderr, "device %s does not support generic_scsi; falling back to cooked_ioctl instead\n", pdev_name); + interface = COOKED_IOCTL; + } + if ((interface == COOKED_IOCTL) && + is_scsi && + (SCSI_GENERIC_MAJOR == major(statstruct->st_rdev))) + { + fprintf(stderr, "device %s is generic_scsi NOT cooked_ioctl\n", pdev_name); + interface = GENERIC_SCSI; + } +#else + +#if defined (HAVE_ST_RDEV) + switch (major(statstruct->st_rdev)) { +#if defined (__linux__) + case SCSI_GENERIC_MAJOR: /* generic */ +#else + default: /* ??? what is the proper value here */ +#endif +#ifndef STAT_MACROS_BROKEN +#if defined (__linux__) + if (!S_ISCHR(statstruct->st_mode)) { + fprintf(stderr, "%s is not a char device\n",pdev_name); + exit(SYNTAX_ERROR); + } + + if (interface != GENERIC_SCSI) { + fprintf(stderr, "wrong interface (cooked_ioctl) for this device (%s)\nset to generic_scsi\n", pdev_name); + interface = GENERIC_SCSI; + } +#endif +#else + default: /* ??? what is the proper value here */ +#endif + break; + +#if defined (__linux__) || defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#if defined (__linux__) + case SCSI_CDROM_MAJOR: /* scsi cd */ + default: /* for example ATAPI cds */ +#else +#if defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#if __FreeBSD_version >= 600021 + case 0: /* majors abandoned */ + /* FALLTHROUGH */ +#endif +#if __FreeBSD_version >= 501113 + case 4: /* GEOM */ + /* FALLTHROUGH */ +#endif + case 117: /* pre-GEOM atapi cd */ + if (!S_ISCHR(statstruct->st_mode)) { + fprintf(stderr, "%s is not a char device\n",pdev_name); + exit(SYNTAX_ERROR); + } + if (interface != COOKED_IOCTL) { + fprintf(stderr, +"cdrom device (%s) is not of type generic SCSI. \ +Setting interface to cooked_ioctl.\n", pdev_name); + interface = COOKED_IOCTL; + } + break; + case 19: /* first atapi cd */ +#endif +#endif + if (!S_ISBLK(statstruct->st_mode)) { + fprintf(stderr, "%s is not a block device\n",pdev_name); + exit(SYNTAX_ERROR); + } +#if defined (__linux__) +#if LINUX_VERSION_CODE >= 0x20600 + /* In Linux kernel 2.6 it is better to use the SCSI interface + * with the device. + */ + break; +#endif +#endif + if (interface != COOKED_IOCTL) { + fprintf(stderr, +"cdrom device (%s) is not of type generic SCSI. \ +Setting interface to cooked_ioctl.\n", pdev_name); + interface = COOKED_IOCTL; + } + + if (interface == COOKED_IOCTL) { + fprintf(stderr, "\nW: The cooked_ioctl interface is functionally very limited!!\n"); +#if defined (__linux__) + fprintf(stderr, "\nW: For good sampling quality simply use the generic SCSI interface!\n" + "For example dev=ATA:1,0,0\n"); +#endif + } + + break; +#endif + } +#endif +#endif + if (global.overlap >= global.nsectors) + global.overlap = global.nsectors-1; +} + +/* open the cdrom device */ +static int OpenCdRom(char *pdev_name) +{ + int retval = 0; + struct stat fstatstruct; + + /* The device (given by pdevname) can be: + a. an SCSI device specified with a /dev/xxx name, + b. an SCSI device specified with bus,target,lun numbers, + c. a non-SCSI device such as ATAPI or proprietary CDROM devices. + */ +#ifdef HAVE_IOCTL_INTERFACE + struct stat statstruct; + int have_named_device = 0; + + have_named_device = FALSE; + if (pdev_name) { + have_named_device = strchr(pdev_name, ':') == NULL + && memcmp(pdev_name, "/dev/", 5) == 0; + } + + if (have_named_device) { + if (stat(pdev_name, &statstruct)) { + fprintf(stderr, "cannot stat device %s\n", pdev_name); + exit(STAT_ERROR); + } else { + Check_interface_for_device( &statstruct, pdev_name ); + } + } +#endif + + if (interface == GENERIC_SCSI) { + char errstr[80]; + + priv_on(); + needroot(0); + needgroup(0); + /* + * Call usal_remote() to force loading the remote SCSI transport library + * code that is located in librusal instead of the dummy remote routines + * that are located inside libusal. + */ + usal_remote(); + if (pdev_name != NULL && + ((strncmp(pdev_name, "HELP", 4) == 0) || + (strncmp(pdev_name, "help", 4) == 0))) { + usal_help(stderr); + exit(NO_ERROR); + } + /* device name, debug, verboseopen */ + usalp = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0); + + if (usalp == NULL) { + int err = geterrno(); + + errmsgno(err, "%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":""); + errmsgno(EX_BAD, "For possible targets try 'wodim -scanbus'.%s\n", + geteuid() ? " Make sure you are root.":""); + priv_off(); + dontneedgroup(); + dontneedroot(); +#if defined(sun) || defined(__sun) + fprintf(stderr, "On SunOS/Solaris make sure you have Joerg Schillings usal SCSI driver installed.\n"); +#endif +#if defined (__linux__) + fprintf(stderr, "Use the script scan_scsi.linux to find out more.\n"); +#endif + fprintf(stderr, "Probably you did not define your SCSI device.\n"); + fprintf(stderr, "Set the CDDA_DEVICE environment variable or use the -D option.\n"); + fprintf(stderr, "You can also define the default device in the Makefile.\n"); + fprintf(stderr, "For possible transport specifiers try 'wodim dev=help'.\n"); + exit(SYNTAX_ERROR); + } + usal_settimeout(usalp, 300); + usal_settimeout(usalp, 60); + usalp->silent = global.scsi_silent; + usalp->verbose = global.scsi_verbose; + + if (global.nsectors > (unsigned) usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW) + global.nsectors = usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW; + if (global.overlap >= global.nsectors) + global.overlap = global.nsectors-1; + + /* + * Newer versions of Linux seem to introduce an incompatible change + * and require root privileges or limit RLIMIT_MEMLOCK infinity + * in order to get a SCSI buffer in case we did call mlockall(MCL_FUTURE). + */ + init_scsibuf(usalp, global.nsectors*CD_FRAMESIZE_RAW); + priv_off(); + dontneedgroup(); + dontneedroot(); + + if (global.scandevs) { + list_devices(usalp, stdout, 0); + exit(0); + } + + if (global.scanbus) { + select_target(usalp, stdout); + exit(0); + } + } else { + needgroup(0); + retval = open(pdev_name,O_RDONLY +#ifdef linux + | O_NONBLOCK +#endif + ); + dontneedgroup(); + + if (retval < 0) { + fprintf(stderr, "while opening %s :", pdev_name); + perror(""); + exit(DEVICEOPEN_ERROR); + } + + /* Do final security checks here */ + if (fstat(retval, &fstatstruct)) { + fprintf(stderr, "Could not fstat %s (fd %d): ", pdev_name, retval); + perror(""); + exit(STAT_ERROR); + } + Check_interface_for_device( &fstatstruct, pdev_name ); + +#if defined HAVE_IOCTL_INTERFACE + /* Watch for race conditions */ + if (have_named_device + && (fstatstruct.st_dev != statstruct.st_dev || + fstatstruct.st_ino != statstruct.st_ino)) { + fprintf(stderr,"Race condition attempted in OpenCdRom. Exiting now.\n"); + exit(RACE_ERROR); + } +#endif + /* + * The structure looks like a desaster :-( + * We do this more than once as it is impossible to understand where + * the right place would be to do this.... + */ + if (usalp != NULL) { + usalp->verbose = global.scsi_verbose; + } + } + return retval; +} +#endif /* SIM_CD */ + +/******************* Simulation interface *****************/ +#if defined SIM_CD +#include "toc.h" +static unsigned long sim_pos=0; + +/* read 'SectorBurst' adjacent sectors of audio sectors + * to Buffer '*p' beginning at sector 'lSector' + */ +static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + unsigned int loop=0; + Int16_t *q = (Int16_t *) p; + int joffset = 0; + + if (lSector > g_toc[cdtracks].dwStartSector || lSector + SectorBurstVal > g_toc[cdtracks].dwStartSector + 1) { + fprintf(stderr, "Read request out of bounds: %u - %u (%d - %d allowed)\n", + lSector, lSector + SectorBurstVal, 0, g_toc[cdtracks].dwStartSector); + } +#if 0 + /* jitter with a probability of jprob */ + if (random() <= jprob) { + /* jitter up to jmax samples */ + joffset = random(); + } +#endif + +#ifdef DEBUG_SHM + fprintf(stderr, ", last_b = %p\n", *last_buffer); +#endif + for (loop = lSector*CD_FRAMESAMPLES + joffset; + loop < (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; + loop++) { + *q++ = loop; + *q++ = ~loop; + } +#ifdef DEBUG_SHM + fprintf(stderr, "sim wrote from %p upto %p - 4 (%d), last_b = %p\n", + p, q, SectorBurstVal*CD_FRAMESAMPLES, *last_buffer); +#endif + sim_pos = (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; + return SectorBurstVal; +} + +static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors); +static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors) +{ + sim_pos = from_sector*CD_FRAMESAMPLES; + return 0; +} + +static unsigned sim_indices; + + +/* read the table of contents (toc) via the ioctl interface */ +static unsigned ReadToc_sim(SCSI *x, TOC *toc); +static unsigned ReadToc_sim(SCSI *x, TOC *toc) +{ + unsigned int scenario; + int scen[12][3] = { + {1,1,500}, + {1,2,500}, + {1,99,150*99}, + {2,1,500}, + {2,2,500}, + {2,99,150*99}, + {2,1,500}, + {5,2,500}, + {5,99,150*99}, + {99,1,1000}, + {99,2,1000}, + {99,99,150*99}, + }; + unsigned int i; + unsigned trcks; +#if 0 + fprintf(stderr, "select one of the following TOCs\n" + "0 : 1 track with 1 index\n" + "1 : 1 track with 2 indices\n" + "2 : 1 track with 99 indices\n" + "3 : 2 tracks with 1 index each\n" + "4 : 2 tracks with 2 indices each\n" + "5 : 2 tracks with 99 indices each\n" + "6 : 2 tracks (data and audio) with 1 index each\n" + "7 : 5 tracks with 2 indices each\n" + "8 : 5 tracks with 99 indices each\n" + "9 : 99 tracks with 1 index each\n" + "10: 99 tracks with 2 indices each\n" + "11: 99 tracks with 99 indices each\n" + ); + + do { + scanf("%u", &scenario); + } while (scenario > sizeof(scen)/2/sizeof(int)); +#else + scenario = 6; +#endif + /* build table of contents */ + +#if 0 + trcks = scen[scenario][0] + 1; + sim_indices = scen[scenario][1]; + + for (i = 0; i < trcks; i++) { + toc[i].bFlags = (scenario == 6 && i == 0) ? 0x40 : 0xb1; + toc[i].bTrack = i + 1; + toc[i].dwStartSector = i * scen[scenario][2]; + toc[i].mins = (toc[i].dwStartSector+150) / (60*75); + toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60); + toc[i].frms = (toc[i].dwStartSector+150) % (75); + } + toc[i].bTrack = 0xaa; + toc[i].dwStartSector = i * scen[scenario][2]; + toc[i].mins = (toc[i].dwStartSector+150) / (60*75); + toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60); + toc[i].frms = (toc[i].dwStartSector+150) % (75); +#else + { + int starts[15] = { 23625, 30115, 39050, 51777, 67507, + 88612, 112962, 116840, 143387, 162662, + 173990, 186427, 188077, 209757, 257120}; + trcks = 14 + 1; + sim_indices = 1; + + for (i = 0; i < trcks; i++) { + toc[i].bFlags = 0x0; + toc[i].bTrack = i + 1; + toc[i].dwStartSector = starts[i]; + toc[i].mins = (starts[i]+150) / (60*75); + toc[i].secs = (starts[i]+150 / 75) % (60); + toc[i].frms = (starts[i]+150) % (75); + } + toc[i].bTrack = 0xaa; + toc[i].dwStartSector = starts[i]; + toc[i].mins = (starts[i]) / (60*75); + toc[i].secs = (starts[i] / 75) % (60); + toc[i].frms = (starts[i]) % (75); + } +#endif + return --trcks; /* without lead-out */ +} + + +static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, + unsigned char track); +/* request sub-q-channel information. This function may cause confusion + * for a drive, when called in the sampling process. + */ +static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, + unsigned char track) +{ + subq_chnl *SQp = (subq_chnl *) (SubQbuffer); + subq_position *SQPp = (subq_position *) &SQp->data; + unsigned long sim_pos1; + unsigned long sim_pos2; + + if ( sq_format != GET_POSITIONDATA ) return NULL; /* not supported by sim */ + + /* simulate CDROMSUBCHNL ioctl */ + + /* copy to SubQbuffer */ + SQp->audio_status = 0; + SQp->format = 0xff; + SQp->control_adr = 0xff; + sim_pos1 = sim_pos/CD_FRAMESAMPLES; + sim_pos2 = sim_pos1 % 150; + SQp->track = (sim_pos1 / 5000) + 1; + SQp->index = ((sim_pos1 / 150) % sim_indices) + 1; + sim_pos1 += 150; + SQPp->abs_min = sim_pos1 / (75*60); + SQPp->abs_sec = (sim_pos1 / 75) % 60; + SQPp->abs_frame = sim_pos1 % 75; + SQPp->trel_min = sim_pos2 / (75*60); + SQPp->trel_sec = (sim_pos2 / 75) % 60; + SQPp->trel_frame = sim_pos2 % 75; + + return (subq_chnl *)(SubQbuffer); +} + +static void SelectSpeed_sim(SCSI *x, unsigned sp); +/* ARGSUSED */ +static void SelectSpeed_sim(SCSI *x, unsigned sp) +{ +} + +static void trash_cache_sim(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); + +/* ARGSUSED */ +static void trash_cache_sim(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ +} + +static void SetupSimCd(void); + +static void SetupSimCd() +{ + EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy; + ReadCdRom = ReadCdRom_sim; + ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadCdRom_sim; + doReadToc = ReadToc_sim; + ReadTocText = NULL; + ReadSubQ = ReadSubQ_sim; + ReadSubChannels = NULL; + ReadLastAudio = NULL; + SelectSpeed = SelectSpeed_sim; + Play_at = Play_at_sim; + StopPlay = (int (*)(SCSI *))Dummy; + trash_cache = trash_cache_sim; + +} + +#endif /* def SIM_CD */ + +/* perform initialization depending on the interface used. */ +void SetupInterface() +{ +#if defined SIM_CD + fprintf( stderr, "SIMULATION MODE !!!!!!!!!!!\n"); +#else + /* ensure interface is setup correctly */ + global.cooked_fd = OpenCdRom ( global.dev_name ); +#endif + + global.pagesize = getpagesize(); + + /* request one sector for table of contents */ + bufferTOC = malloc( CD_FRAMESIZE_RAW + 96 ); /* assumes sufficient aligned addresses */ + /* SubQchannel buffer */ + SubQbuffer = malloc( 48 ); /* assumes sufficient aligned addresses */ + cmd = malloc( 18 ); /* assumes sufficient aligned addresses */ + if ( !bufferTOC || !SubQbuffer || !cmd ) { + fprintf( stderr, "Too low on memory. Giving up.\n"); + exit(NOMEM_ERROR); + } + +#if defined SIM_CD + usalp = malloc(sizeof(* usalp)); + if (usalp == NULL) { + FatalError("No memory for SCSI structure.\n"); + } + usalp->silent = 0; + SetupSimCd(); +#else + /* if drive is of type scsi, get vendor name */ + if (interface == GENERIC_SCSI) { + unsigned sector_size; + + SetupSCSI(); + sector_size = get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11); + if (!SCSI_emulated_ATAPI_on(usalp)) { + if ( sector_size != 2048 && set_sectorsize(usalp, 2048) ) { + fprintf( stderr, "Could not change sector size from %d to 2048\n", sector_size ); + } + } else { + sector_size = 2048; + } + + /* get cache setting */ + + /* set cache to zero */ + + } else { +#if defined (HAVE_IOCTL_INTERFACE) + usalp = malloc(sizeof(* usalp)); + if (usalp == NULL) { + FatalError("No memory for SCSI structure.\n"); + } + usalp->silent = 0; + SetupCookedIoctl( global.dev_name ); +#else + FatalError("Sorry, there is no known method to access the device.\n"); +#endif + } +#endif /* if def SIM_CD */ + /* + * The structure looks like a desaster :-( + * We do this more than once as it is impossible to understand where + * the right place would be to do this.... + */ + if (usalp != NULL) { + usalp->verbose = global.scsi_verbose; + } +} + +#ifdef HAVE_PRIV_H +#include <priv.h> +#endif + +void +priv_init() +{ +#ifdef HAVE_PRIV_SET + /* + * Give up privs we do not need anymore. + * We no longer need: + * file_dac_read,sys_devices,proc_priocntl,net_privaddr + */ + priv_set(PRIV_OFF, PRIV_EFFECTIVE, + PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, + PRIV_NET_PRIVADDR, NULL); + priv_set(PRIV_OFF, PRIV_INHERITABLE, + PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, + PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL); +#endif +} + +void +priv_on() +{ +#ifdef HAVE_PRIV_SET + /* + * Get back privs we may need now. + * We need: + * file_dac_read,sys_devices,proc_priocntl,net_privaddr + */ + priv_set(PRIV_ON, PRIV_EFFECTIVE, + PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, + PRIV_NET_PRIVADDR, NULL); +#endif +} + +void +priv_off() +{ +#ifdef HAVE_PRIV_SET + /* + * Give up privs we do not need anymore. + * We no longer need: + * file_dac_read,sys_devices,proc_priocntl,net_privaddr + */ + priv_set(PRIV_OFF, PRIV_EFFECTIVE, + PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, + PRIV_NET_PRIVADDR, NULL); +#endif +} diff --git a/icedax/interface.h b/icedax/interface.h new file mode 100644 index 0000000..b285b71 --- /dev/null +++ b/icedax/interface.h @@ -0,0 +1,135 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)interface.h 1.14 06/02/19 Copyright 1998-2001 Heiko Eissfeldt, Copyright 2005-2006 J. Schilling */ + +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * header file interface.h for cdda2wav */ + +#ifndef CD_FRAMESIZE +#define CD_FRAMESIZE 2048 +#endif + +#ifndef CD_FRAMESIZE_RAW +#define CD_FRAMESIZE_RAW 2352 +#endif + +#define CD_FRAMESAMPLES (CD_FRAMESIZE_RAW / 4) + +extern unsigned interface; + +extern int trackindex_disp; +#ifndef NSECTORS +#define NSECTORS 75 +#endif + +/* interface types */ +#define GENERIC_SCSI 0 +#define COOKED_IOCTL 1 + +/* constants for sub-q-channel info */ +#define GET_ALL 0 +#define GET_POSITIONDATA 1 +#define GET_CATALOGNUMBER 2 +#define GET_TRACK_ISRC 3 + +typedef struct subq_chnl { + unsigned char reserved; + unsigned char audio_status; + unsigned short subq_length; + unsigned char format; + unsigned char control_adr; + unsigned char track; + unsigned char index; + unsigned char data[40]; /* this has subq_all, subq_position, + subq_catalog or subq_track_isrc format */ +} subq_chnl; + +typedef struct subq_all { + unsigned char abs_min; + unsigned char abs_sec; + unsigned char abs_frame; + unsigned char abs_reserved; + unsigned char trel_min; + unsigned char trel_sec; + unsigned char trel_frame; + unsigned char trel_reserved; + unsigned char mc_valid; /* MSB */ + unsigned char media_catalog_number[13]; + unsigned char zero; + unsigned char aframe; + unsigned char tc_valid; /* MSB */ + unsigned char track_ISRC[15]; +} subq_all; + +typedef struct subq_position { + unsigned char abs_reserved; + unsigned char abs_min; + unsigned char abs_sec; + unsigned char abs_frame; + unsigned char trel_reserved; + unsigned char trel_min; + unsigned char trel_sec; + unsigned char trel_frame; +} subq_position; + +typedef struct subq_catalog { + unsigned char mc_valid; /* MSB */ + unsigned char media_catalog_number[13]; + unsigned char zero; + unsigned char aframe; +} subq_catalog; + +typedef struct subq_track_isrc { + unsigned char tc_valid; /* MSB */ + unsigned char track_isrc[15]; +} subq_track_isrc; + +#if !defined NO_SCSI_STUFF + +struct TOC; + +/* cdrom access function pointer */ +extern void (*EnableCdda)(SCSI *usalp, int Switch, unsigned uSectorsize); +extern unsigned (*doReadToc)(SCSI *usalp); +extern void (*ReadTocText)(SCSI *usalp); +extern unsigned (*ReadLastAudio)(SCSI *usalp); +extern int (*ReadCdRom)(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +extern int (*ReadCdRomSub)(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +extern int (*ReadCdRomData)(SCSI *usalp, unsigned char *p, unsigned lSector, + unsigned SectorBurstVal); +extern subq_chnl *(*ReadSubQ)(SCSI *usalp, unsigned char sq_format, + unsigned char track); +extern subq_chnl *(*ReadSubChannels)(SCSI *usalp, unsigned lSector); +extern void (*SelectSpeed)(SCSI *usalp, unsigned speed); +extern int (*Play_at)(SCSI *usalp, unsigned from_sector, unsigned sectors); +extern int (*StopPlay)(SCSI *usalp); +extern void (*trash_cache)(UINT4 *p, unsigned lSector, unsigned SectorBurstVal); + +SCSI *get_scsi_p(void); +#endif + +extern unsigned char *bufferTOC; +extern subq_chnl *SubQbuffer; + + +void SetupInterface(void); +int Toshiba3401(void); + +void priv_init(void); +void priv_on(void); +void priv_off(void); diff --git a/icedax/ioctl.c b/icedax/ioctl.c new file mode 100644 index 0000000..c3bd627 --- /dev/null +++ b/icedax/ioctl.c @@ -0,0 +1,578 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)ioctl.c 1.22 06/02/19 Copyright 1998,1999,2000 Heiko Eissfeldt, Copyright 2006 J. Schilling */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) 1999 Heiko Eissfeldt heiko@colossus.escape.de + * + * Ioctl interface module for cdrom drive access + * + * Solaris ATAPI cdrom drives are untested! + * + */ +#include "config.h" +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <strdefs.h> +#include <errno.h> +#include <signal.h> +#include <fctldefs.h> +#include <assert.h> + +#include <sys/ioctl.h> +#include <statdefs.h> +#include <schily.h> +#include <device.h> + +#include <usal/scsitransp.h> + +#include "mycdrom.h" +#include "lowlevel.h" +/* some include file locations have changed with newer kernels */ +#if defined (__linux__) +# if LINUX_VERSION_CODE > 0x10300 + 97 +# if LINUX_VERSION_CODE < 0x200ff +# include <linux/sbpcd.h> +# include <linux/ucdrom.h> +# endif +# if !defined(CDROM_SELECT_SPEED) +# include <linux/ucdrom.h> +# endif +# endif +#endif + +#include "mytype.h" +#include "byteorder.h" +#include "interface.h" +#include "toc.h" +#include "icedax.h" +#include "ioctl.h" +#include "global.h" +#include "exitcodes.h" + +#include <utypes.h> +#include <wodim.h> + +#if defined (HAVE_IOCTL_INTERFACE) +#if !defined(sun) && !defined(__sun) && !(defined(__FreeBSD__) && (__FreeBSD_version >= 501112)) +static struct cdrom_read_audio arg; +#endif + +#if (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +static unsigned sector_size; +#endif + +static int err; + +static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize); +/* ARGSUSED */ +static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize) +{ +#if (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + if (usalp && usalp->verbose) + fprintf(stderr, "EnableCdda_cooked (CDRIOCSETBLOCKSIZE)...\n"); + + if (fAudioMode) { + if (ioctl(global.cooked_fd, CDRIOCGETBLOCKSIZE, §or_size) ==-1) + sector_size = CD_FRAMESIZE; + ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &uSectorsize); + } else + ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, §or_size); +#else +#if defined CDIOCSETCDDA + if (usalp && usalp->verbose) { + fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA)...\n"); + if (uSectorsize != CD_FRAMESIZE_RAW) + fprintf(stderr, "non audio sector size is ignored.\n"); + } + + ioctl(global.cooked_fd, CDIOCSETCDDA, &fAudioMode); +#else + fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA) is not available...\n"); +#endif +#endif + +} + + +static unsigned ReadToc_cooked(SCSI *x); + +/* read the table of contents (toc) via the ioctl interface */ +static unsigned ReadToc_cooked(SCSI *x) +{ + unsigned i; + unsigned tracks; + struct cdrom_tochdr hdr; + struct cdrom_tocentry entry[100]; + struct cdrom_tocentry entryMSF[100]; + + if (x && x->verbose) { + fprintf(stderr, "ReadToc_cooked (CDROMREADTOCHDR)...\n"); + } + + /* get TocHeader to find out how many entries there are */ + err = ioctl( global.cooked_fd, CDROMREADTOCHDR, &hdr ); + if ( err != 0 ) { + /* error handling */ + if (err == -1) { + if (errno == EPERM) + fprintf( stderr, "Please run this program setuid root.\n"); + perror("cooked: Read TOC "); + exit( DEVICE_ERROR ); + } else { + fprintf( stderr, "can't get TocHeader (error %d).\n", err ); + exit( MEDIA_ERROR ); + } + } + /* get all TocEntries */ + for ( i = 0; i < hdr.cdth_trk1; i++ ) { + entryMSF[i].cdte_track = 1+i; + entryMSF[i].cdte_format = CDROM_MSF; + err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] ); + if ( err != 0 ) { + /* error handling */ + fprintf( stderr, "can't get TocEntry #%d msf (error %d).\n", i+1, err ); + exit( MEDIA_ERROR ); + } + } + entryMSF[i].cdte_track = CDROM_LEADOUT; + entryMSF[i].cdte_format = CDROM_MSF; + err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] ); + if ( err != 0 ) { + /* error handling */ + fprintf( stderr, "can't get TocEntry LEADOUT msf (error %d).\n", err ); + exit( MEDIA_ERROR ); + } + tracks = hdr.cdth_trk1+1; +/* + for (i = 0; i < tracks; i++) { + toc[i].bFlags = (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f); + toc[i].bTrack = entry[i].cdte_track; + toc[i].mins = entry[i].cdte_addr.msf.minute; + toc[i].secs = entry[i].cdte_addr.msf.second; + toc[i].frms = entry[i].cdte_addr.msf.frame; + } +*/ + /* get all TocEntries now in lba format */ + for ( i = 0; i < hdr.cdth_trk1; i++ ) { + entry[i].cdte_track = 1+i; + entry[i].cdte_format = CDROM_LBA; + err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] ); + if ( err != 0 ) { + /* error handling */ + fprintf( stderr, "can't get TocEntry #%d lba (error %d).\n", i+1, err ); + exit( MEDIA_ERROR ); + } +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba); +#endif + } + entry[i].cdte_track = CDROM_LEADOUT; + entry[i].cdte_format = CDROM_LBA; + err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] ); + if ( err != 0 ) { + /* error handling */ + fprintf( stderr, "can't get TocEntry LEADOUT lba (error %d).\n", err ); + exit( MEDIA_ERROR ); + } +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba); +#endif + + for (i = 0; i < tracks; i++) { + toc_entry(i+1, + (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f), + entry[i].cdte_track, + NULL /* ISRC */, + entry[i].cdte_addr.lba, + entryMSF[i].cdte_addr.msf.minute, + entryMSF[i].cdte_addr.msf.second, + entryMSF[i].cdte_addr.msf.frame); + } + bufferTOC[0] = '\0'; + bufferTOC[1] = '\0'; + return --tracks; /* without lead-out */ +} + +static void trash_cache_cooked(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); + +static void trash_cache_cooked(UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + /* trash the cache */ + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD__) && __FreeBSD_version >= 501112 + pread(global.cooked_fd, (void *) &p[0], 3*CD_FRAMESIZE_RAW, + find_an_off_sector(lSector, SectorBurstVal)*CD_FRAMESIZE_RAW); +#else + static struct cdrom_read_audio arg2; + + arg2.address.lba = find_an_off_sector(lSector, SectorBurstVal); + arg2.addr_format = CDROM_LBA; + arg2.nframes = 3; + arg2.buffer = (unsigned char *) &p[0]; + + ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2); +#endif +#endif +#if defined __linux__ + static struct cdrom_read_audio arg2; + + arg2.addr.lba = find_an_off_sector(lSector, SectorBurstVal); + arg2.addr_format = CDROM_LBA; + arg2.nframes = 3; + arg2.buf = (unsigned char *) &p[0]; + + ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2); +#endif +#if defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE) + struct cdrom_cdda suncdda; + + suncdda.cdda_addr = lSector; + suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW; + suncdda.cdda_data = (char *) &p[0]; + suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE; + + ioctl(global.cooked_fd, CDROMCDDA, &suncdda); +#endif +} + +static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +/* read 'SectorBurst' adjacent sectors of data sectors + * to Buffer '*p' beginning at sector 'lSector' + */ +static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + int retval; + + if (x && x->verbose) { + fprintf(stderr, "ReadCdRomData_cooked (lseek & read)...\n"); + } + + if ((retval = lseek(global.cooked_fd, lSector*CD_FRAMESIZE, SEEK_SET)) + != (int)lSector*CD_FRAMESIZE) { perror("cannot seek sector"); } + if ((retval = read(global.cooked_fd, p, SectorBurstVal*CD_FRAMESIZE)) + != (int)SectorBurstVal*CD_FRAMESIZE) { perror("cannot read sector"); } + + return; +} + +static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +/* read 'SectorBurst' adjacent sectors of audio sectors + * to Buffer '*p' beginning at sector 'lSector' + */ +static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + int retry_count=0; + static int nothing_read = 1; + +/* read 2352 bytes audio data */ +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD__) && __FreeBSD_version >= 501112 + if (x && x->verbose) { + fprintf(stderr, "ReadCdRom_cooked (pread)...\n"); + } + + do { + err = 0; + if (pread(global.cooked_fd, (void *) &p[0], SectorBurstVal*CD_FRAMESIZE_RAW, + lSector*CD_FRAMESIZE_RAW) == -1) + err = -1; +#else + arg.address.lba = lSector; + arg.addr_format = CDROM_LBA; + arg.nframes = SectorBurstVal; + arg.buffer = (unsigned char *) &p[0]; + + if (x && x->verbose) { + fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n"); + } + + do { + err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg); +#endif +#endif +#if defined __linux__ + arg.addr.lba = lSector; + arg.addr_format = CDROM_LBA; + arg.nframes = SectorBurstVal; + arg.buf = (unsigned char *) &p[0]; + + if (x && x->verbose) { + fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n"); + } + + do { + err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg); +#endif +#if defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE) + struct cdrom_cdda suncdda; + + suncdda.cdda_addr = lSector; + suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW; + suncdda.cdda_data = (char *) &p[0]; + suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE; + + if (x && x->verbose) { + fprintf(stderr, "ReadCdRom_cooked (CDROMCDDA)...\n"); + } + + do { + err = ioctl(global.cooked_fd, CDROMCDDA, &suncdda); +#endif + retry_count++; + + if (err) { + trash_cache_cooked(p, lSector, SectorBurstVal); + } + + } while ((err) && (retry_count < 30)); + if (err != 0) { + if (x->silent == 0) { + /* error handling */ + if (err == -1) { + if (nothing_read && (errno == EINVAL || errno == EIO)) + fprintf( stderr, "Sorry, this driver and/or drive does not support cdda reading.\n"); + perror("cooked: Read cdda "); + fprintf(stderr, " sector %u + %u, buffer %p + %x\n", lSector, SectorBurstVal, p, global.shmsize); + } else { + fprintf(stderr, "can't read frame #%u (error %d).\n", + lSector, err); + } + } + return SectorBurstVal - 1; + } else { + nothing_read = 0; + } + + return SectorBurstVal; +} + +static int StopPlay_cooked(SCSI *x); +static int StopPlay_cooked(SCSI *x) +{ + if (x && x->verbose) { + fprintf(stderr, "StopPlay_cooked (CDROMSTOP)...\n"); + } + + return ioctl( global.cooked_fd, CDROMSTOP, 0 ) ? 0 : -1; +} + +static int Play_at_cooked(SCSI *x, unsigned int from_sector, + unsigned int sectors); +static int Play_at_cooked(SCSI *x, unsigned int from_sector, + unsigned int sectors) +{ + struct cdrom_msf cmsf; + int retval; + + if (x && x->verbose) { + fprintf(stderr, "Play_at_cooked (CDROMSTART & CDROMPLAYMSF)... (%u-%u)", + from_sector, from_sector+sectors-1); + + fprintf(stderr, "\n"); + } + + cmsf.cdmsf_min0 = (from_sector + 150) / (60*75); + cmsf.cdmsf_sec0 = ((from_sector + 150) / 75) % 60; + cmsf.cdmsf_frame0 = (from_sector + 150) % 75; + cmsf.cdmsf_min1 = (from_sector + 150 + sectors) / (60*75); + cmsf.cdmsf_sec1 = ((from_sector + 150 + sectors) / 75) % 60; + cmsf.cdmsf_frame1 = (from_sector + 150 + sectors) % 75; + +#if 0 +/* makes index scanning under FreeBSD too slow */ + if (( retval = ioctl( global.cooked_fd, CDROMSTART, 0 )) != 0){ + perror(""); + } +#endif + if (( retval = ioctl( global.cooked_fd, CDROMPLAYMSF, &cmsf )) != 0){ + perror(""); + } + return retval; +} + +/* request sub-q-channel information. This function may cause confusion + * for a drive, when called in the sampling process. + */ +static subq_chnl *ReadSubQ_cooked(SCSI *x, unsigned char sq_format, + unsigned char track) +{ + struct cdrom_subchnl sub_ch; + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + struct cd_sub_channel_info sub_ch_info; + + if (x && x->verbose) { + fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n"); + } + + sub_ch.address_format = CD_MSF_FORMAT; + sub_ch.track = track; + sub_ch.data_len = sizeof(struct cd_sub_channel_info); + sub_ch.data = &sub_ch_info; + + switch (sq_format) { + case GET_CATALOGNUMBER: + sub_ch.data_format = CD_MEDIA_CATALOG; +#else + if (x && x->verbose) { + fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n"); + } + + switch (sq_format) { + case GET_CATALOGNUMBER: +#endif +#if defined CDROM_GET_MCN + if (!(err = ioctl(global.cooked_fd, CDROM_GET_MCN, (struct cdrom_mcn *) SubQbuffer))) { + subq_chnl *SQp = (subq_chnl *) SubQbuffer; + subq_catalog *SQPp = (subq_catalog *) &SQp->data; + + memmove(SQPp->media_catalog_number, SQp, sizeof (SQPp->media_catalog_number)); + SQPp->zero = 0; + SQPp->mc_valid = 0x80; + break; + } else +#endif + { + return NULL; + } + case GET_POSITIONDATA: +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + sub_ch.data_format = CD_CURRENT_POSITION; +#endif +#if defined (__linux__) + sub_ch.cdsc_format = CDROM_MSF; +#endif + if (!(err = ioctl(global.cooked_fd, CDROMSUBCHNL, &sub_ch))) { + /* copy to SubQbuffer */ + subq_chnl *SQp = (subq_chnl *) (SubQbuffer); + subq_position *SQPp = (subq_position *) SQp->data; + SQp->audio_status = sub_ch.cdsc_audiostatus; + SQp->format = sub_ch.cdsc_format; + SQp->control_adr = (sub_ch.cdsc_adr << 4) | (sub_ch.cdsc_ctrl & 0x0f); + SQp->track = sub_ch.cdsc_trk; + SQp->index = sub_ch.cdsc_ind; + SQPp->abs_min = sub_ch.cdsc_absaddr.msf.minute; + SQPp->abs_sec = sub_ch.cdsc_absaddr.msf.second; + SQPp->abs_frame = sub_ch.cdsc_absaddr.msf.frame; + SQPp->trel_min = sub_ch.cdsc_reladdr.msf.minute; + SQPp->trel_sec = sub_ch.cdsc_reladdr.msf.second; + SQPp->trel_frame = sub_ch.cdsc_reladdr.msf.frame; + } else { + if (err == -1) { + if (errno == EPERM) + fprintf( stderr, "Please run this program setuid root.\n"); + perror("cooked: Read subq "); + exit( DEVICE_ERROR ); + } else { + fprintf(stderr, "can't read sub q channel (error %d).\n", err); + exit( DEVICE_ERROR ); + } + } + break; + default: + return NULL; + } /* switch */ + return (subq_chnl *)(SubQbuffer); +} + +/* Speed control */ +static void SpeedSelect_cooked(SCSI *x, unsigned speed); +/* ARGSUSED */ +static void SpeedSelect_cooked(SCSI *x, unsigned speed) +{ + if (x && x->verbose) { + fprintf(stderr, "SpeedSelect_cooked (CDROM_SELECT_SPEED)...\n"); + } + +#ifdef CDROM_SELECT_SPEED + /* CAUTION!!!!! Non standard ioctl parameter types here!!!! */ + if ((err = ioctl(global.cooked_fd, CDROM_SELECT_SPEED, speed))) { + if (err == -1) { + if (errno == EPERM) + fprintf( stderr, "Please run this program setuid root.\n"); + perror("cooked: Speed select "); + /*exit( err ); */ + } else { + fprintf(stderr, "can't set speed %d (error %d).\n", speed, err); + exit( DEVICE_ERROR ); + } + } +#endif +} + +/* set function pointers to use the ioctl routines */ +void SetupCookedIoctl(char *pdev_name) +{ +#if (HAVE_ST_RDEV == 1) + struct stat statstruct; + + if (fstat(global.cooked_fd, &statstruct)) { + fprintf(stderr, "cannot stat cd %d (%s)\n",global.cooked_fd, pdev_name); + exit(STAT_ERROR); + } +#if defined __linux__ + switch (major(statstruct.st_rdev)) { + case CDU31A_CDROM_MAJOR: /* sony cdu-31a/33a */ + global.nsectors = 13; + if (global.nsectors >= 14) { + global.overlap = 10; + } + break; + case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */ + case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */ + case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */ + case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */ + /* some are more compatible than others */ + global.nsectors = 13; + break; + default: + global.nsectors = 8; + break; + } + err = ioctl(global.cooked_fd, CDROMAUDIOBUFSIZ, global.nsectors); + + switch (major(statstruct.st_rdev)) { + case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */ + case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */ + case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */ + case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */ + if (err == -1) { + perror("ioctl(CDROMAUDIOBUFSIZ)"); + } + } +#endif +#endif + EnableCdda = EnableCdda_cooked; + ReadCdRom = ReadCdRom_cooked; + ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned)) ReadCdRomData_cooked; + doReadToc = ReadToc_cooked; + ReadTocText = NULL; + ReadSubQ = ReadSubQ_cooked; + ReadSubChannels = NULL; + SelectSpeed = SpeedSelect_cooked; + Play_at = Play_at_cooked; + StopPlay = StopPlay_cooked; + trash_cache = trash_cache_cooked; + ReadLastAudio = NULL; +} +#endif diff --git a/icedax/ioctl.h b/icedax/ioctl.h new file mode 100644 index 0000000..0fc4e92 --- /dev/null +++ b/icedax/ioctl.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)ioctl.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +void SetupCookedIoctl(char *pdev_name); diff --git a/icedax/lconfig.h b/icedax/lconfig.h new file mode 100644 index 0000000..07326c8 --- /dev/null +++ b/icedax/lconfig.h @@ -0,0 +1,85 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* lconfig.h. Generated automatically by configure. */ +#if 0 +/* @(#)lconfig.h.in 1.5 03/09/04 Copyright 1998-2003 Heiko Eissfeldt */ +#endif +/* #undef HAVE_SYS_CDIO_H */ /* if we should use sys/cdio.h */ + +/* #undef HAVE_SUNDEV_SRREG_H */ /* if we should use sundev/srreg.h */ + +/* #undef HAVE_SYS_AUDIOIO_H */ /* if we should use sys/audioio.h */ + +/* #undef HAVE_SUN_AUDIOIO_H */ /* if we should use sun/audioio.h */ + +/* #undef HAVE_SOUNDCARD_H */ /* if we should use soundcard.h */ + +/* TESTED BY CMAKE */ +/*#define HAVE_SYS_SOUNDCARD_H 1 if we should use sys/soundcard.h */ +/*define HAVE_LINUX_SOUNDCARD_H 1 if we should use linux/soundcard.h */ + +/* #undef HAVE_MACHINE_SOUNDCARD_H */ /* if we should use machine/soundcard.h */ + +/* #undef HAVE_SYS_ASOUNDLIB_H */ /* if we should use sys/asoundlib.h */ + +/* #undef HAVE_WINDOWS_H */ /* if we should use windows.h */ + +/* #undef HAVE_MMSYSTEM_H */ /* if we should use mmsystem.h */ + +/* #undef HAVE_OS2_H */ /* if we should use os2.h */ + +/* #undef HAVE_OS2ME_H */ /* if we should use os2me.h */ + +#if defined HAVE_SOUNDCARD_H || defined HAVE_SYS_SOUNDCARD_H || defined HAVE_LINUX_SOUNDCARD_H || defined HAVE_MACHINE_SOUNDCARD_H +#define HAVE_OSS 1 +#endif + +/* +#if defined HAVE_WINDOWS_H && defined HAVE_MMSYSTEM_H +#define HAVE_WINSOUND 1 +#endif + +#if defined HAVE_OS2_H && defined HAVE_OS2ME_H +#define HAVE_OS2SOUND 1 +#endif +*/ + +#define HAVE_STRTOUL 1 + + +/* EB, some defaults, fixme + */ + +#define CD_DEVICE "/dev/cdrom" +#define FILENAME "audio" +#define UNDERSAMPLING 1 +#define VERSION CDRKIT_VERSION +#define BITS_P_S 16 +#define CHANNELS 2 +#define AUDIOTYPE "wav" +#define DURATION 0 +#define DEF_INTERFACE "generic_scsi" +#define USE_PARANOIA 1 +#define DEFAULT_SPEED 0 +#define CDINDEX_SUPPORT +#define CDDB_SUPPORT +#define CDDBHOST "freedb.freedb.org" +#define CDDBPORT 8880 +#define HAVE_IOCTL_INTERFACE +#define ECHO_TO_SOUNDCARD +#define SOUND_DEV "/dev/dsp" +#define NSECTORS 75 +#define INFOFILES +/* #undef MD5_SIGNATURES */ /* not implemented */ +#define AUX_DEVICE "/dev/cdrom" + diff --git a/icedax/lconfig.h.in b/icedax/lconfig.h.in new file mode 100644 index 0000000..9ef9230 --- /dev/null +++ b/icedax/lconfig.h.in @@ -0,0 +1,44 @@ +#if 0 +/* @(#)lconfig.h.in 1.6 06/02/15 Copyright 1998-2003 Heiko Eissfeldt */ +#endif +#undef HAVE_SYS_CDIO_H /* if we should use sys/cdio.h */ + +#undef HAVE_SYS_CDRIO_H /* if we should use sys/cdrio.h */ + +#undef HAVE_SUNDEV_SRREG_H /* if we should use sundev/srreg.h */ + +#undef HAVE_SYS_AUDIOIO_H /* if we should use sys/audioio.h */ + +#undef HAVE_SUN_AUDIOIO_H /* if we should use sun/audioio.h */ + +#undef HAVE_SOUNDCARD_H /* if we should use soundcard.h */ + +#undef HAVE_SYS_SOUNDCARD_H /* if we should use sys/soundcard.h */ + +#undef HAVE_LINUX_SOUNDCARD_H /* if we should use linux/soundcard.h */ + +#undef HAVE_MACHINE_SOUNDCARD_H /* if we should use machine/soundcard.h */ + +#undef HAVE_SYS_ASOUNDLIB_H /* if we should use sys/asoundlib.h */ + +#undef HAVE_WINDOWS_H /* if we should use windows.h */ + +#undef HAVE_MMSYSTEM_H /* if we should use mmsystem.h */ + +#undef HAVE_OS2_H /* if we should use os2.h */ + +#undef HAVE_OS2ME_H /* if we should use os2me.h */ + +#if defined HAVE_SOUNDCARD_H || defined HAVE_SYS_SOUNDCARD_H || defined HAVE_LINUX_SOUNDCARD_H || defined HAVE_MACHINE_SOUNDCARD_H +#define HAVE_OSS 1 +#endif + +#if defined HAVE_WINDOWS_H && defined HAVE_MMSYSTEM_H +#define HAVE_WINSOUND 1 +#endif + +#if defined HAVE_OS2_H && defined HAVE_OS2ME_H +#define HAVE_OS2SOUND 1 +#endif + +#undef HAVE_STRTOUL diff --git a/icedax/list_audio_tracks.1 b/icedax/list_audio_tracks.1 new file mode 100644 index 0000000..b4a1dd0 --- /dev/null +++ b/icedax/list_audio_tracks.1 @@ -0,0 +1,54 @@ +.TH "LIST_AUDIO_TRACKS" "1" "Tue Feb 15 13:03:51 MST 2005" "" "list_audio_tracks" + +.PP +.SH "NAME" +list_audio_tracks is an alias for icedax. +.PP +.SH "SYNOPSIS" +.PP +\fBlist_audio-tracks\fP +.PP +.SH "DESCRIPTION" +.PP +\fBlist_audio_tracks\fP equals to the invocation of icedax, so all the +arguments for the latter can be used. +.PP +.SH SEE ALSO +icedax(1) +.PP +.SH "AUTHOR" +.PP +\fBicedax\fP was written by Heiko Eissfeldt and others. +.PP +This manpage describes the program implementation of +.B +list_audio_tracks +as shipped by the cdrkit distribution. See +.B +http://alioth.debian.org/projects/debburn/ +for details. It is a spinoff from the original program called cdda2wav +distributed by the cdrtools project. However, the cdrtools developers are not +involved in the development of this spinoff and therefore shall not be made +responsible for any problem caused by it. Do not try to get support for this +program by contacting the original authors. +.PP +If you have support questions, send them to +.PP +.B +debburn-devel@lists.alioth.debian.org +.br +.PP +If you have definitely found a bug, send a mail to this list or to +.PP +.B +submit@bugs.debian.org +.br +.PP +writing at least a short description into the Subject and "Package: cdrkit" into the first line of the mail body. +.PP +This manual page was written by Oleksandr Moskalenko +<malex@tagancha\&.org>, for +the Debian GNU/Linux system\&. It may be used by other distributions +without contacting the author\&. Any mistakes or omissions in the +manual page are my fault; inquiries about or corrections to this +manual page should be directed to me (and not to the primary author)\&. diff --git a/icedax/local.cnf.in b/icedax/local.cnf.in new file mode 100644 index 0000000..5c126a7 --- /dev/null +++ b/icedax/local.cnf.in @@ -0,0 +1,141 @@ +# @(#)local.cnf.in 1.6 03/09/04 Copyright 1998-2002 Heiko Eissfeldt +# +# Makefile for cdda2wav, a sampling utility. +# + +# ############ interface +# choose one of the following interfacing and device types. +# generic_scsi is for scsi cdrom devices. +# uncomment one INTERFACE and one DEF_DEVICE line +# (for details consult the README) +INTERFACE='"generic_scsi"' +#INTERFACE='"cooked_ioctl"' + +# set the default cdrom device +SUN_OS_DEFAULT_DEV= '"0,6,0"' +YOUR_DEFAULT_DEV= '"yourSCSI_Bus,yourSCSI_ID,yourSCSI_LUN"' + +_DEF_DEVICE= $(_UNIQ)$(HAVE_SUN_OS) +__DEF_DEVICE= $(_DEF_DEVICE:$(_UNIQ)=$(YOUR_DEFAULT_DEV)) +DEF_DEVICE= $(__DEF_DEVICE:$(_UNIQ)$(HAVE_SUN_OS)=$(SUN_OS_DEFAULT_DEV)) + +# optional matching device used for a MULTISESSION ioctl +LINUX_AUX_DEV= '"/dev/cdrom"' + +_AUX_DEVICE= $(_UNIQ)$(HAVE_LINUX) +__AUX_DEVICE= $(_AUX_DEVICE:$(_UNIQ)='""') +AUX_DEVICE= $(__AUX_DEVICE:$(_UNIQ)$(HAVE_LINUX)=$(LINUX_AUX_DEV)) + +# number of sectors to request +# under BSD better use < 128 K of shared memory +SECTORS=75 +BSD_SECTORS=27 + +_SECTORS= $(_UNIQ)$(HAVE_BSD_OS) +__SECTORS= $(_SECTORS:$(_UNIQ)=$(SECTORS)) +NSECTORS= $(__SECTORS:$(_UNIQ)$(HAVE_BSD_OS)=$(BSD_SECTORS)) + +# some architectures can use the ioctl() interface cooked_ioctl +HAVE_SUN_IOCTL= @HAVE_SUN_IOCTL@ +_HAVE_IOCTL= $(_UNIQ)$(HAVE_BSD_OS)$(HAVE_SUN_IOCTL)$(HAVE_LINUX) +__HAVE_IOCTL= $(_HAVE_IOCTL:$(_UNIQ)=) +HAVE_IOCTL= $(__HAVE_IOCTL:$(_UNIQ)$(HAVE_BSD_OS)$(HAVE_SUN_IOCTL)$(HAVE_LINUX)=-DHAVE_IOCTL_INTERFACE) + +############# Sound device support +#to disable sound support comment out the corresponding line with HAVE_SOUND +OSS_SOUND_DEV= '"/dev/dsp"' +SUN_SOUND_DEV= '"/dev/audio"' + +HAVE_OSS= @HAVE_OSS@ +HAVE_SUNSOUND= @HAVE_SUNSOUND@ +HAVE_WINSOUND= @HAVE_WINSOUND@ +HAVE_OS2SOUND= @HAVE_OS2SOUND@ +HAVE_QNXSOUND= @HAVE_SYS_ASOUNDLIB_H@ +#_HAVE_SOUND= $(_UNIQ)$(HAVE_OSS)$(HAVE_SUNSOUND) +_HAVE_SOUND= $(_UNIQ)$(HAVE_OSS)$(HAVE_SUNSOUND)$(HAVE_WINSOUND)$(HAVE_OS2SOUND)$(HAVE_QNXSOUND) +__HAVE_SOUND= $(_HAVE_SOUND:$(_UNIQ)=) +#HAVE_SOUND= $(__HAVE_SOUND:$(_UNIQ)$(HAVE_OSS)$(HAVE_SUNSOUND)=-DECHO_TO_SOUNDCARD) +HAVE_SOUND= $(__HAVE_SOUND:$(_UNIQ)$(HAVE_OSS)$(HAVE_SUNSOUND)$(HAVE_WINSOUND)$(HAVE_OS2SOUND)$(HAVE_QNXSOUND)=-DECHO_TO_SOUNDCARD) + +_SOUND_DEVICE= $(_UNIQ)$(HAVE_OSS)$(HAVE_SOUND)$(HAVE_SUNSOUND) +__SOUND_DEVICE= $(_SOUND_DEVICE:$(_UNIQ)='""') +___SOUND_DEVICE= $(__SOUND_DEVICE:$(_UNIQ)$(HAVE_OSS)$(HAVE_SOUND)=$(OSS_SOUND_DEV)) +____SOUND_DEVICE= $(___SOUND_DEVICE:$(_UNIQ)$(HAVE_SOUND)$(HAVE_SUNSOUND)=$(SUN_SOUND_DEV)) +SOUND_DEVICE= $(____SOUND_DEVICE:$(_UNIQ)$(HAVE_OSS)$(HAVE_SOUND)$(HAVE_SUNSOUND)=$(OSS_SOUND_DEV)) + +_EXTRALIB= $(_UNIQ)$(HAVE_WINSOUND)$(HAVE_OS2SOUND)$(HAVE_QNXSOUND) +__EXTRALIB= $(_EXTRALIB:$(_UNIQ)=@EXTRALIBS@) +___EXTRALIB= $(__EXTRALIB:$(_UNIQ)$(HAVE_WINSOUND)=@EXTRALIBS@ -lwinmm) +____EXTRALIB= $(___EXTRALIB:$(_UNIQ)$(HAVE_QNXSOUND)=@EXTRALIBS@ -lasound) +EXTRALIB= $(____EXTRALIB:$(_UNIQ)$(HAVE_OS2SOUND)=@EXTRALIBS@ -los2me) + +############# sound file defaults +# Defaults for wav/au/cdr output file formats +# default divider for 44.1 KHz +DEF_UNDERSAMPLING=1 + +# 16, 12 or 8 bits per sample +DEF_BITS=16 +# 1 = mono, 2 = stereo +DEF_CHANNELS=2 + +DEF_TIME=0 # number of seconds to record + +DEF_SPEED=0 # default reading speed +#DEF_SPEED=0xFFFF # default reading speed + +############## output file types: wav, aiff, aifc, sun au or cdr ########### +# enable one DEF_TYPE and one DEF_FILE +# first are for wav sound files, second are for sun au pcm sound files, +# third are for headerless sound files (raw samples in bigendian format) +# default audio file type + +_DEF_TYPE= $(_UNIQ)$(HAVE_SUN_OS) +__DEF_TYPE= $(_DEF_TYPE:$(_UNIQ)='"wav"') +DEF_TYPE= $(__DEF_TYPE:$(_UNIQ)$(HAVE_SUN_OS)='"au"') +#DEF_TYPE= "wav" +#DEF_TYPE= "au" +#DEF_TYPE= "cdr" +#DEF_TYPE= "aiff" +#DEF_TYPE= "aifc" + +# default file name for sound file +DEF_FILE='"audio"' + +############## enable/disable info files #################################### +# Info files contain date/time, track, recording time, ISRC, optional MD5 +# signature and more, each item in one line. These files are generated one +# per track. +# Comment out if you don't want this. +WANT_INFOFILES=-DINFOFILES + +############## enable/disable MD5 signatures in info files ################## +# Comment out if you don't want this. +WANT_MD5=-DMD5_SIGNATURES +MD5OBJECTS=md5c.o + +# CDINDEX server support +# Comment out if you don't want a disk description file for the cdindex server +WANT_CDINDEX_SUPPORT=-DCDINDEX_SUPPORT + +# CDDB server support +# Comment out if you don't want a network access to the cddb server +WANT_CDDB_SUPPORT=-DCDDB_SUPPORT +CDDB_SERVERHOST='"freedb.freedb.org"' +CDDB_SERVERPORT=8880 + +# end of tunable parameters +# +CDDA2WAVDEFS=-DCD_DEVICE=$(DEF_DEVICE) -DFILENAME=$(DEF_FILE) \ +-DUNDERSAMPLING=$(DEF_UNDERSAMPLING) -DVERSION=$(CUR_VERSION) \ +-DBITS_P_S=$(DEF_BITS) -DCHANNELS=$(DEF_CHANNELS) -DAUDIOTYPE=$(DEF_TYPE) \ +-DDURATION=$(DEF_TIME) -DDEF_INTERFACE=$(INTERFACE) -DUSE_PARANOIA=1 \ +-DDEFAULT_SPEED=$(DEF_SPEED) $(WANT_CDINDEX_SUPPORT) $(WANT_CDDB_SUPPORT) \ +-DCDDBHOST=$(CDDB_SERVERHOST) -DCDDBPORT=$(CDDB_SERVERPORT) $(HAVE_IOCTL) \ +$(HAVE_SOUND) -DSOUND_DEV=$(SOUND_DEVICE) -DNSECTORS=$(NSECTORS) \ +$(WANT_INFOFILES) $(WANT_MD5) -DAUX_DEVICE=$(AUX_DEVICE) + +LIBS += @LIBS@ + +VERSION_OS=@CDRTOOLS_VERSION@_$(O_ARCH)_$(OSREL)_$(K_ARCH)_$(P_ARCH) +CUR_VERSION='"$(VERSION_OS)"' diff --git a/icedax/lowlevel.h b/icedax/lowlevel.h new file mode 100644 index 0000000..084ef34 --- /dev/null +++ b/icedax/lowlevel.h @@ -0,0 +1,25 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)lowlevel.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +/* os dependent functions */ + +#ifndef LOWLEVEL +# define LOWLEVEL 1 + +# if defined(__linux__) +# include <linux/version.h> +# include <linux/major.h> + +# endif /* defined __linux__ */ + +#endif /* ifndef LOWLEVEL */ diff --git a/icedax/mycdrom.h b/icedax/mycdrom.h new file mode 100644 index 0000000..1819321 --- /dev/null +++ b/icedax/mycdrom.h @@ -0,0 +1,150 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)mycdrom.h 1.10 06/05/07 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2005-2006 J. Schilling */ +#if defined(__linux__) +# include <linux/cdrom.h> +#else +# if defined HAVE_SYS_CDIO_H +# include <sys/cdio.h> +# if defined(__FreeBSD__) && __FreeBSD__ >= 2 +# include <osreldate.h> +# endif +# if defined HAVE_SYS_CDRIO_H /* Was: if __FreeBSD_version >= 400014 */ +# include <sys/cdrio.h> +# endif + +# if (defined (__sun) && defined (SVR4)) +# if 0 +/* just for info */ +/* Sun has this cdda reading ioctl: CDROMCDDA */ +/* + * Definition of CD-DA structure + */ +struct cdrom_cdda { + unsigned int cdda_addr; + unsigned int cdda_length; + caddr_t cdda_data; + unsigned char cdda_subcode; +}; +/* +To get the subcode information related to CD-DA data, the following values are + appropriate for the cdda_subcode field: + +CDROM_DA_NO_SUBCODE +CD-DA data with no subcode. + +CDROM_DA_SUBQ +CD-DA data with sub Q code. + +CDROM_DA_ALL_SUBCODE +CD-DA data with all subcode. + +CDROM_DA_SUBCODE_ONLY +All subcode only. + +To allocate the memory related to CD-DA and/or subcode data, the following + values are appropriate for each data block transferred: + +CD-DA data with no subcode +2352 bytes + +CD-DA data with sub Q code +2368 bytes + +CD-DA data with all subcode +2448 bytes + +All subcode only +96 bytes +*/ + +# endif /* if 0 */ +# else /* not Sun SVR4 */ +# if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __DragonFly__ || defined __OpenBSD__ +# if (defined(__FreeBSD__) && __FreeBSD_version < 228000) || !defined(CDIOCREADAUDIO) + /* + * FreeBSD_version >= 501112 has no CDIOCREADAUDIO but uses pread() + */ +# if !(defined(__FreeBSD__) && __FreeBSD_version >= 501112) +# undef HAVE_IOCTL_INTERFACE +# endif +# endif /* __FreeBSD_version < 228000 || !CDIOCREADAUDIO */ + +#ifdef HAVE_IOCTL_INTERFACE + +#define CDROM_LBA CD_LBA_FORMAT +#define CDROM_MSF CD_MSF_FORMAT +#define CDROM_DATA_TRACK 0x04 +#define CDROM_LEADOUT 0xAA + +#define CDROMSTOP CDIOCSTOP +#define CDROMSTART CDIOCSTART +#define CDROMREADTOCHDR CDIOREADTOCHEADER +#define CDROMREADTOCENTRY CDIOREADTOCENTRY +#define CDROMPLAYMSF CDIOCPLAYMSF +#define CDROMREADAUDIO CDIOCREADAUDIO +#define CDROM_GET_MCN CDIOCREADSUBCHANNEL +#define CDROMSUBCHNL CDIOCREADSUBCHANNEL + +#ifndef CDIOREADTOCENTRY +#define CDIOREADTOCENTRY CDIOREADTOCENTRYS +#endif + +#define cdrom_tochdr ioc_toc_header +#define cdth_trk0 starting_track +#define cdth_trk1 ending_track + +#define cdrom_tocentry ioc_read_toc_single_entry +#define cdte_track track +#define cdte_format address_format +#define cdte_adr entry.addr_type +#define cdte_ctrl entry.control +#define cdte_addr entry.addr + +#define cdrom_read_audio ioc_read_audio +#define addr_format address_format +#define buff buffer + +#define cdrom_msf ioc_play_msf +#define cdmsf_min0 start_m +#define cdmsf_sec0 start_s +#define cdmsf_frame0 start_f +#define cdmsf_min1 end_m +#define cdmsf_sec1 end_s +#define cdmsf_frame1 end_f + +#define cdrom_subchnl ioc_read_subchannel +#define cdsc_audiostatus data->header.audio_status +#define cdsc_format data->what.position.data_format +#define cdsc_adr data->what.position.addr_type +#define cdsc_ctrl data->what.position.control +#define cdsc_trk data->what.position.track_number +#define cdsc_ind data->what.position.index_number +#define cdsc_absaddr data->what.position.absaddr +#define cdsc_reladdr data->what.position.reladdr +# endif /* HAVE_IOCTL_INTERFACE */ +# else /* not *BSD */ +# undef HAVE_IOCTL_INTERFACE +# endif /* not *BSD */ +# endif /* not SUN SVR4 */ +# else /* HAVE_SYS_CDIO_H */ +# if defined HAVE_SUNDEV_SRREG_H +# include <sundev/srreg.h> +# if !defined CDROMCDDA +# undef HAVE_IOCTL_INTERFACE +# endif +# else +# undef HAVE_IOCTL_INTERFACE +# endif +# endif /* not HAVE_SYS_CDIO_H */ +#endif /* not linux */ diff --git a/icedax/mytype.h b/icedax/mytype.h new file mode 100644 index 0000000..189f1c9 --- /dev/null +++ b/icedax/mytype.h @@ -0,0 +1,39 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)mytype.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +#if 4 == SIZEOF_LONG_INT +#define UINT4 long unsigned int +#define UINT4_C ULONG_C +#else +#if 4 == SIZEOF_INT +#define UINT4 unsigned int +#define UINT4_C UINT_C +#else +#if 4 == SIZEOF_SHORT_INT +#define UINT4 short unsigned int +#define UINT4_C USHORT_C +#else +error need an integer type with 32 bits, but do not know one! +#endif +#endif +#endif +#define TRUE 1 +#define FALSE 0 + +#ifndef offset_of +#define offset_of(TYPE, MEMBER) ((size_t) ((TYPE *)0)->MEMBER) +#endif +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + diff --git a/icedax/pitchplay b/icedax/pitchplay new file mode 100755 index 0000000..a9f3dc2 --- /dev/null +++ b/icedax/pitchplay @@ -0,0 +1,39 @@ +#! /bin/sh +# +# Script to play audio tracks with different pitches +# through a soundcard (cdda2wav must have soundcard +# support enabled). +# +# Pitches are specified in percentage with 100% being +# the original pitch, 50% being one octave lower, 200% +# one octave higher. +# +# based on a script from Raul Sobon, who created the pitch +# feature. Thanks Raul. +# +# usage: pitchplay <track a> <pitch a> <track b> <pitch b> ... +# +# example: pitchplay 1 90 3 140 5 50 +# will play track 1 with a pitch of 90%, +# track 3 with a pitch of 140%, and +# track 5 with a pitch of 50%. +# +CDDA2WAV=icedax +#CDDA2WAVOPTS="-qeNP0 -n75" +CDDA2WAVOPTS="-qeNP0 -n40" + +if [ $(( $# % 2 )) -eq 0 ]; then + while [ $# -ge 2 ]; do + echo playing track $1 with a pitch of $2% + $CDDA2WAV $CDDA2WAVOPTS -t $1 -p $2 + RES=$? + if [ $RES -ne 0 ]; then + echo "$CDDA2WAV error, return value "$RES". Aborted." >&2 + break + fi + shift 2 + done +else + echo "usage: $0 [<Tracknr> <Pitch>] ..." >&2 +fi + diff --git a/icedax/pitchplay.1 b/icedax/pitchplay.1 new file mode 100644 index 0000000..dee13ea --- /dev/null +++ b/icedax/pitchplay.1 @@ -0,0 +1,59 @@ +.TH "PITCHPLAY" "1" "Tue Feb 15 12:53:23 MST 2005" "" "pitchplay" + +.PP +.SH "NAME" +pitchplay \- wrapper script to play audio tracks with cdda2wav with different +pitches through a soundcard (cdda2wav must have soundcard support enabled). +.PP +.SH "SYNOPSIS" +.PP +\fBpitchplay\fP <track a> <pitch a> <track b> <pitch b>... +.PP +.SH "DESCRIPTION" +.PP +\fBpitchplay\fP allows playback of audio tracks with cdda2wav with pitches +specified in percentage with 100% being the original pitch, 50% being one +octave lower, 200% one octave higher. +.PP +.SH "EXAMPLES" +.PP +\fBpitchplay\fP 1 90 3 140 5 50 +.br +will play track 1 with a pitch of 90%, track 3 with a pitch of 140%, and track 5 with a pitch of 50%. +.PP +.SH SEE ALSO +cdda2wav(1) +.PP +.SH "AUTHOR" +.PP +\fBcdda2was\fP was written by Joerg Schilling <js@cs\&.tu-berlin\&.de> and +others. +.PP +This manpage describes the program implementation of +.B +pitchplay +as shipped by the cdrkit distribution. See +.B +http://alioth.debian.org/projects/debburn/ +for details. It is a spinoff from the original program distributed by the cdrtools project. However, the cdrtools developers are not involved in the development of this spinoff and therefore shall not be made responsible for any problem caused by it. Do not try to get support for this program by contacting the original authors. +.PP +If you have support questions, send them to +.PP +.B +debburn-devel@lists.alioth.debian.org +.br +.PP +If you have definitely found a bug, send a mail to this list or to +.PP +.B +submit@bugs.debian.org +.br +.PP +writing at least a short description into the Subject and "Package: cdrkit" into the first line of the mail body. +.PP +This manual page was written by Oleksandr Moskalenko +<malex@tagancha\&.org>, for +the Debian GNU/Linux system\&. It may be used by other distributions +without contacting the author\&. Any mistakes or omissions in the +manual page are my fault; inquiries about or corrections to this +manual page should be directed to me (and not to the primary author)\&. diff --git a/icedax/raw.c b/icedax/raw.c new file mode 100644 index 0000000..b56841e --- /dev/null +++ b/icedax/raw.c @@ -0,0 +1,61 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)raw.c 1.4 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +#include "config.h" +#include <unixstd.h> +#include "sndfile.h" + +static int InitSound(void); + +static int InitSound() +{ + return 0; +} + +static int ExitSound(void); + +static int ExitSound() +{ + return 0; +} + +static unsigned long GetHdrSize(void); + +static unsigned long GetHdrSize() +{ + return 0L; +} + +static unsigned long InSizeToOutSize(unsigned long BytesToDo); + +static unsigned long InSizeToOutSize(unsigned long BytesToDo) +{ + return BytesToDo; +} + +struct soundfile rawsound = +{ + (int (*)(int audio, long channels, + unsigned long myrate, long nBitsPerSample, + unsigned long expected_bytes)) InitSound, + + (int (*)(int audio, unsigned long nBytesDone)) ExitSound, + + GetHdrSize, + + (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo)) write, /* get sound samples out */ + + InSizeToOutSize, /* compressed? output file size */ + + 1 /* needs big endian samples */ +}; diff --git a/icedax/raw.h b/icedax/raw.h new file mode 100644 index 0000000..2a9ef8b --- /dev/null +++ b/icedax/raw.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)raw.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +extern struct soundfile rawsound; diff --git a/icedax/readmult b/icedax/readmult new file mode 100755 index 0000000..6f0884e --- /dev/null +++ b/icedax/readmult @@ -0,0 +1,31 @@ +#! /bin/sh +# +# Script to read more than 1 song with icedax +# Each file gets an individual name from the command line +# +# based on a perl script from Matthias Schniedermeyer +# +# usage: readmult <track a> <title a> <track b> <title b> ... +# +# example: readmult 1 intro 3 lovesong 5 medley +# will produce a file named intro.wav for track 1, +# a file named lovesong.wav for track 3, and +# a file named medley.wav for track 5. +# +CDDA2WAV=icedax +CDDA2WAVOPTS="-P0" + +if [ $(( $# % 2 )) -eq 0 ]; then + while [ $# -ge 2 ]; do + $CDDA2WAV $CDDA2WAVOPTS -Owav -t $1 $PREFIX$2".wav" + RES=$? + if [ $RES -ne 0 ]; then + echo "$CDDA2WAV error, return value "$RES". Aborted." >&2 + break + fi + shift 2 + done +else + echo "usage: $0 [<Tracknr> <Filename>] ..." >&2 +fi + diff --git a/icedax/readmult.1 b/icedax/readmult.1 new file mode 100644 index 0000000..8801736 --- /dev/null +++ b/icedax/readmult.1 @@ -0,0 +1,52 @@ +.TH "READMULT" "1" "Tue Feb 15 12:34:06 MST 2005" "" "readmult" + +.PP +.SH "NAME" +readmult \- a multitrack wrapper for cdda2wav +.PP +.SH "SYNOPSIS" +.PP +\fBreadmult\fP <track a> <title a> <track b> <title b> ... +.PP +.SH "DESCRIPTION" +.PP +\fBreadmult\fP allows simultaneous extraction and naming of multiple tracks +with cdda2wav +.PP +.SH SEE ALSO +cdda2wav(1) +.PP +.SH "AUTHOR" +.PP +\fBcdda2was\fP was written by Joerg Schilling <js@cs\&.tu-berlin\&.de> and +others. +.PP +This describes the program as shipped with cdrkit, see +This manpage describes the program implementation of +.B +readmult +as shipped by the cdrkit distribution. See +.B +http://alioth.debian.org/projects/debburn/ +for details. It is a spinoff from the original program distributed by the cdrtools project. However, the cdrtools developers are not involved in the development of this spinoff and therefore shall not be made responsible for any problem caused by it. Do not try to get support for this program by contacting the original authors. +.PP +If you have support questions, send them to +.PP +.B +debburn-devel@lists.alioth.debian.org +.br +.PP +If you have definitely found a bug, send a mail to this list or to +.PP +.B +submit@bugs.debian.org +.br +.PP +writing at least a short description into the Subject and "Package: cdrkit" into the first line of the mail body. +.PP +This manual page was written by Oleksandr Moskalenko +<malex@tagancha\&.org>, for +the Debian GNU/Linux system\&. It may be used by other distributions +without contacting the author\&. Any mistakes or omissions in the +manual page are my fault; inquiries about or corrections to this +manual page should be directed to me (and not to the primary author)\&. diff --git a/icedax/resample.c b/icedax/resample.c new file mode 100644 index 0000000..3f5b5d0 --- /dev/null +++ b/icedax/resample.c @@ -0,0 +1,985 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)resample.c 1.15 02/11/21 Copyright 1998,1999,2000 Heiko Eissfeldt */ +/* resampling module + * + * The audio data has been read. Here are the + * functions to ensure a correct continuation + * of the output stream and to convert to a + * lower sample rate. + * + */ + +#undef DEBUG_VOTE_ENDIANESS +#undef DEBUG_SHIFTS /* simulate bad cdrom drives */ +#undef DEBUG_MATCHING +#undef SHOW_JITTER +#undef CHECK_MEM + +#include "config.h" +#include <timedefs.h> +#include <stdio.h> +#include <stdxlib.h> +#include <utypes.h> +#include <unixstd.h> +#include <standard.h> +#include <strdefs.h> +#include <limits.h> +#include <assert.h> +#include <math.h> + +#include <usal/scsitransp.h> + +#include "mytype.h" +#include "icedax.h" +#include "interface.h" +#include "byteorder.h" +#include "ringbuff.h" +#include "resample.h" +#include "toc.h" +#include "sndfile.h" +#include "sndconfig.h" +#include "global.h" +#include "exitcodes.h" + + +int waitforsignal = 0; /* flag: wait for any audio response */ +int any_signal = 0; + +short undersampling; /* conversion factor */ +short samples_to_do; /* loop variable for conversion */ +int Halved; /* interpolate due to non integral divider */ + +static long lsum = 0, rsum = 0; /* accumulator for left/right channel */ +static long ls2 = 0, rs2 = 0, ls3 = 0, rs3 = 0, auxl = 0, auxr = 0; + +static const unsigned char *my_symmemmem(const unsigned char *HAYSTACK, + const size_t HAYSTACK_LEN, + const unsigned char *const NEEDLE, + const size_t NEEDLE_LEN); +static const unsigned char *my_memmem(const unsigned char *HAYSTACK, + const size_t HAYSTACK_LEN, + const unsigned char *const NEEDLE, + const size_t NEEDLE_LEN); +static const unsigned char *my_memrmem(const unsigned char *HAYSTACK, + const size_t HAYSTACK_LEN, + const unsigned char *const NEEDLE, + const size_t NEEDLE_LEN); +static const unsigned char *sync_buffers(const unsigned char *const newbuf); +static long interpolate(long p1, long p2, long p3); +static void emit_sample(long lsumval, long rsumval, long channels); +static void change_endianness(UINT4 *pSam, unsigned int Samples); +static void swap_channels(UINT4 *pSam, unsigned int Samples); +static int guess_endianess(UINT4 *p, Int16_t *p2, unsigned int SamplesToDo); + + +#ifdef CHECK_MEM +static void check_mem(const unsigned char *p, unsigned long amount, + const unsigned char *q, unsigned line, char *file); + +static void check_mem(const unsigned char *p, unsigned long amount, + const unsigned char *q, unsigned line, char *file) +{ + if (p < q || p+amount > q + ENTRY_SIZE) { + fprintf(stderr, "file %s, line %u: invalid buffer range (%p - %p), allowed is (%p - %p)\n", + file,line,p, p+amount-1, q, q + ENTRY_SIZE-1); + exit(INTERNAL_ERROR); + } +} +#endif + + +#ifdef DEBUG_MATCHING +int memcmp(const void * a, const void * b, size_t c) +{ + return 1; +} +#endif + +static const unsigned char * +my_symmemmem(const unsigned char *HAYSTACK, const size_t HAYSTACK_LEN, + const unsigned char * const NEEDLE, const size_t NEEDLE_LEN) +{ + const unsigned char * const UPPER_LIMIT = HAYSTACK + HAYSTACK_LEN - NEEDLE_LEN - 1; + const unsigned char * HAYSTACK2 = HAYSTACK-1; + + while (HAYSTACK <= UPPER_LIMIT) { + if (memcmp(NEEDLE, HAYSTACK, NEEDLE_LEN) == 0) { + return HAYSTACK; + } else { + if (memcmp(NEEDLE, HAYSTACK2, NEEDLE_LEN) == 0) { + return HAYSTACK2; + } + HAYSTACK2--; + HAYSTACK++; + } + } +#ifdef DEBUG_MATCHING + HAYSTACK2++; + HAYSTACK--; + fprintf(stderr, "scompared %p-%p with %p-%p (%p)\n", + NEEDLE, NEEDLE + NEEDLE_LEN-1, + HAYSTACK2, HAYSTACK + NEEDLE_LEN-1, HAYSTACK); +#endif + return NULL; +} + +static const unsigned char * +my_memmem(const unsigned char *HAYSTACK, const size_t HAYSTACK_LEN, + const unsigned char * const NEEDLE, const size_t NEEDLE_LEN) +{ + const unsigned char * const UPPER_LIMIT = HAYSTACK + HAYSTACK_LEN - NEEDLE_LEN; + + while (HAYSTACK <= UPPER_LIMIT) { + if (memcmp(NEEDLE, HAYSTACK, NEEDLE_LEN) == 0) { + return HAYSTACK; + } else { + HAYSTACK++; + } + } +#ifdef DEBUG_MATCHING + HAYSTACK--; + fprintf(stderr, "fcompared %p-%p with %p-%p (%p)\n", + NEEDLE, NEEDLE + NEEDLE_LEN-1, + HAYSTACK - HAYSTACK_LEN + NEEDLE_LEN, HAYSTACK + NEEDLE_LEN-1, + HAYSTACK); +#endif + return NULL; +} + +static const unsigned char * +my_memrmem(const unsigned char *HAYSTACK, const size_t HAYSTACK_LEN, + const unsigned char * const NEEDLE, const size_t NEEDLE_LEN) +{ + const unsigned char * const LOWER_LIMIT = HAYSTACK - (HAYSTACK_LEN - 1); + + while (HAYSTACK >= LOWER_LIMIT) { + if (memcmp(NEEDLE, HAYSTACK, NEEDLE_LEN) == 0) { + return HAYSTACK; + } else { + HAYSTACK--; + } + } +#ifdef DEBUG_MATCHING + HAYSTACK++; + fprintf(stderr, "bcompared %p-%p with %p-%p (%p)\n", + NEEDLE, NEEDLE + NEEDLE_LEN-1, + HAYSTACK, HAYSTACK + (HAYSTACK_LEN - 1), + HAYSTACK + (HAYSTACK_LEN - 1) - NEEDLE_LEN - 1); +#endif + return NULL; +} + +/* find continuation in new buffer */ +static const unsigned char * +sync_buffers(const unsigned char * const newbuf) +{ + const unsigned char *retval = newbuf; + + if (global.overlap != 0) { + /* find position of SYNC_SIZE bytes + of the old buffer in the new buffer */ + size_t haystack_len; + const size_t needle_len = SYNC_SIZE; + const unsigned char * const oldbuf = (const unsigned char *) (get_previous_read_buffer()->data); + const unsigned char * haystack; + const unsigned char * needle; + + /* compare the previous buffer with the new one + * + * 1. symmetrical search: + * look for the last SYNC_SIZE bytes of the previous buffer + * in the new buffer (from the optimum to the outer positions). + * + * 2. if the first approach did not find anything do forward search + * look for the last SYNC_SIZE bytes of the previous buffer + * in the new buffer (from behind the overlap to the end). + * + */ + + haystack_len = min((global.nsectors - global.overlap)*CD_FRAMESIZE_RAW + +SYNC_SIZE+1, + global.overlap*CD_FRAMESIZE_RAW); + /* expected here */ + haystack = newbuf + CD_FRAMESIZE_RAW*global.overlap - SYNC_SIZE; + needle = oldbuf + CD_FRAMESIZE_RAW*global.nsectors - SYNC_SIZE; + +#ifdef DEBUG_MATCHING + fprintf(stderr, "oldbuf %p-%p new %p-%p %u %u %u\n", + oldbuf, oldbuf + CD_FRAMESIZE_RAW*global.nsectors - 1, + newbuf, newbuf + CD_FRAMESIZE_RAW*global.nsectors - 1, + CD_FRAMESIZE_RAW*global.nsectors, global.nsectors, global.overlap); +#endif + + retval = my_symmemmem(haystack, haystack_len, needle, needle_len); + if (retval != NULL) { + retval += SYNC_SIZE; + } else { + /* fallback to asymmetrical search */ + + /* if there is no asymmetrical part left, return with 'not found' */ + if (2*global.overlap == global.nsectors) { + retval = NULL; + } else if (2*global.overlap > global.nsectors) { + /* the asymmetrical part is in front, search backwards */ + haystack_len = (2*global.overlap-global.nsectors)*CD_FRAMESIZE_RAW; + haystack = newbuf + haystack_len - 1; + retval = my_memrmem(haystack, haystack_len, needle, needle_len); + } else { + /* the asymmetrical part is at the end, search forward */ + haystack = newbuf + 2*(global.overlap*CD_FRAMESIZE_RAW - SYNC_SIZE); + haystack_len = (global.nsectors-2*global.overlap)*CD_FRAMESIZE_RAW + 2*SYNC_SIZE; + retval = my_memmem(haystack, haystack_len, needle, needle_len); + } + if (retval != NULL) + retval += SYNC_SIZE; + } + +#ifdef SHOW_JITTER + if (retval) { + fprintf(stderr,"%d\n", + retval-(newbuf+global.overlap*CD_FRAMESIZE_RAW)); + } else { + fprintf(stderr,"no match\n"); + } +#endif + } + + return retval; +} + +/* quadratic interpolation + * p1, p3 span the interval 0 - 2. give interpolated value for 1/2 */ +static long int +interpolate(long int p1, long int p2, long int p3) +{ + return (3L*p1 + 6L*p2 - p3)/8L; +} + +static unsigned char *pStart; /* running ptr defining end of output buffer */ +static unsigned char *pDst; /* start of output buffer */ +/* + * Write the filtered sample into the output buffer. + */ +static void +emit_sample(long lsumval, long rsumval, long channels) +{ + if (global.findminmax) { + if (rsumval > global.maxamp[0]) global.maxamp[0] = rsumval; + if (rsumval < global.minamp[0]) global.minamp[0] = rsumval; + if (lsumval < global.minamp[1]) global.minamp[1] = lsumval; + if (lsumval > global.maxamp[1]) global.maxamp[1] = lsumval; + } + /* convert to output format */ + if ( channels == 1 ) { + Int16_t sum; /* mono section */ + sum = ( lsumval + rsumval ) >> (global.sh_bits + 1); + if ( global.sh_bits == 8 ) { + if ( waitforsignal == 1 ) { + if ( any_signal == 0 ) { + if ( ( (char) sum) != '\0' ) { + pStart = (unsigned char *) pDst; + any_signal = 1; + *pDst++ = ( unsigned char ) sum + ( 1 << 7 ); + } else global.SkippedSamples++; + } else *pDst++ = ( unsigned char ) sum + ( 1 << 7 ); + } else *pDst++ = ( unsigned char ) sum + ( 1 << 7 ); + } else { + Int16_t * myptr = (Int16_t *) pDst; + if ( waitforsignal == 1 ) { + if ( any_signal == 0 ) { + if ( sum != 0 ) { + pStart = (unsigned char *) pDst; + any_signal = 1; + *myptr = sum; pDst += sizeof( Int16_t ); + } else global.SkippedSamples++; + } else { *myptr = sum; pDst += sizeof( Int16_t ); } + } else { *myptr = sum; pDst += sizeof( Int16_t ); } + } + } else { + /* stereo section */ + lsumval >>= global.sh_bits; + rsumval >>= global.sh_bits; + if ( global.sh_bits == 8 ) { + if ( waitforsignal == 1 ) { + if ( any_signal == 0 ) { + if ( ((( char ) lsumval != '\0') || (( char ) rsumval != '\0'))) { + pStart = (unsigned char *) pDst; + any_signal = 1; + *pDst++ = ( unsigned char )( short ) lsumval + ( 1 << 7 ); + *pDst++ = ( unsigned char )( short ) rsumval + ( 1 << 7 ); + } else global.SkippedSamples++; + } else { + *pDst++ = ( unsigned char )( short ) lsumval + ( 1 << 7 ); + *pDst++ = ( unsigned char )( short ) rsumval + ( 1 << 7 ); + } + } else { + *pDst++ = ( unsigned char )( short ) lsumval + ( 1 << 7 ); + *pDst++ = ( unsigned char )( short ) rsumval + ( 1 << 7 ); + } + } else { + Int16_t * myptr = (Int16_t *) pDst; + if ( waitforsignal == 1 ) { + if ( any_signal == 0 ) { + if ( ((( Int16_t ) lsumval != 0) || (( Int16_t ) rsumval != 0))) { + pStart = (unsigned char *) pDst; + any_signal = 1; + *myptr++ = ( Int16_t ) lsumval; + *myptr = ( Int16_t ) rsumval; + pDst += 2*sizeof( Int16_t ); + } else global.SkippedSamples++; + } else { + *myptr++ = ( Int16_t ) lsumval; + *myptr = ( Int16_t ) rsumval; + pDst += 2*sizeof( Int16_t ); + } + } else { + *myptr++ = ( Int16_t ) lsumval; + *myptr = ( Int16_t ) rsumval; + pDst += 2*sizeof( Int16_t ); + } + } + } +} + +static void change_endianness(UINT4 *pSam, unsigned int Samples) +{ + UINT4 *pend = (pSam + Samples); + + /* type UINT4 may not be greater than the assumed biggest type */ +#if (SIZEOF_LONG_INT < 4) +error type unsigned long is too small +#endif + +#if (SIZEOF_LONG_INT == 4) + + unsigned long *plong = (unsigned long *)pSam; + + for (; plong < pend;) { + *plong = ((*plong >> 8L) & UINT_C(0x00ff00ff)) | + ((*plong << 8L) & UINT_C(0xff00ff00)); + plong++; + } +#else /* sizeof long unsigned > 4 bytes */ +#if (SIZEOF_LONG_INT == 8) +#define INTEGRAL_LONGS (SIZEOF_LONG_INT-1UL) + register unsigned long *plong; + unsigned long *pend0 = (unsigned long *) (((unsigned long) pend) & ~ INTEGRAL_LONGS); + + if (((unsigned long) pSam) & INTEGRAL_LONGS) { + *pSam = ((*pSam >> 8L) & UINT_C(0x00ff00ff)) | + ((*pSam << 8L) & UINT_C(0xff00ff00)); + pSam++; + } + + plong = (unsigned long *)pSam; + + for (; plong < pend0;) { + *plong = ((*plong >> 8L) & ULONG_C(0x00ff00ff00ff00ff)) | + ((*plong << 8L) & ULONG_C(0xff00ff00ff00ff00)); + plong++; + } + + if (((unsigned long *) pend) != pend0) { + UINT4 *pint = (UINT4 *) pend0; + + for (;pint < pend;) { + *pint = ((*pint >> 8) & UINT_C(0x00ff00ff)) | + ((*pint << 8) & UINT_C(0xff00ff00)); + pint++; + } + } +#else /* sizeof long unsigned > 4 bytes but not 8 */ + { + UINT4 *pint = pSam; + + for (;pint < pend;) { + *pint = ((*pint >> 8) & UINT_C(0x00ff00ff)) | + ((*pint << 8) & UINT_C(0xff00ff00)); + pint++; + } + } +#endif +#endif +} + +static void swap_channels(UINT4 *pSam, unsigned int Samples) +{ + UINT4 *pend = (pSam + Samples); + + /* type UINT4 may not be greater than the assumed biggest type */ +#if (SIZEOF_LONG_INT < 4) +error type unsigned long is too small +#endif + +#if (SIZEOF_LONG_INT == 4) + + unsigned long *plong = (unsigned long *)pSam; + + for (; plong < pend;) { + *plong = ((*plong >> 16L) & UINT_C(0x0000ffff)) | + ((*plong << 16L) & UINT_C(0xffff0000)); + plong++; + } +#else /* sizeof long unsigned > 4 bytes */ +#if (SIZEOF_LONG_INT == 8) +#define INTEGRAL_LONGS (SIZEOF_LONG_INT-1UL) + register unsigned long *plong; + unsigned long *pend0 = (unsigned long *) (((unsigned long) pend) & ~ INTEGRAL_LONGS); + + if (((unsigned long) pSam) & INTEGRAL_LONGS) { + *pSam = ((*pSam >> 16L) & UINT_C(0x0000ffff)) | + ((*pSam << 16L) & UINT_C(0xffff0000)); + pSam++; + } + + plong = (unsigned long *)pSam; + + for (; plong < pend0;) { + *plong = ((*plong >> 16L) & ULONG_C(0x0000ffff0000ffff)) | + ((*plong << 16L) & ULONG_C(0xffff0000ffff0000)); + plong++; + } + + if (((unsigned long *) pend) != pend0) { + UINT4 *pint = (UINT4 *) pend0; + + for (;pint < pend;) { + *pint = ((*pint >> 16L) & UINT_C(0x0000ffff)) | + ((*pint << 16L) & UINT_C(0xffff0000)); + pint++; + } + } +#else /* sizeof long unsigned > 4 bytes but not 8 */ + { + UINT4 *pint = pSam; + + for (;pint < pend;) { + *pint = ((*pint >> 16L) & UINT_C(0x0000ffff)) | + ((*pint << 16L) & UINT_C(0xffff0000)); + pint++; + } + } +#endif +#endif +} + +#ifdef ECHO_TO_SOUNDCARD +static long ReSampleBuffer(unsigned char *p, unsigned char *newp, + long samples, int samplesize); +static long ReSampleBuffer(unsigned char *p, unsigned char *newp, + long samples, int samplesize) +{ + double idx=0.0; + UINT4 di=0,si=0; + + if (global.playback_rate == 100.0) { + memcpy(newp, p, samplesize* samples); + di = samples; + } else while( si < (UINT4)samples ){ + memcpy( newp+(di*samplesize), p+(si*samplesize), samplesize ); + idx += (double)(global.playback_rate/100.0); + si = (UINT4)idx; + di++; + } + return di*samplesize; +} +#endif + +static int guess_endianess(UINT4 *p, Int16_t *p2, unsigned SamplesToDo) +{ + /* analyse samples */ + int vote_for_little = 0; + int vote_for_big = 0; + int total_votes; + + while (((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) { + unsigned char *p3 = (unsigned char *)p2; +#if MY_LITTLE_ENDIAN == 1 + int diff_lowl = *(p2+0) - *(p2+2); + int diff_lowr = *(p2+1) - *(p2+3); + int diff_bigl = ((*(p3 ) << 8) + *(p3+1)) - ((*(p3+4) << 8) + *(p3+5)); + int diff_bigr = ((*(p3+2) << 8) + *(p3+3)) - ((*(p3+6) << 8) + *(p3+7)); +#else + int diff_lowl = ((*(p3+1) << 8) + *(p3 )) - ((*(p3+5) << 8) + *(p3+4)); + int diff_lowr = ((*(p3+3) << 8) + *(p3+2)) - ((*(p3+7) << 8) + *(p3+6)); + int diff_bigl = *(p2+0) - *(p2+2); + int diff_bigr = *(p2+1) - *(p2+3); +#endif + + if ((abs(diff_lowl) + abs(diff_lowr)) < + (abs(diff_bigl) + abs(diff_bigr))) { + vote_for_little++; + } else { + if ((abs(diff_lowl) + abs(diff_lowr)) > + (abs(diff_bigl) + abs(diff_bigr))) { + vote_for_big++; + } + } + p2 += 2; + } +#ifdef DEBUG_VOTE_ENDIANESS + if (global.quiet != 1) + fprintf(stderr, "votes for little: %4d, votes for big: %4d\n", + vote_for_little, vote_for_big); +#endif + total_votes = vote_for_big + vote_for_little; + if (total_votes < 3 + || abs(vote_for_big - vote_for_little) < total_votes/3) { + return -1; + } else { + if (vote_for_big > vote_for_little) + return 1; + else + return 0; + } +} + +int jitterShift = 0; + +void handle_inputendianess(UINT4 *p, unsigned SamplesToDo) +{ + /* if endianess is unknown, guess endianess based on + differences between succesive samples. If endianess + is correct, the differences are smaller than with the + opposite byte order. + */ + if ((*in_lendian) < 0) { + Int16_t *p2 = (Int16_t *)p; + + /* skip constant samples */ + while ((((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) + && *p2 == *(p2+2)) p2++; + + if (((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) { + switch (guess_endianess(p, p2, SamplesToDo)) { + case -1: break; + case 1: (*in_lendian) = 0; +#if 0 + if (global.quiet != 1) + fprintf(stderr, "big endian detected\n"); +#endif + break; + case 0: (*in_lendian) = 1; +#if 0 + if (global.quiet != 1) + fprintf(stderr, "little endian detected\n"); +#endif + break; + } + } + } + + /* ENDIAN ISSUES: + * the individual endianess of cdrom/cd-writer, cpu, + * sound card and audio output format need a careful treatment. + * + * For possible sample processing (rate conversion) we need + * the samples in cpu byte order. This is the first conversion. + * + * After processing it depends on the endianness of the output + * format, whether a second conversion is needed. + * + */ + + if (global.need_hostorder && (*in_lendian) != MY_LITTLE_ENDIAN) { + /* change endianess of delivered samples to native cpu order */ + change_endianness(p, SamplesToDo); + } +} + +unsigned char * +synchronize(UINT4 *p, unsigned SamplesToDo, unsigned TotSamplesDone) +{ + static int jitter = 0; + char *pSrc; /* start of cdrom buffer */ + + /* synchronisation code */ + if (TotSamplesDone != 0 && global.overlap != 0 && SamplesToDo > CD_FRAMESAMPLES) { + + pSrc = (char *) sync_buffers((unsigned char *)p); + if (!pSrc ) { + return NULL; + } + if (pSrc) { + jitter = ((unsigned char *)pSrc - (((unsigned char *)p) + global.overlap*CD_FRAMESIZE_RAW))/4; + jitterShift += jitter; + SamplesToDo -= jitter + global.overlap*CD_FRAMESAMPLES; +#if 0 + fprintf(stderr, + "Length: pre %d, diff1 %ld, diff2 %ld, min %ld\n", SamplesToDo, + (TotSamplesWanted - TotSamplesDone), + SamplesNeeded((TotSamplesWanted - TotSamplesDone), undersampling), + min(SamplesToDo, SamplesNeeded((TotSamplesWanted - TotSamplesDone), undersampling))); +#endif + } + } else { + pSrc = ( char * ) p; + } + return (unsigned char *) pSrc; +} + +/* convert cdda data to required output format + * sync code for unreliable cdroms included + * + */ +long +SaveBuffer(UINT4 *p, unsigned long SamplesToDo, unsigned long *TotSamplesDone) +{ + UINT4 *pSrc; /* start of cdrom buffer */ + UINT4 *pSrcStop; /* end of cdrom buffer */ + + /* in case of different endianness between host and output format, + or channel swaps, or deemphasizing + copy in a seperate buffer and modify the local copy */ + if ( ((((!global.need_hostorder && global.need_big_endian == (*in_lendian)) || + (global.need_hostorder && global.need_big_endian != MY_BIG_ENDIAN) + ) || (global.deemphasize != 0) + ) && (global.OutSampleSize > 1) + ) || global.swapchannels != 0) { + static UINT4 *localoutputbuffer; + if (localoutputbuffer == NULL) { + localoutputbuffer = malloc(global.nsectors*CD_FRAMESIZE_RAW); + if (localoutputbuffer == NULL) { + perror("cannot allocate local buffer"); + return 1; + } + } + memcpy(localoutputbuffer, p, SamplesToDo*4); + p = localoutputbuffer; + } + + pSrc = p; + pDst = (unsigned char *) p; + pStart = ( unsigned char * ) pSrc; + pSrcStop = pSrc + SamplesToDo; + + /* code for subsampling and output stage */ + + if (global.ismono && global.findmono) { + Int16_t *pmm; + for (pmm = (Int16_t *)pStart; (UINT4 *) pmm < pSrcStop; pmm += 2) { + if (*pmm != *(pmm+1)) { + global.ismono = 0; + break; + } + } + } + /* optimize the case of no conversion */ + if (1 && undersampling == 1 && samples_to_do == 1 && + global.channels == 2 && global.OutSampleSize == 2 && Halved == 0) { + /* output format is the original cdda format -> + * just forward the buffer + */ + + if ( waitforsignal != 0 && any_signal == 0) { + UINT4 *myptr = (UINT4 *)pStart; + while (myptr < pSrcStop && *myptr == 0) myptr++; + pStart = (unsigned char *) myptr; + /* scan for first signal */ + if ( (UINT4 *)pStart != pSrcStop ) { + /* first non null amplitude is found in buffer */ + any_signal = 1; + global.SkippedSamples += ((UINT4 *)pStart - p); + } else { + global.SkippedSamples += (pSrcStop - p); + } + } + pDst = (unsigned char *) pSrcStop; /* set pDst to end */ + + if (global.deemphasize && (Get_Preemphasis(get_current_track())) ) { + /* this implements an attenuation treble shelving filter + to undo the effect of pre-emphasis. The filter is of + a recursive first order */ + static Int16_t lastin[2] = { 0, 0 }; + static double lastout[2] = { 0.0, 0.0 }; + Int16_t *pmm; + + /* Here is the gnuplot file for the frequency response + of the deemphasis. The error is below +-0.1dB + +# first define the ideal filter. We use the tenfold sampling frequency. +T=1./441000. +OmegaU=1./15E-6 +OmegaL=15./50.*OmegaU +V0=OmegaL/OmegaU +H0=V0-1. +B=V0*tan(OmegaU*T/2.) +# the coefficients follow +a1=(B - 1.)/(B + 1.) +b0=(1.0 + (1.0 - a1) * H0/2.) +b1=(a1 + (a1 - 1.0) * H0/2.) +# helper variables +D=b1/b0 +o=2*pi*T +H2(f)=b0*sqrt((1+2*cos(f*o)*D+D*D)/(1+2*cos(f*o)*a1+a1*a1)) +# now approximate the ideal curve with a fitted one for sampling frequency +# of 44100 Hz. +T2=1./44100. +V02=0.3365 +OmegaU2=1./19E-6 +B2=V02*tan(OmegaU2*T2/2.) +# the coefficients follow +a12=(B2 - 1.)/(B2 + 1.) +b02=(1.0 + (1.0 - a12) * (V02-1.)/2.) +b12=(a12 + (a12 - 1.0) * (V02-1.)/2.) +# helper variables +D2=b12/b02 +o2=2*pi*T2 +H(f)=b02*sqrt((1+2*cos(f*o2)*D2+D2*D2)/(1+2*cos(f*o2)*a12+a12*a12)) +# plot best, real, ideal, level with halved attenuation, +# level at full attentuation, 10fold magnified error +set logscale x +set grid xtics ytics mxtics mytics +plot [f=1000:20000] [-12:2] 20*log10(H(f)),20*log10(H2(f)), 20*log10(OmegaL/(2*pi*f)), 0.5*20*log10(V0), 20*log10(V0), 200*log10(H(f)/H2(f)) +pause -1 "Hit return to continue" + */ + +#ifdef TEST +#define V0 0.3365 +#define OMEGAG (1./19e-6) +#define T (1./44100.) +#define H0 (V0-1.) +#define B (V0*tan((OMEGAG * T)/2.0)) +#define a1 ((B - 1.)/(B + 1.)) +#define b0 (1.0 + (1.0 - a1) * H0/2.0) +#define b1 (a1 + (a1 - 1.0) * H0/2.0) +#undef V0 +#undef OMEGAG +#undef T +#undef H0 +#undef B +#else +#define a1 -0.62786881719628784282 +#define b0 0.45995451989513153057 +#define b1 -0.08782333709141937339 +#endif + + for (pmm = (Int16_t *)pStart; pmm < (Int16_t *)pDst;) { + lastout[0] = *pmm * b0 + lastin[0] * b1 - lastout[0] * a1; + lastin[0] = *pmm; + *pmm++ = lastout[0] > 0.0 ? lastout[0] + 0.5 : lastout[0] - 0.5; + lastout[1] = *pmm * b0 + lastin[1] * b1 - lastout[1] * a1; + lastin[1] = *pmm; + *pmm++ = lastout[1] > 0.0 ? lastout[1] + 0.5 : lastout[1] - 0.5; + } +#undef a1 +#undef b0 +#undef b1 + } + + if (global.swapchannels == 1) { + swap_channels((UINT4 *)pStart, SamplesToDo); + } + + if (global.findminmax) { + Int16_t *pmm; + for (pmm = (Int16_t *)pStart; pmm < (Int16_t *)pDst; pmm++) { + if (*pmm < global.minamp[1]) global.minamp[1] = *pmm; + if (*pmm > global.maxamp[1]) global.maxamp[1] = *pmm; + pmm++; + if (*pmm < global.minamp[0]) global.minamp[0] = *pmm; + if (*pmm > global.maxamp[0]) global.maxamp[0] = *pmm; + } + } + } else { + +#define none_missing 0 +#define one_missing 1 +#define two_missing 2 +#define collecting 3 + + static int sample_state = collecting; + static int Toggle_on = 0; + + if (global.channels == 2 && global.swapchannels == 1) { + swap_channels((UINT4 *)pStart, SamplesToDo); + } + + /* conversion required */ + while ( pSrc < pSrcStop ) { + + long l,r; + + long iSamples_left = (pSrcStop - pSrc) / sizeof(Int16_t) / 2; + Int16_t *myptr = (Int16_t *) pSrc; + + /* LSB l, MSB l */ + l = *myptr++; /* left channel */ + r = *myptr++; /* right channel */ + pSrc = (UINT4 *) myptr; + + switch (sample_state) { + case two_missing: +two__missing: + ls2 += l; rs2 += r; + if (undersampling > 1) { + ls3 += l; rs3 += r; + } + sample_state = one_missing; + break; + case one_missing: + auxl = l; auxr = r; + + ls3 += l; rs3 += r; + sample_state = none_missing; + + /* FALLTHROUGH */ +none__missing: + case none_missing: + /* Filtered samples are complete. Now interpolate and scale. */ + + if (Halved != 0 && Toggle_on == 0) { + lsum = interpolate(lsum, ls2, ls3)/(int) undersampling; + rsum = interpolate(rsum, rs2, rs3)/(int) undersampling; + } else { + lsum /= (int) undersampling; + rsum /= (int) undersampling; + } + emit_sample(lsum, rsum, global.channels); + /* reload counter */ + samples_to_do = undersampling - 1; + lsum = auxl; + rsum = auxr; + /* reset sample register */ + auxl = ls2 = ls3 = 0; + auxr = rs2 = rs3 = 0; + Toggle_on ^= 1; + sample_state = collecting; + break; + case collecting: + if ( samples_to_do > 0) { + samples_to_do--; + if (Halved != 0 && Toggle_on == 0) { + /* Divider x.5 : we need data for quadratic interpolation */ + iSamples_left--; + + lsum += l; rsum += r; + if ( samples_to_do < undersampling - 1) { + ls2 += l; rs2 += r; + } + if ( samples_to_do < undersampling - 2) { + ls3 += l; rs3 += r; + } + } else { + /* integral divider */ + lsum += l; + rsum += r; + iSamples_left--; + } + } else { + if (Halved != 0 && Toggle_on == 0) { + sample_state = two_missing; + goto two__missing; + } else { + auxl = l; + auxr = r; + sample_state = none_missing; + goto none__missing; + } + } + break; + } /* switch state */ + + } /* while */ + + /* flush_buffer */ + if ((samples_to_do == 0 && Halved == 0)) + { + if (Halved != 0 && Toggle_on == 0) { + lsum = interpolate(lsum, ls2, ls3)/(int) undersampling; + rsum = interpolate(rsum, rs2, rs3)/(int) undersampling; + } else { + lsum /= (int) undersampling; + rsum /= (int) undersampling; + } + emit_sample(lsum, rsum, global.channels); + + /* reload counter */ + samples_to_do = undersampling; + + /* reset sample register */ + lsum = auxl = ls2 = ls3 = 0; + rsum = auxr = rs2 = rs3 = 0; + Toggle_on ^= 1; + sample_state = collecting; + } + + } /* if optimize else */ + + if ( waitforsignal == 0 ) pStart = (unsigned char *)p; + + if ( waitforsignal == 0 || any_signal != 0) { + int retval = 0; + unsigned outlen; + unsigned todo; + + assert(pDst >= pStart); + outlen = (size_t) (pDst - pStart); + + if (outlen <= 0) return 0; + +#ifdef ECHO_TO_SOUNDCARD + + /* this assumes the soundcard needs samples in native cpu byte order */ + if (global.echo != 0) { + static unsigned char *newp; + unsigned newlen; + + newlen = (100*(outlen/4))/global.playback_rate; + newlen = (newlen*4); + if ( (newp != NULL) || (newp = malloc( 2*global.nsectors*CD_FRAMESIZE_RAW+32 )) ) { + newlen = ReSampleBuffer( pStart, newp, outlen/4, global.OutSampleSize*global.channels ); + write_snd_device((char *)newp, newlen); + } + } +#endif + + if ( global.no_file != 0 ) { + *TotSamplesDone += SamplesToDo; + return 0; + } + if ( (!global.need_hostorder && global.need_big_endian == (*in_lendian)) || + (global.need_hostorder && global.need_big_endian != MY_BIG_ENDIAN)) { + if ( global.OutSampleSize > 1) { + /* change endianness from input sample or native cpu order + to required output endianness */ + change_endianness((UINT4 *)pStart, outlen/4); + } + } + { + unsigned char * p2 = pStart; + + todo = outlen; + while (todo != 0) { + int retval_; + retval_ = global.audio_out->WriteSound ( global.audio, p2, todo ); + if (retval_ < 0) break; + + p2 += retval_; + todo -= retval_; + } + } + if (todo == 0) { + *TotSamplesDone += SamplesToDo; + return 0; + } else { + fprintf(stderr, "write(audio, 0x%p, %u) = %d\n",pStart,outlen,retval); + perror("Probably disk space exhausted"); + return 1; + } + } else { + *TotSamplesDone += SamplesToDo; + return 0; + } +} diff --git a/icedax/resample.h b/icedax/resample.h new file mode 100644 index 0000000..d25216c --- /dev/null +++ b/icedax/resample.h @@ -0,0 +1,26 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)resample.h 1.3 02/08/02 Copyright 1998,1999 Heiko Eissfeldt */ +#define SYNC_SIZE 600 /* has to be smaller than CD_FRAMESAMPLES */ + +extern int waitforsignal; /* flag: wait for any audio response */ +extern int any_signal; + +extern short undersampling; /* conversion factor */ +extern short samples_to_do; /* loop variable for conversion */ +extern int Halved; /* interpolate due to non integral divider */ +extern int jitterShift; /* track accumulated jitter */ +long SaveBuffer(UINT4 *p, unsigned long SecsToDo, unsigned long *BytesDone); +unsigned char *synchronize(UINT4 *p, unsigned SamplesToDo, + unsigned TotSamplesDone); +void handle_inputendianess(UINT4 *p, unsigned SamplesToDo); diff --git a/icedax/ringbuff.c b/icedax/ringbuff.c new file mode 100644 index 0000000..6678ffb --- /dev/null +++ b/icedax/ringbuff.c @@ -0,0 +1,231 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)ringbuff.c 1.8 02/11/21 Copyright 1998,1999,2000 Heiko Eissfeldt */ +#include "config.h" + +#include <stdxlib.h> +#include <stdio.h> +#include <standard.h> +#include <unixstd.h> + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) +#include <sys/ipc.h> +#include <sys/sem.h> +#endif + +#include <usal/scsitransp.h> + +#include "mytype.h" +#include "global.h" +#include "interface.h" +#include "ringbuff.h" +#include "semshm.h" +#include "exitcodes.h" + +#undef WARN_INTERRUPT +#undef _DEBUG +#include <assert.h> + +static void occupy_buffer(void); + +myringbuff **he_fill_buffer; +myringbuff **last_buffer; +volatile unsigned long *total_segments_read; +volatile unsigned long *total_segments_written; +volatile int *child_waits; +volatile int *parent_waits; +volatile int *in_lendian; +volatile int *eorecording; + +static myringbuff *previous_read_buffer; +static unsigned int total_buffers; + +#define SEMS 2 + +#define defined_buffers() ((*total_segments_read) - (*total_segments_written)) +#define free_buffers() (total_buffers - defined_buffers()) +#define occupied_buffers() (defined_buffers()) + +/* ARGSUSED */ +void set_total_buffers(unsigned int num_buffers, int mysem_id) +{ +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) + union my_semun mysemun; + + mysemun.val = 0; + if (semctl(mysem_id,(int) DEF_SEM,SETVAL,mysemun) < 0) { + perror("semctl DEF_SEM"); + } + + mysemun.val = num_buffers; + if (semctl(mysem_id,(int) FREE_SEM,SETVAL,mysemun) < 0) { + perror("semctl FREE_SEM"); + } +#endif + + total_buffers = num_buffers; + + /* initialize pointers */ + *he_fill_buffer = *last_buffer = previous_read_buffer = NULL; +#ifdef DEBUG_SHM +fprintf(stderr, "init: fill_b = %p, last_b = %p\n", *he_fill_buffer, *last_buffer); +#endif +} + +const myringbuff *get_previous_read_buffer() +{ + assert(previous_read_buffer != NULL); + assert(previous_read_buffer != *he_fill_buffer); + return previous_read_buffer; +} + +const myringbuff *get_he_fill_buffer() +{ + assert(*he_fill_buffer != NULL); + assert(previous_read_buffer != *he_fill_buffer); + return *he_fill_buffer; +} + +void define_buffer() +{ + assert(defined_buffers() < total_buffers); + +#ifdef _DEBUG +#if 0 + fprintf(stderr,"stop reading %p - %p\n", + *he_fill_buffer, (char *)(*he_fill_buffer) + ENTRY_SIZE -1); +#endif +#endif + + if (*last_buffer == NULL) + *last_buffer = *he_fill_buffer; +#ifdef DEBUG_SHM +fprintf(stderr, "define: fill_b = %p, last_b = %p\n", *he_fill_buffer, *last_buffer); +#endif + + (*total_segments_read)++; + semrelease(sem_id,DEF_SEM,1); +} + +void drop_buffer() +{ + assert(free_buffers() < total_buffers); + assert(occupied_buffers() > 0); + +#ifdef _DEBUG +#if 0 + fprintf(stderr," stop writing %p - %p ", + *last_buffer, (char *)(*last_buffer) + ENTRY_SIZE -1); +#endif +#endif + + if (*last_buffer == NULL) + *last_buffer = *he_fill_buffer; + else + *last_buffer = INC(*last_buffer); +#ifdef DEBUG_SHM +fprintf(stderr, "drop: fill_b = %p, last_b = %p\n", *he_fill_buffer, *last_buffer); +#endif + (*total_segments_written)++; + semrelease(sem_id,FREE_SEM, 1); +} + +void drop_all_buffers() +{ + (*total_segments_written) = (*total_segments_read); + semrelease(sem_id,FREE_SEM, total_buffers); +} + +static void occupy_buffer() +{ + assert(occupied_buffers() <= total_buffers); + + previous_read_buffer = *he_fill_buffer; + + if (*he_fill_buffer == NULL) { + *he_fill_buffer = RB_BASE; + } else { + *he_fill_buffer = INC(*he_fill_buffer); + } +} + +#if defined HAVE_FORK_AND_SHAREDMEM +myringbuff * get_next_buffer() +{ +#ifdef WARN_INTERRUPT + if (free_buffers() <= 0) { + fprintf(stderr, "READER waits!! r=%lu, w=%lu\n", *total_segments_read, +*total_segments_written); + } +#endif + + /* wait for a new buffer to become available */ + if (semrequest(sem_id,FREE_SEM) != 0) { + /* semaphore operation failed. + try again... + */ + fprintf(stderr, "child reader sem request failed\n"); + exit(SEMAPHORE_ERROR); + } +#if 0 + fprintf(stderr,"start reading %p - %p\n", + *he_fill_buffer, (char *)(*fill_buffer) + ENTRY_SIZE -1); +#endif + + occupy_buffer(); + +#ifdef DEBUG_SHM +fprintf(stderr, "next: fill_b = %p, last_b = %p, @last = %p\n", *he_fill_buffer, *last_buffer, last_buffer); +#endif + return *he_fill_buffer; +} + +myringbuff *get_oldest_buffer() +{ + myringbuff *retval; + +#ifdef WARN_INTERRUPT + if (free_buffers() == total_buffers) { + fprintf(stderr, "WRITER waits!! r=%lu, w=%lu\n", *total_segments_read, + *total_segments_written); + } +#endif + /* wait for buffer to be defined */ + if (semrequest(sem_id,DEF_SEM) != 0) { + /* semaphore operation failed. */ + perror("request defined buff:"); + fprintf(stderr, "parent writer sem request failed\n"); + } + + retval = *last_buffer; + +#if 0 + fprintf(stderr," begin writing %p - %p\n", + retval, (char *)retval + ENTRY_SIZE -1); +#endif + + return retval; +} +#else /* HAVE_FORK_AND_SHAREDMEM */ +myringbuff * get_next_buffer() +{ + occupy_buffer(); + return *he_fill_buffer; +} + +myringbuff * get_oldest_buffer() +{ + return *he_fill_buffer; +} +#endif /* HAVE_FORK_AND_SHAREDMEM */ + diff --git a/icedax/ringbuff.h b/icedax/ringbuff.h new file mode 100644 index 0000000..6c85b3a --- /dev/null +++ b/icedax/ringbuff.h @@ -0,0 +1,97 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)ringbuff.h 1.5 01/10/20 Copyright 1998,1999,2000 Heiko Eissfeldt */ +/* This file contains data structures that reside in the shared memory + * segment. + */ + + +/* the linux semctl prototype is broken as is the definition + of union semun in sys/sem.h. */ + +#ifdef HAVE_UNION_SEMUN +# define my_semun semun +#else +union my_semun { + int val; + struct semid_ds *pid; + unsigned short *array; +}; +#endif + +/* Ringbuffer structures. + Space for the ringbuffer is allocated page aligned + and contains the following + + -------------------- start of page + header (once for the ring buffer) \\ + space for page alignment ||+- HEADER_SIZE +RB_BASE -+v || + myringbuffer.offset |/ + -------------------- start of page/-- pagesize + myringbuffer.data (SEGMENT_SIZE)\ + space for page alignment |+- ENTRY_SIZE_PAGE_AL + myringbuffer.offset / + -------------------- start of page + myringbuffer.data + space for page alignment + ... +*/ +typedef struct { + int offset; + UINT4 data[CD_FRAMESAMPLES]; +} myringbuff; + +struct ringbuffheader { + myringbuff *p1; + myringbuff *p2; + volatile unsigned long total_read; + volatile unsigned long total_written; + volatile int child_waitstate; + volatile int parent_waitstate; + volatile int input_littleendian; + volatile int end_is_reached; + volatile unsigned long nSamplesToDo; + int offset; + UINT4 data[CD_FRAMESAMPLES]; +}; + +extern myringbuff **he_fill_buffer; +extern myringbuff **last_buffer; +extern volatile unsigned long *total_segments_read; +extern volatile unsigned long *total_segments_written; +extern volatile int *child_waits; +extern volatile int *parent_waits; +extern volatile int *in_lendian; +extern volatile int *eorecording; + +#define palign(x, a) (((char *)(x)) + ((a) - 1 - (((unsigned)((x)-1))%(a)))) +#define multpage(x, a) ((((x) + (a) - 1) / (a)) * (a)) + +#define HEADER_SIZE multpage(offset_of(struct ringbuffheader, data), global.pagesize) +#define SEGMENT_SIZE (global.nsectors*CD_FRAMESIZE_RAW) +#define ENTRY_SIZE_PAGE_AL multpage(SEGMENT_SIZE + offset_of(myringbuff, data), global.pagesize) + +#define RB_BASE ((myringbuff *)(((unsigned char *)he_fill_buffer) + HEADER_SIZE - offset_of(myringbuff, data))) + +#define INC(a) (myringbuff *)(((char *)RB_BASE) + (((((char *) (a))-((char *)RB_BASE))/ENTRY_SIZE_PAGE_AL + 1) % total_buffers)*ENTRY_SIZE_PAGE_AL) + + +void set_total_buffers(unsigned int num_buffers, int mysem_id); +const myringbuff *get_previous_read_buffer(void); +const myringbuff *get_he_fill_buffer(void); +myringbuff *get_next_buffer(void); +myringbuff *get_oldest_buffer(void); +void define_buffer(void); +void drop_buffer(void); +void drop_all_buffers(void); diff --git a/icedax/scsi_cmds.c b/icedax/scsi_cmds.c new file mode 100644 index 0000000..e77b3af --- /dev/null +++ b/icedax/scsi_cmds.c @@ -0,0 +1,1720 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)scsi_cmds.c 1.29 03/03/31 Copyright 1998-2002 Heiko Eissfeldt */ +/* file for all SCSI commands + * FUA (Force Unit Access) bit handling copied from Monty's cdparanoia. + */ +#undef DEBUG_FULLTOC +#undef WARN_FULLTOC +#define TESTSUBQFALLBACK 0 + +#include "config.h" +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <schily.h> + +#include <btorder.h> + +#define g5x_cdblen(cdb, len) ((cdb)->count[0] = ((len) >> 16L)& 0xFF,\ + (cdb)->count[1] = ((len) >> 8L) & 0xFF,\ + (cdb)->count[2] = (len) & 0xFF) + + +#include <usal/usalcmd.h> +#include <usal/scsidefs.h> +#include <usal/scsireg.h> + +#include <usal/scsitransp.h> + +#include "mytype.h" +#include "icedax.h" +#include "interface.h" +#include "byteorder.h" +#include "global.h" +#include "wodim.h" +#include "toc.h" +#include "scsi_cmds.h" +#include "exitcodes.h" + +unsigned char *bufferTOC; +subq_chnl *SubQbuffer; +unsigned char *cmd; + +static unsigned ReadFullTOCSony(SCSI *usalp); +static unsigned ReadFullTOCMMC(SCSI *usalp); + + +int SCSI_emulated_ATAPI_on(SCSI *usalp) +{ +/* return is_atapi;*/ + if (usal_isatapi(usalp) > 0) + return (TRUE); + + (void) allow_atapi(usalp, TRUE); + return (allow_atapi(usalp, TRUE)); +} + +int heiko_mmc(SCSI *usalp) +{ + unsigned char mode[0x100]; + int was_atapi; + struct cd_mode_page_2A *mp; + int retval; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + + was_atapi = allow_atapi(usalp, 1); + usalp->silent++; + mp = mmc_cap(usalp, mode); + usalp->silent--; + allow_atapi(usalp, was_atapi); + if (mp == NULL) + return (0); + + /* have a look at the capabilities */ + if (mp->cd_da_supported == 0) { + retval = -1; + } else { + retval = 1 + mp->cd_da_accurate; + } + return retval; +} + + +int accepts_fua_bit; +unsigned char density = 0; +unsigned char orgmode4 = 0; +unsigned char orgmode10, orgmode11; + +/* get current sector size from SCSI cdrom drive */ +unsigned int +get_orig_sectorsize(SCSI *usalp, unsigned char *m4, unsigned char *m10, + unsigned char *m11) +{ + /* first get current values for density, etc. */ + + static unsigned char *modesense = NULL; + + if (modesense == NULL) { + modesense = malloc(12); + if (modesense == NULL) { + fprintf(stderr, "Cannot allocate memory for mode sense command in line %d\n", __LINE__); + return 0; + } + } + + /* do the scsi cmd */ + if (usalp->verbose) fprintf(stderr, "\nget density and sector size..."); + if (mode_sense(usalp, modesense, 12, 0x01, 0) < 0) + fprintf(stderr, "get_orig_sectorsize mode sense failed\n"); + + /* FIXME: some drives dont deliver block descriptors !!! */ + if (modesense[3] == 0) + return 0; + +#if 0 + modesense[4] = 0x81; + modesense[10] = 0x08; + modesense[11] = 0x00; +#endif + + if (m4 != NULL) /* density */ + *m4 = modesense[4]; + if (m10 != NULL) /* MSB sector size */ + *m10 = modesense[10]; + if (m11 != NULL) /* LSB sector size */ + *m11 = modesense[11]; + + return (modesense[10] << 8) + modesense[11]; +} + + + +/* switch CDROM scsi drives to given sector size */ +int set_sectorsize(SCSI *usalp, unsigned int secsize) +{ + static unsigned char mode [4 + 8]; + int retval; + + if (orgmode4 == 0xff) { + get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11); + } + if (orgmode4 == 0x82 && secsize == 2048) + orgmode4 = 0x81; + + /* prepare to read cds in the previous mode */ + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + mode[ 3] = 8; /* Block Descriptor Length */ + mode[ 4] = orgmode4; /* normal density */ + mode[10] = secsize >> 8; /* block length "msb" */ + mode[11] = secsize & 0xFF; /* block length lsb */ + + if (usalp->verbose) fprintf(stderr, "\nset density and sector size..."); + /* do the scsi cmd */ + if ((retval = mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2)) < 0) + fprintf (stderr, "setting sector size failed\n"); + + return retval; +} + + +/* switch Toshiba/DEC and HP drives from/to cdda density */ +void EnableCddaModeSelect(SCSI *usalp, int fAudioMode, unsigned uSectorsize) +{ + /* reserved, Medium type=0, Dev spec Parm = 0, block descriptor len 0 oder 8, + Density (cd format) + (0=YellowBook, XA Mode 2=81h, XA Mode1=83h and raw audio via SCSI=82h), + # blks msb, #blks, #blks lsb, reserved, + blocksize, blocklen msb, blocklen lsb, + */ + + /* MODE_SELECT, page = SCSI-2 save page disabled, reserved, reserved, + parm list len, flags */ + static unsigned char mode [4 + 8] = { + /* mode section */ + 0, + 0, 0, + 8, /* Block Descriptor Length */ + /* block descriptor */ + 0, /* Density Code */ + 0, 0, 0, /* # of Blocks */ + 0, /* reserved */ + 0, 0, 0};/* Blocklen */ + + if (orgmode4 == 0 && fAudioMode) { + if (0 == get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11)) { + /* cannot retrieve density, sectorsize */ + orgmode10 = (CD_FRAMESIZE >> 8L); + orgmode11 = (CD_FRAMESIZE & 0xFF); + } + } + + if (fAudioMode) { + /* prepare to read audio cdda */ + mode [4] = density; /* cdda density */ + mode [10] = (uSectorsize >> 8L); /* block length "msb" */ + mode [11] = (uSectorsize & 0xFF); /* block length "lsb" */ + } else { + /* prepare to read cds in the previous mode */ + mode [4] = orgmode4; /* 0x00; \* normal density */ + mode [10] = orgmode10; /* (CD_FRAMESIZE >> 8L); \* block length "msb" */ + mode [11] = orgmode11; /* (CD_FRAMESIZE & 0xFF); \* block length lsb */ + } + + if (usalp->verbose) fprintf(stderr, "\nset density/sector size (EnableCddaModeSelect)...\n"); + /* do the scsi cmd */ + if (mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2) < 0) + fprintf (stderr, "Audio mode switch failed\n"); +} + + +/* read CD Text information from the table of contents */ +void ReadTocTextSCSIMMC(SCSI *usalp) +{ + short datalength; + +#if 1 + /* READTOC, MSF, format, res, res, res, Start track/session, len msb, + len lsb, control */ + unsigned char *p = bufferTOC; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 4; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 5; /* format field */ + scmd->cdb.g1_cdb.res6 = 0; /* track/session is reserved */ + g1_cdblen(&scmd->cdb.g1_cdb, 4); + + usalp->silent++; + if (usalp->verbose) fprintf(stderr, "\nRead TOC CD Text size ..."); + + usalp->cmdname = "read toc size (text)"; + + if (usal_cmd(usalp) < 0) { + usalp->silent--; + if (global.quiet != 1) + fprintf (stderr, "Read TOC CD Text failed (probably not supported).\n"); + p[0] = p[1] = '\0'; + return ; + } + usalp->silent--; + + datalength = (p[0] << 8) | (p[1]); + if (datalength <= 2) + return; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 2+datalength; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 5; /* format field */ + scmd->cdb.g1_cdb.res6 = 0; /* track/session is reserved */ + g1_cdblen(&scmd->cdb.g1_cdb, 2+datalength); + + usalp->silent++; + if (usalp->verbose) fprintf(stderr, "\nRead TOC CD Text data (length %hd)...", 2+datalength); + + usalp->cmdname = "read toc data (text)"; + + if (usal_cmd(usalp) < 0) { + usalp->silent--; + if (global.quiet != 1) + fprintf (stderr, "Read TOC CD Text data failed (probably not supported).\n"); + p[0] = p[1] = '\0'; + return ; + } + usalp->silent--; +#else + { FILE *fp; + int read_; + /*fp = fopen("PearlJam.cdtext", "rb");*/ + /*fp = fopen("celine.cdtext", "rb");*/ + fp = fopen("japan.cdtext", "rb"); + if (fp == NULL) { perror(""); return; } + fillbytes(bufferTOC, CD_FRAMESIZE, '\0'); + read_ = fread(bufferTOC, 1, CD_FRAMESIZE, fp ); +fprintf(stderr, "read %d bytes. sizeof(bufferTOC)=%u\n", read_, CD_FRAMESIZE); + datalength = (bufferTOC[0] << 8) | (bufferTOC[1]); + fclose(fp); + } +#endif +} + +/* read the full TOC */ +static unsigned ReadFullTOCSony(SCSI *usalp) +{ + /* READTOC, MSF, format, res, res, res, Start track/session, len msb, + len lsb, control */ + register struct usal_cmd *scmd = usalp->scmd; + unsigned tracks = 99; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 4 + (3 + tracks + 6) * 11; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res6 = 1; /* session */ + g1_cdblen(&scmd->cdb.g1_cdb, 4 + (3 + tracks + 6) * 11); + scmd->cdb.g1_cdb.vu_97 = 1; /* format */ + + usalp->silent++; + if (usalp->verbose) fprintf(stderr, "\nRead Full TOC Sony ..."); + + usalp->cmdname = "read full toc sony"; + + if (usal_cmd(usalp) < 0) { + usalp->silent--; + if (global.quiet != 1) + fprintf (stderr, "Read Full TOC Sony failed (probably not supported).\n"); + return 0; + } + usalp->silent--; + + return (unsigned)((bufferTOC[0] << 8) | bufferTOC[1]); +} + +struct msf_address { + unsigned char mins; + unsigned char secs; + unsigned char frame; +}; + +struct zmsf_address { + unsigned char zero; + unsigned char mins; + unsigned char secs; + unsigned char frame; +}; + +#ifdef WARN_FULLTOC +static unsigned lba(struct msf_address *ad); + +static unsigned lba(struct msf_address *ad) +{ + return ad->mins*60*75 + ad->secs*75 + ad->frame; +} +#endif + +static unsigned dvd_lba(struct zmsf_address *ad); + +static unsigned dvd_lba(struct zmsf_address *ad) +{ + return ad->zero*1053696 + ad->mins*60*75 + ad->secs*75 + ad->frame; +} + +struct tocdesc { + unsigned char session; + unsigned char adrctl; + unsigned char tno; + unsigned char point; + struct msf_address adr1; + struct zmsf_address padr2; +}; + +struct outer { + unsigned char len_msb; + unsigned char len_lsb; + unsigned char first_track; + unsigned char last_track; + struct tocdesc ent[1]; +}; + +static unsigned long first_session_leadout = 0; + +static unsigned collect_tracks(struct outer *po, unsigned entries, + BOOL bcd_flag); + +static unsigned collect_tracks(struct outer *po, unsigned entries, + BOOL bcd_flag) +{ + unsigned tracks = 0; + int i; + unsigned session; + unsigned last_start; + unsigned leadout_start_orig; + unsigned leadout_start; + unsigned max_leadout = 0; + +#ifdef DEBUG_FULLTOC + for (i = 0; i < entries; i++) { +fprintf(stderr, "%3d: %d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n" + ,i + ,bufferTOC[4+0 + (i * 11)] + ,bufferTOC[4+1 + (i * 11)] + ,bufferTOC[4+2 + (i * 11)] + ,bufferTOC[4+3 + (i * 11)] + ,bufferTOC[4+4 + (i * 11)] + ,bufferTOC[4+5 + (i * 11)] + ,bufferTOC[4+6 + (i * 11)] + ,bufferTOC[4+7 + (i * 11)] + ,bufferTOC[4+8 + (i * 11)] + ,bufferTOC[4+9 + (i * 11)] + ,bufferTOC[4+10 + (i * 11)] + ); + } +#endif + /* reformat to standard toc format */ + + bufferTOC[2] = 0; + bufferTOC[3] = 0; + session = 0; + last_start = 0; + leadout_start_orig = 0; + leadout_start = 0; + + for (i = 0; i < entries; i++) { +#ifdef WARN_FULLTOC + if (po->ent[i].tno != 0) { + fprintf(stderr, +"entry %d, tno is not 0: %d!\n", +i, po->ent[i].tno); + } +#endif + if (bcd_flag) { + po->ent[i].session = from_bcd(po->ent[i].session); + po->ent[i].adr1.mins = from_bcd(po->ent[i].adr1.mins); + po->ent[i].adr1.secs = from_bcd(po->ent[i].adr1.secs); + po->ent[i].adr1.frame = from_bcd(po->ent[i].adr1.frame); + po->ent[i].padr2.mins = from_bcd(po->ent[i].padr2.mins); + po->ent[i].padr2.secs = from_bcd(po->ent[i].padr2.secs); + po->ent[i].padr2.frame = from_bcd(po->ent[i].padr2.frame); + } + switch (po->ent[i].point) { + case 0xa0: + + /* check if session is monotonous increasing */ + + if (session+1 == po->ent[i].session) { + session = po->ent[i].session; + } +#ifdef WARN_FULLTOC + else fprintf(stderr, +"entry %d, session anomaly %d != %d!\n", +i, session+1, po->ent[i].session); + + /* check the adrctl field */ + if (0x10 != (po->ent[i].adrctl & 0x10)) { + fprintf(stderr, +"entry %d, incorrect adrctl field %x!\n", +i, po->ent[i].adrctl); + } +#endif + /* first track number */ + if (bufferTOC[2] < po->ent[i].padr2.mins + && bufferTOC[3] < po->ent[i].padr2.mins) { + bufferTOC[2] = po->ent[i].padr2.mins; + } +#ifdef WARN_FULLTOC + else + fprintf(stderr, +"entry %d, session %d: start tracknumber anomaly: %d <= %d,%d(last)!\n", +i, session, po->ent[i].padr2.mins, bufferTOC[2], bufferTOC[3]); +#endif + break; + + case 0xa1: +#ifdef WARN_FULLTOC + /* check if session is constant */ + if (session != po->ent[i].session) { + fprintf(stderr, +"entry %d, session anomaly %d != %d!\n", +i, session, po->ent[i].session); + } + + /* check the adrctl field */ + if (0x10 != (po->ent[i].adrctl & 0x10)) { + fprintf(stderr, +"entry %d, incorrect adrctl field %x!\n", +i, po->ent[i].adrctl); + } +#endif + /* last track number */ + if (bufferTOC[2] <= po->ent[i].padr2.mins + && bufferTOC[3] < po->ent[i].padr2.mins) { + bufferTOC[3] = po->ent[i].padr2.mins; + } +#ifdef WARN_FULLTOC + else + fprintf(stderr, +"entry %d, session %d: end tracknumber anomaly: %d <= %d,%d(last)!\n", +i, session, po->ent[i].padr2.mins, bufferTOC[2], bufferTOC[3]); +#endif + break; + + case 0xa2: +#ifdef WARN_FULLTOC + /* check if session is constant */ + if (session != po->ent[i].session) { + fprintf(stderr, +"entry %d, session anomaly %d != %d!\n", +i, session, po->ent[i].session); + } + + /* check the adrctl field */ + if (0x10 != (po->ent[i].adrctl & 0x10)) { + fprintf(stderr, +"entry %d, incorrect adrctl field %x!\n", +i, po->ent[i].adrctl); + } +#endif + /* register leadout position */ + { + unsigned leadout_start_tmp = + dvd_lba(&po->ent[i].padr2); + + if (first_session_leadout == 0) + first_session_leadout = leadout_start_tmp - 150; + + if (leadout_start_tmp > leadout_start) { + leadout_start_orig = leadout_start_tmp; + leadout_start = leadout_start_tmp; + } +#ifdef WARN_FULLTOC + else + fprintf(stderr, +"entry %d, leadout position anomaly %u!\n", +i, leadout_start_tmp); +#endif + } + break; + + case 0xb0: +#ifdef WARN_FULLTOC + /* check if session is constant */ + if (session != po->ent[i].session) { + fprintf(stderr, +"entry %d, session anomaly %d != %d!\n", +i, session, po->ent[i].session); + } + + /* check the adrctl field */ + if (0x50 != (po->ent[i].adrctl & 0x50)) { + fprintf(stderr, +"entry %d, incorrect adrctl field %x!\n", +i, po->ent[i].adrctl); + } + + /* check the next program area */ + if (lba(&po->ent[i].adr1) < 6750 + leadout_start) { + fprintf(stderr, +"entry %d, next program area %u < leadout_start + 6750 = %u!\n", +i, lba(&po->ent[i].adr1), 6750 + leadout_start); + } + + /* check the maximum leadout_start */ + if (max_leadout != 0 && dvd_lba(&po->ent[i].padr2) != max_leadout) { + fprintf(stderr, +"entry %d, max leadout_start %u != last max_leadout_start %u!\n", +i, dvd_lba(&po->ent[i].padr2), max_leadout); + } +#endif + if (max_leadout == 0) + max_leadout = dvd_lba(&po->ent[i].padr2); + + break; + case 0xb1: + case 0xb2: + case 0xb3: + case 0xb4: + case 0xb5: + case 0xb6: + break; + case 0xc0: + case 0xc1: + break; + default: + /* check if session is constant */ + if (session != po->ent[i].session) { +#ifdef WARN_FULLTOC + fprintf(stderr, +"entry %d, session anomaly %d != %d!\n", +i, session, po->ent[i].session); +#endif + continue; + } + + /* check tno */ + if (bcd_flag) + po->ent[i].point = from_bcd(po->ent[i].point); + + if (po->ent[i].point < bufferTOC[2] + || po->ent[i].point > bufferTOC[3]) { +#ifdef WARN_FULLTOC + fprintf(stderr, +"entry %d, track number anomaly %d - %d - %d!\n", +i, bufferTOC[2], po->ent[i].point, bufferTOC[3]); +#endif + } else { + /* check start position */ + unsigned trackstart = dvd_lba(&po->ent[i].padr2); + + /* correct illegal leadouts */ + if (leadout_start < trackstart) { + leadout_start = trackstart+1; + } + if (trackstart < last_start || trackstart >= leadout_start) { +#ifdef WARN_FULLTOC + fprintf(stderr, +"entry %d, track %d start position anomaly %d - %d - %d!\n", +i, po->ent[i].point, last_start, trackstart, leadout_start); +#endif + } else { + last_start = trackstart; + memcpy(&po->ent[tracks], &po->ent[i], sizeof(struct tocdesc)); + tracks++; + } + } + } /* switch */ + } /* for */ + + /* patch leadout track */ + po->ent[tracks].session = session; + po->ent[tracks].adrctl = 0x10; + po->ent[tracks].tno = 0; + po->ent[tracks].point = 0xAA; + po->ent[tracks].adr1.mins = 0; + po->ent[tracks].adr1.secs = 0; + po->ent[tracks].adr1.frame = 0; + po->ent[tracks].padr2.zero = leadout_start_orig / (1053696); + po->ent[tracks].padr2.mins = (leadout_start_orig / (60*75)) % 100; + po->ent[tracks].padr2.secs = (leadout_start_orig / 75) % 60; + po->ent[tracks].padr2.frame = leadout_start_orig % 75; + tracks++; + + /* length */ + bufferTOC[0] = ((tracks * 8) + 2) >> 8; + bufferTOC[1] = ((tracks * 8) + 2) & 0xff; + + + /* reformat 11 byte blocks to 8 byte entries */ + + /* 1: Session \ / reserved + 2: adr ctrl | | adr ctrl + 3: TNO | | track number + 4: Point | | reserved + 5: Min +-->----+ 0 + 6: Sec | | Min + 7: Frame | | Sec + 8: Zero | \ Frame + 9: PMin | + 10: PSec | + 11: PFrame / + */ + for (i = 0; i < tracks; i++) { + bufferTOC[4+0 + (i << 3)] = 0; + bufferTOC[4+1 + (i << 3)] = bufferTOC[4+1 + (i*11)]; + bufferTOC[4+1 + (i << 3)] = (bufferTOC[4+1 + (i << 3)] >> 4) | (bufferTOC[4+1 + (i << 3)] << 4); + bufferTOC[4+2 + (i << 3)] = bufferTOC[4+3 + (i*11)]; + bufferTOC[4+3 + (i << 3)] = 0; + bufferTOC[4+4 + (i << 3)] = bufferTOC[4+7 + (i*11)]; + bufferTOC[4+5 + (i << 3)] = bufferTOC[4+8 + (i*11)]; + bufferTOC[4+6 + (i << 3)] = bufferTOC[4+9 + (i*11)]; + bufferTOC[4+7 + (i << 3)] = bufferTOC[4+10 + (i*11)]; +#ifdef DEBUG_FULLTOC +fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n" + ,bufferTOC[4+ 1 + i*8] + ,bufferTOC[4+ 2 + i*8] + ,bufferTOC[4+ 4 + i*8] + ,bufferTOC[4+ 5 + i*8] + ,bufferTOC[4+ 6 + i*8] + ,bufferTOC[4+ 7 + i*8] +); +#endif + } + + TOC_entries(tracks, NULL, bufferTOC+4, 0); + return tracks; +} + +/* read the table of contents from the cd and fill the TOC array */ +unsigned ReadTocSony(SCSI *usalp) +{ + unsigned tracks = 0; + unsigned return_length; + + struct outer *po = (struct outer *)bufferTOC; + + return_length = ReadFullTOCSony(usalp); + + /* Check if the format was understood */ + if ((return_length & 7) == 2 && (bufferTOC[3] - bufferTOC[2]) == (return_length >> 3)) { + /* The extended format seems not be understood, fallback to + * the classical format. */ + return ReadTocSCSI( usalp ); + } + + tracks = collect_tracks(po, ((return_length - 2) / 11), TRUE); + + return --tracks; /* without lead-out */ +} + +/* read the start of the lead-out from the first session TOC */ +unsigned ReadFirstSessionTOCSony(SCSI *usalp) +{ + unsigned return_length; + + if (first_session_leadout != 0) + return first_session_leadout; + + return_length = ReadFullTOCSony(usalp); + if (return_length >= 4 + (3 * 11) -2) { + unsigned off; + + /* We want the entry with POINT = 0xA2, which has the start position + of the first session lead out */ + off = 4 + 2 * 11 + 3; + if (bufferTOC[off-3] == 1 && bufferTOC[off] == 0xA2) { + unsigned retval; + + off = 4 + 2 * 11 + 8; + retval = bufferTOC[off] >> 4; + retval *= 10; retval += bufferTOC[off] & 0xf; + retval *= 60; + off++; + retval += 10 * (bufferTOC[off] >> 4) + (bufferTOC[off] & 0xf); + retval *= 75; + off++; + retval += 10 * (bufferTOC[off] >> 4) + (bufferTOC[off] & 0xf); + retval -= 150; + + return retval; + } + } + return 0; +} + +/* read the full TOC */ +static unsigned ReadFullTOCMMC(SCSI *usalp) +{ + + /* READTOC, MSF, format, res, res, res, Start track/session, len msb, + len lsb, control */ + register struct usal_cmd *scmd = usalp->scmd; + unsigned tracks = 99; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 4 + (tracks + 8) * 11; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* Read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 2; /* format */ + scmd->cdb.g1_cdb.res6 = 1; /* session */ + g1_cdblen(&scmd->cdb.g1_cdb, 4 + (tracks + 8) * 11); + + usalp->silent++; + if (usalp->verbose) fprintf(stderr, "\nRead Full TOC MMC..."); + + usalp->cmdname = "read full toc mmc"; + + if (usal_cmd(usalp) < 0) { + if (global.quiet != 1) + fprintf (stderr, "Read Full TOC MMC failed (probably not supported).\n"); +#ifdef B_BEOS_VERSION +#else + usalp->silent--; + return 0; +#endif + } + usalp->silent--; + + return (unsigned)((bufferTOC[0] << 8) | bufferTOC[1]); +} + +/* read the start of the lead-out from the first session TOC */ +unsigned ReadFirstSessionTOCMMC(SCSI *usalp) +{ + unsigned off; + unsigned return_length; + + if (first_session_leadout != 0) + return first_session_leadout; + + return_length = ReadFullTOCMMC(usalp); + + /* We want the entry with POINT = 0xA2, which has the start position + of the first session lead out */ + off = 4 + 3; + while (off < return_length && bufferTOC[off] != 0xA2) { + off += 11; + } + if (off < return_length) { + off += 5; + return (bufferTOC[off]*60 + bufferTOC[off+1])*75 + bufferTOC[off+2] - 150; + } + return 0; +} + +/* read the table of contents from the cd and fill the TOC array */ +unsigned ReadTocMMC(SCSI *usalp) +{ + unsigned tracks = 0; + unsigned return_length; + + struct outer *po = (struct outer *)bufferTOC; + + return_length = ReadFullTOCMMC(usalp); + if (return_length - 2 < 4*11 || ((return_length - 2) % 11) != 0) + return ReadTocSCSI(usalp); + + tracks = collect_tracks(po, ((return_length - 2) / 11), FALSE); + return --tracks; /* without lead-out */ +} + +/* read the table of contents from the cd and fill the TOC array */ +unsigned ReadTocSCSI(SCSI *usalp) +{ + unsigned tracks; + int result; + unsigned char bufferTOCMSF[CD_FRAMESIZE]; + + /* first read the first and last track number */ + /* READTOC, MSF format flag, res, res, res, res, Start track, len msb, + len lsb, flags */ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 4; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res6 = 1; /* start track */ + g1_cdblen(&scmd->cdb.g1_cdb, 4); + + if (usalp->verbose) fprintf(stderr, "\nRead TOC size (standard)..."); + /* do the scsi cmd (read table of contents) */ + + usalp->cmdname = "read toc size"; + if (usal_cmd(usalp) < 0) + FatalError ("Read TOC size failed.\n"); + + + tracks = ((bufferTOC [3] ) - bufferTOC [2] + 2) ; + if (tracks > MAXTRK) return 0; + if (tracks == 0) return 0; + + + memset(bufferTOCMSF, 0, sizeof(bufferTOCMSF)); + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOCMSF; + scmd->size = 4 + tracks * 8; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res = 1; /* MSF format */ + scmd->cdb.g1_cdb.res6 = 1; /* start track */ + g1_cdblen(&scmd->cdb.g1_cdb, 4 + tracks * 8); + + if (usalp->verbose) fprintf(stderr, "\nRead TOC tracks (standard MSF)..."); + /* do the scsi cmd (read table of contents) */ + + usalp->cmdname = "read toc tracks "; + result = usal_cmd(usalp); + + if (result < 0) { + /* MSF format did not succeeded */ + memset(bufferTOCMSF, 0, sizeof(bufferTOCMSF)); + } else { + int i; + for (i = 0; i < tracks; i++) { + bufferTOCMSF[4+1 + (i << 3)] = (bufferTOCMSF[4+1 + (i << 3)] >> 4) | (bufferTOCMSF[4+1 + (i << 3)] << 4); +#if 0 +fprintf(stderr, "MSF %d %02x %02x %02x %02x %02x %02x %02x %02x\n" + ,i + ,bufferTOCMSF[4+0 + (i * 8)] + ,bufferTOCMSF[4+1 + (i * 8)] + ,bufferTOCMSF[4+2 + (i * 8)] + ,bufferTOCMSF[4+3 + (i * 8)] + ,bufferTOCMSF[4+4 + (i * 8)] + ,bufferTOCMSF[4+5 + (i * 8)] + ,bufferTOCMSF[4+6 + (i * 8)] + ,bufferTOCMSF[4+7 + (i * 8)] + ); +#endif + } + } + + /* LBA format for cd burners like Philips CD-522 */ + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)bufferTOC; + scmd->size = 4 + tracks * 8; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x43; /* read TOC command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res = 0; /* LBA format */ + scmd->cdb.g1_cdb.res6 = 1; /* start track */ + g1_cdblen(&scmd->cdb.g1_cdb, 4 + tracks * 8); + + if (usalp->verbose) fprintf(stderr, "\nRead TOC tracks (standard LBA)..."); + /* do the scsi cmd (read table of contents) */ + + usalp->cmdname = "read toc tracks "; + if (usal_cmd(usalp) < 0) { + FatalError ("Read TOC tracks (lba) failed.\n"); + } + { + int i; + for (i = 0; i < tracks; i++) { + bufferTOC[4+1 + (i << 3)] = (bufferTOC[4+1 + (i << 3)] >> 4) | (bufferTOC[4+1 + (i << 3)] << 4); +#if 0 +fprintf(stderr, "LBA %d %02x %02x %02x %02x %02x %02x %02x %02x\n" + ,i + ,bufferTOC[4+0 + (i * 8)] + ,bufferTOC[4+1 + (i * 8)] + ,bufferTOC[4+2 + (i * 8)] + ,bufferTOC[4+3 + (i * 8)] + ,bufferTOC[4+4 + (i * 8)] + ,bufferTOC[4+5 + (i * 8)] + ,bufferTOC[4+6 + (i * 8)] + ,bufferTOC[4+7 + (i * 8)] + ); +#endif + } + } + TOC_entries(tracks, bufferTOC+4, bufferTOCMSF+4, result); + return --tracks; /* without lead-out */ +} + +/* ---------------- Read methods ------------------------------ */ + +/* Read max. SectorBurst of cdda sectors to buffer + via standard SCSI-2 Read(10) command */ +static int ReadStandardLowlevel(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal, unsigned secsize); + +static int ReadStandardLowlevel(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal, unsigned secsize) +{ + /* READ10, flags, block1 msb, block2, block3, block4 lsb, reserved, + transfer len msb, transfer len lsb, block addressing mode */ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal * secsize; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x28; /* read 10 command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + g1_cdbaddr(&scmd->cdb.g1_cdb, lSector); + g1_cdblen(&scmd->cdb.g1_cdb, SectorBurstVal); + if (usalp->verbose) fprintf(stderr, "\nReadStandard10 %s (%u)...", secsize > 2048 ? "CDDA" : "CD_DATA", secsize); + + usalp->cmdname = "ReadStandard10"; + + if (usal_cmd(usalp)) return 0; + + /* has all or something been read? */ + return SectorBurstVal - usal_getresid(usalp)/secsize; +} + + +int +ReadStandard(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + return ReadStandardLowlevel(usalp, p, lSector, SectorBurstVal, CD_FRAMESIZE_RAW); +} + +int +ReadStandardData(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + return ReadStandardLowlevel(usalp, p, lSector, SectorBurstVal, CD_FRAMESIZE); +} + +/* Read max. SectorBurst of cdda sectors to buffer + via vendor-specific ReadCdda(10) command */ +int ReadCdda10(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + /* READ10, flags, block1 msb, block2, block3, block4 lsb, reserved, + transfer len msb, transfer len lsb, block addressing mode */ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0xd4; /* Read audio command */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + g1_cdbaddr(&scmd->cdb.g1_cdb, lSector); + g1_cdblen(&scmd->cdb.g1_cdb, SectorBurstVal); + if (usalp->verbose) fprintf(stderr, "\nReadNEC10 CDDA..."); + + usalp->cmdname = "Read10 NEC"; + + if (usal_cmd(usalp)) return 0; + + /* has all or something been read? */ + return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; +} + + +/* Read max. SectorBurst of cdda sectors to buffer + via vendor-specific ReadCdda(12) command */ +int ReadCdda12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + + if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA..."); + + usalp->cmdname = "Read12"; + + if (usal_cmd(usalp)) return 0; + + /* has all or something been read? */ + return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; +} + +/* Read max. SectorBurst of cdda sectors to buffer + via vendor-specific ReadCdda(12) command */ +/* +> It uses a 12 Byte CDB with 0xd4 as opcode, the start sector is coded as +> normal and the number of sectors is coded in Byte 8 and 9 (begining with 0). +*/ + +int ReadCdda12Matsushita(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xd4; /* read audio command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + + if (usalp->verbose) fprintf(stderr, "\nReadMatsushita12 CDDA..."); + + usalp->cmdname = "Read12Matsushita"; + + if (usal_cmd(usalp)) return 0; + + /* has all or something been read? */ + return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; +} + +/* Read max. SectorBurst of cdda sectors to buffer + via MMC standard READ CD command */ +int ReadCddaMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd; + scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*CD_FRAMESIZE_RAW; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xbe; /* read cd command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res = 1 << 1; /* expected sector type field CDDA */ + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5x_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + scmd->cdb.g5_cdb.count[3] = 1 << 4; /* User data */ + + if (usalp->verbose) fprintf(stderr, "\nReadMMC12 CDDA..."); + + usalp->cmdname = "ReadCD MMC 12"; + + if (usal_cmd(usalp)) return 0; + + /* has all or something been read? */ + return SectorBurstVal - usal_getresid(usalp)/CD_FRAMESIZE_RAW; +} + +int ReadCddaFallbackMMC(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + static int ReadCdda12_unknown = 0; + int retval = -999; + + usalp->silent++; + if (ReadCdda12_unknown + || ((retval = ReadCdda12(usalp, p, lSector, SectorBurstVal)) <= 0)) { + /* if the command is not available, use the regular + * MMC ReadCd + */ + if (retval <= 0 && usal_sense_key(usalp) == 0x05) { + ReadCdda12_unknown = 1; + } + usalp->silent--; + ReadCdRom = ReadCddaMMC12; + ReadCdRomSub = ReadCddaSubMMC12; + return ReadCddaMMC12(usalp, p, lSector, SectorBurstVal); + } + usalp->silent--; + return retval; +} + +/* Read the Sub-Q-Channel to SubQbuffer. This is the method for + * drives that do not support subchannel parameters. */ +#ifdef PROTOTYPES +static subq_chnl *ReadSubQFallback (SCSI *usalp, unsigned char sq_format, unsigned char track) +#else +static subq_chnl * +ReadSubQFallback(SCSI *usalp, unsigned char sq_format, unsigned char track) +#endif +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)SubQbuffer; + scmd->size = 24; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x42; /* Read SubQChannel */ + /* use LBA */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 0x40; /* SubQ info */ + scmd->cdb.g1_cdb.addr[1] = 0; /* parameter list: all */ + scmd->cdb.g1_cdb.res6 = track; /* track number */ + g1_cdblen(&scmd->cdb.g1_cdb, 24); + + if (usalp->verbose) fprintf(stderr, "\nRead Subchannel_dumb..."); + + usalp->cmdname = "Read Subchannel_dumb"; + + if (usal_cmd(usalp) < 0) { + fprintf( stderr, "Read SubQ failed\n"); + } + + /* check, if the requested format is delivered */ + { unsigned char *p = (unsigned char *) SubQbuffer; + if ((((unsigned)p[2] << 8) | p[3]) /* LENGTH */ > ULONG_C(11) && + (p[5] >> 4) /* ADR */ == sq_format) { + if (sq_format == GET_POSITIONDATA) + p[5] = (p[5] << 4) | (p[5] >> 4); + return SubQbuffer; + } + } + + /* FIXME: we might actively search for the requested info ... */ + return NULL; +} + +/* Read the Sub-Q-Channel to SubQbuffer */ +#ifdef PROTOTYPES +subq_chnl *ReadSubQSCSI (SCSI *usalp, unsigned char sq_format, unsigned char track) +#else +subq_chnl * +ReadSubQSCSI(SCSI *usalp, unsigned char sq_format, unsigned char track) +#endif +{ + int resp_size; + register struct usal_cmd *scmd = usalp->scmd; + + switch (sq_format) { + case GET_POSITIONDATA: + resp_size = 16; + track = 0; + break; + case GET_CATALOGNUMBER: + resp_size = 24; + track = 0; + break; + case GET_TRACK_ISRC: + resp_size = 24; + break; + default: + fprintf(stderr, "ReadSubQSCSI: unknown format %d\n", sq_format); + return NULL; + } + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)SubQbuffer; + scmd->size = resp_size; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x42; + /* use LBA */ + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 0x40; /* SubQ info */ + scmd->cdb.g1_cdb.addr[1] = sq_format; /* parameter list: all */ + scmd->cdb.g1_cdb.res6 = track; /* track number */ + g1_cdblen(&scmd->cdb.g1_cdb, resp_size); + + if (usalp->verbose) fprintf(stderr, "\nRead Subchannel..."); + + usalp->cmdname = "Read Subchannel"; + + if (usal_cmd(usalp) < 0) { + /* in case of error do a fallback for dumb firmwares */ + return ReadSubQFallback(usalp, sq_format, track); + } + + if (sq_format == GET_POSITIONDATA) + SubQbuffer->control_adr = (SubQbuffer->control_adr << 4) | (SubQbuffer->control_adr >> 4); + return SubQbuffer; +} + +static subq_chnl sc; + +static subq_chnl* fill_subchannel(unsigned char bufferwithQ[]); +static subq_chnl* fill_subchannel(unsigned char bufferwithQ[]) +{ + sc.subq_length = 0; + sc.control_adr = bufferwithQ[CD_FRAMESIZE_RAW + 0]; + sc.track = bufferwithQ[CD_FRAMESIZE_RAW + 1]; + sc.index = bufferwithQ[CD_FRAMESIZE_RAW + 2]; + return ≻ +} + +int +ReadCddaSubSony(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 16); + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + scmd->cdb.g5_cdb.res10 = 0x01; /* subcode 1 -> cdda + 16 * q sub */ + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + + if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA + SubChannels..."); + + usalp->cmdname = "Read12SubChannelsSony"; + + if (usal_cmd(usalp)) return -1; + + /* has all or something been read? */ + return usal_getresid(usalp) != 0; +} + +int ReadCddaSub96Sony(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); + +int ReadCddaSub96Sony(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 96); + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xd8; /* read audio command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res |= (accepts_fua_bit == 1 ? 1 << 2 : 0); + scmd->cdb.g5_cdb.res10 = 0x02; /* subcode 2 -> cdda + 96 * q sub */ + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + + if (usalp->verbose) fprintf(stderr, "\nReadSony12 CDDA + 96 byte SubChannels..."); + + usalp->cmdname = "Read12SubChannelsSony"; + + if (usal_cmd(usalp)) return -1; + + /* has all or something been read? */ + return usal_getresid(usalp) != 0; +} + +subq_chnl *ReadSubChannelsSony(SCSI *usalp, unsigned lSector) +{ + /*int retval = ReadCddaSub96Sony(usalp, (UINT4 *)bufferTOC, lSector, 1);*/ + int retval = ReadCddaSubSony(usalp, (UINT4 *)bufferTOC, lSector, 1); + if (retval != 0) return NULL; + + return fill_subchannel(bufferTOC); +} + +/* Read max. SectorBurst of cdda sectors to buffer + via MMC standard READ CD command */ +int ReadCddaSubMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) +{ + register struct usal_cmd *scmd; + scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)p; + scmd->size = SectorBurstVal*(CD_FRAMESIZE_RAW + 16); + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xbe; /* read cd command */ + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + scmd->cdb.g5_cdb.res = 1 << 1; /* expected sector type field CDDA */ + g5_cdbaddr(&scmd->cdb.g5_cdb, lSector); + g5x_cdblen(&scmd->cdb.g5_cdb, SectorBurstVal); + scmd->cdb.g5_cdb.count[3] = 1 << 4; /* User data */ + scmd->cdb.g5_cdb.res10 = 0x02; /* subcode 2 -> cdda + 16 * q sub */ + + if (usalp->verbose) fprintf(stderr, "\nReadMMC12 CDDA + SUB..."); + + usalp->cmdname = "ReadCD Sub MMC 12"; + + if (usal_cmd(usalp)) return -1; + + /* has all or something been read? */ + return usal_getresid(usalp) != 0; +} + +static subq_chnl *ReadSubChannelsMMC(SCSI *usalp, unsigned lSector); +static subq_chnl *ReadSubChannelsMMC(SCSI *usalp, unsigned lSector) +{ + int retval = ReadCddaSubMMC12(usalp, (UINT4 *)bufferTOC, lSector, 1); + if (retval != 0) return NULL; + + return fill_subchannel(bufferTOC); +} + +subq_chnl *ReadSubChannelsFallbackMMC(SCSI *usalp, unsigned lSector) +{ + static int ReadSubSony_unknown = 0; + subq_chnl *retval = NULL; + + usalp->silent++; + if (ReadSubSony_unknown + || ((retval = ReadSubChannelsSony(usalp, lSector)) == NULL)) { + /* if the command is not available, use the regular + * MMC ReadCd + */ + if (retval == NULL && usal_sense_key(usalp) == 0x05) { + ReadSubSony_unknown = 1; + } + usalp->silent--; + return ReadSubChannelsMMC(usalp, lSector); + } + usalp->silent--; + return retval; +} + +subq_chnl *ReadStandardSub(usalp, lSector) + SCSI *usalp; + unsigned lSector; +{ + if (0 == ReadStandardLowlevel (usalp, (UINT4 *)bufferTOC, lSector, 1, CD_FRAMESIZE_RAW + 16 )) { + return NULL; + } +#if 0 +fprintf(stderr, "Subchannel Sec %x: %02x %02x %02x %02x\n" + ,lSector + ,bufferTOC[CD_FRAMESIZE_RAW + 0] + ,bufferTOC[CD_FRAMESIZE_RAW + 1] + ,bufferTOC[CD_FRAMESIZE_RAW + 2] + ,bufferTOC[CD_FRAMESIZE_RAW + 3] + ); +#endif + sc.control_adr = (bufferTOC[CD_FRAMESIZE_RAW + 0] << 4) + | bufferTOC[CD_FRAMESIZE_RAW + 1]; + sc.track = from_bcd(bufferTOC[CD_FRAMESIZE_RAW + 2]); + sc.index = from_bcd(bufferTOC[CD_FRAMESIZE_RAW + 3]); + return ≻ +} +/********* non standardized speed selects ***********************/ + +void SpeedSelectSCSIToshiba(SCSI *usalp, unsigned speed) +{ + static unsigned char mode [4 + 3]; + unsigned char *page = mode + 4; + int retval; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + /* the first 4 mode bytes are zero. */ + page[0] = 0x20; + page[1] = 1; + page[2] = speed; /* 0 for single speed, 1 for double speed (3401) */ + + if (usalp->verbose) fprintf(stderr, "\nspeed select Toshiba..."); + + usalp->silent++; + /* do the scsi cmd */ + if ((retval = mode_select(usalp, mode, 7, 0, usalp->inq->data_format >= 2)) < 0) + fprintf (stderr, "speed select Toshiba failed\n"); + usalp->silent--; +} + +void SpeedSelectSCSINEC(SCSI *usalp, unsigned speed) +{ + static unsigned char mode [4 + 8]; + unsigned char *page = mode + 4; + int retval; + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + /* the first 4 mode bytes are zero. */ + page [0] = 0x0f; /* page code */ + page [1] = 6; /* parameter length */ + /* bit 5 == 1 for single speed, otherwise double speed */ + page [2] = speed == 1 ? 1 << 5 : 0; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)mode; + scmd->size = 12; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0xC5; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[0] = 0 ? 1 : 0 | 1 ? 0x10 : 0; + g1_cdblen(&scmd->cdb.g1_cdb, 12); + + if (usalp->verbose) fprintf(stderr, "\nspeed select NEC..."); + /* do the scsi cmd */ + + usalp->cmdname = "speed select NEC"; + + if ((retval = usal_cmd(usalp)) < 0) + fprintf(stderr ,"speed select NEC failed\n"); +} + +void SpeedSelectSCSIPhilipsCDD2600(SCSI *usalp, unsigned speed) +{ + /* MODE_SELECT, page = SCSI-2 save page disabled, reserved, reserved, + parm list len, flags */ + static unsigned char mode [4 + 8]; + unsigned char *page = mode + 4; + int retval; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + /* the first 4 mode bytes are zero. */ + page[0] = 0x23; + page[1] = 6; + page[2] = page [4] = speed; + page[3] = 1; + + if (usalp->verbose) fprintf(stderr, "\nspeed select Philips..."); + /* do the scsi cmd */ + if ((retval = mode_select(usalp, mode, 12, 0, usalp->inq->data_format >= 2)) < 0) + fprintf (stderr, "speed select PhilipsCDD2600 failed\n"); +} + +void SpeedSelectSCSISony(SCSI *usalp, unsigned speed) +{ + static unsigned char mode [4 + 4]; + unsigned char *page = mode + 4; + int retval; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + /* the first 4 mode bytes are zero. */ + page[0] = 0x31; + page[1] = 2; + page[2] = speed; + + if (usalp->verbose) fprintf(stderr, "\nspeed select Sony..."); + /* do the scsi cmd */ + usalp->silent++; + if ((retval = mode_select(usalp, mode, 8, 0, usalp->inq->data_format >= 2)) < 0) + fprintf (stderr, "speed select Sony failed\n"); + usalp->silent--; +} + +void SpeedSelectSCSIYamaha (usalp, speed) + SCSI *usalp; + unsigned speed; +{ + static unsigned char mode [4 + 4]; + unsigned char *page = mode + 4; + int retval; + + fillbytes((caddr_t)mode, sizeof(mode), '\0'); + /* the first 4 mode bytes are zero. */ + page[0] = 0x31; + page[1] = 2; + page[2] = speed; + + if (usalp->verbose) fprintf(stderr, "\nspeed select Yamaha..."); + /* do the scsi cmd */ + if ((retval = mode_select(usalp, mode, 8, 0, usalp->inq->data_format >= 2)) < 0) + fprintf (stderr, "speed select Yamaha failed\n"); +} + +void SpeedSelectSCSIMMC(SCSI *usalp, unsigned speed) +{ + int spd; + register struct usal_cmd *scmd = usalp->scmd; + + if (speed == 0 || speed == 0xFFFF) { + spd = 0xFFFF; + } else { + spd = (1764 * speed) / 10; + } + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G5_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g5_cdb.cmd = 0xBB; + scmd->cdb.g5_cdb.lun = usal_lun(usalp); + i_to_2_byte(&scmd->cdb.g5_cdb.addr[0], spd); + i_to_2_byte(&scmd->cdb.g5_cdb.addr[2], 0xffff); + + if (usalp->verbose) fprintf(stderr, "\nspeed select MMC..."); + + usalp->cmdname = "set cd speed"; + + usalp->silent++; + if (usal_cmd(usalp) < 0) { + if (usal_sense_key(usalp) == 0x05 && + usal_sense_code(usalp) == 0x20 && + usal_sense_qual(usalp) == 0x00) { + /* this optional command is not implemented */ + } else { + usal_printerr(usalp); + fprintf (stderr, "speed select MMC failed\n"); + } + } + usalp->silent--; +} + +/* request vendor brand and model */ +unsigned char *Inquiry(SCSI *usalp) +{ + static unsigned char *Inqbuffer = NULL; + register struct usal_cmd *scmd = usalp->scmd; + + if (Inqbuffer == NULL) { + Inqbuffer = malloc(36); + if (Inqbuffer == NULL) { + fprintf(stderr, "Cannot allocate memory for inquiry command in line %d\n", __LINE__); + return NULL; + } + } + + fillbytes(Inqbuffer, 36, '\0'); + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)Inqbuffer; + scmd->size = 36; + scmd->flags = SCG_RECV_DATA|SCG_DISRE_ENA; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g0_cdb.cmd = SC_INQUIRY; + scmd->cdb.g0_cdb.lun = usal_lun(usalp); + scmd->cdb.g0_cdb.count = 36; + + usalp->cmdname = "inquiry"; + + if (usal_cmd(usalp) < 0) + return (NULL); + + /* define structure with inquiry data */ + memcpy(usalp->inq, Inqbuffer, sizeof(*usalp->inq)); + + if (usalp->verbose) + usal_prbytes("Inquiry Data :", (Uchar *)Inqbuffer, 22 - scmd->resid); + + return (Inqbuffer); +} + +#define SC_CLASS_EXTENDED_SENSE 0x07 +#define TESTUNITREADY_CMD 0 +#define TESTUNITREADY_CMDLEN 6 + +#define ADD_SENSECODE 12 +#define ADD_SC_QUALIFIER 13 +#define NO_MEDIA_SC 0x3a +#define NO_MEDIA_SCQ 0x00 + +int TestForMedium(SCSI *usalp) +{ + register struct usal_cmd *scmd = usalp->scmd; + + if (interface != GENERIC_SCSI) { + return 1; + } + + /* request READY status */ + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = (caddr_t)0; + scmd->size = 0; + scmd->flags = SCG_DISRE_ENA | (1 ? SCG_SILENT:0); + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY; + scmd->cdb.g0_cdb.lun = usal_lun(usalp); + + if (usalp->verbose) fprintf(stderr, "\ntest unit ready..."); + usalp->silent++; + + usalp->cmdname = "test unit ready"; + + if (usal_cmd(usalp) >= 0) { + usalp->silent--; + return 1; + } + usalp->silent--; + + if (scmd->sense.code >= SC_CLASS_EXTENDED_SENSE) { + return + scmd->u_sense.cmd_sense[ADD_SENSECODE] != NO_MEDIA_SC || + scmd->u_sense.cmd_sense[ADD_SC_QUALIFIER] != NO_MEDIA_SCQ; + } else { + /* analyse status. */ + /* 'check condition' is interpreted as not ready. */ + return (scmd->u_scb.cmd_scb[0] & 0x1e) != 0x02; + } +} + +int StopPlaySCSI(SCSI *usalp) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = NULL; + scmd->size = 0; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g0_cdb.cmd = 0x1b; + scmd->cdb.g0_cdb.lun = usal_lun(usalp); + + if (usalp->verbose) fprintf(stderr, "\nstop audio play"); + /* do the scsi cmd */ + + usalp->cmdname = "stop audio play"; + + return usal_cmd(usalp) >= 0 ? 0 : -1; +} + +int Play_atSCSI(SCSI *usalp, unsigned int from_sector, unsigned int sectors) +{ + register struct usal_cmd *scmd = usalp->scmd; + + fillbytes((caddr_t)scmd, sizeof(*scmd), '\0'); + scmd->addr = NULL; + scmd->size = 0; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G1_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g1_cdb.cmd = 0x47; + scmd->cdb.g1_cdb.lun = usal_lun(usalp); + scmd->cdb.g1_cdb.addr[1] = (from_sector + 150) / (60*75); + scmd->cdb.g1_cdb.addr[2] = ((from_sector + 150) / 75) % 60; + scmd->cdb.g1_cdb.addr[3] = (from_sector + 150) % 75; + scmd->cdb.g1_cdb.res6 = (from_sector + 150 + sectors) / (60*75); + scmd->cdb.g1_cdb.count[0] = ((from_sector + 150 + sectors) / 75) % 60; + scmd->cdb.g1_cdb.count[1] = (from_sector + 150 + sectors) % 75; + + if (usalp->verbose) fprintf(stderr, "\nplay sectors..."); + /* do the scsi cmd */ + + usalp->cmdname = "play sectors"; + + return usal_cmd(usalp) >= 0 ? 0 : -1; +} + +static caddr_t scsibuffer; /* page aligned scsi transfer buffer */ + +void init_scsibuf(SCSI *scsp, unsigned amt); + +void init_scsibuf(SCSI *usalp, unsigned amt) +{ + if (scsibuffer != NULL) { + fprintf(stderr, "the SCSI transfer buffer has already been allocated!\n"); + exit(SETUPSCSI_ERROR); + } + scsibuffer = usal_getbuf(usalp, amt); + if (scsibuffer == NULL) { + fprintf(stderr, "could not get SCSI transfer buffer!\n"); + exit(SETUPSCSI_ERROR); + } +} diff --git a/icedax/scsi_cmds.h b/icedax/scsi_cmds.h new file mode 100644 index 0000000..d82d1c9 --- /dev/null +++ b/icedax/scsi_cmds.h @@ -0,0 +1,71 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)scsi_cmds.h 1.11 03/03/02 Copyright 1998,1999 Heiko Eissfeldt */ +/* header file for scsi_cmds.c */ + +extern unsigned char *cmd; +struct TOC; +int SCSI_emulated_ATAPI_on(SCSI *usalp); +unsigned char *Inquiry(SCSI *usalp); +int TestForMedium(SCSI *usalp); +void SpeedSelectSCSIMMC(SCSI *usalp, unsigned speed); +void SpeedSelectSCSIYamaha(SCSI *usalp, unsigned speed); +void SpeedSelectSCSISony(SCSI *usalp, unsigned speed); +void SpeedSelectSCSIPhilipsCDD2600(SCSI *usalp, unsigned speed); +void SpeedSelectSCSINEC(SCSI *usalp, unsigned speed); +void SpeedSelectSCSIToshiba(SCSI *usalp, unsigned speed); +subq_chnl *ReadSubQSCSI(SCSI *usalp, unsigned char sq_format, + unsigned char ltrack); +subq_chnl *ReadSubChannelsSony(SCSI *usalp, unsigned lSector); +subq_chnl *ReadSubChannelsFallbackMMC(SCSI *usalp, unsigned lSector); +subq_chnl *ReadStandardSub(SCSI *usalp, unsigned lSector); +int ReadCddaMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +int ReadCdda12Matsushita(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +int ReadCdda12(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SecorBurstVal); +int ReadCdda10(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SecorBurstVal); +int ReadStandard(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SctorBurstVal); +int ReadStandardData(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SctorBurstVal); +int ReadCddaFallbackMMC(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SctorBurstVal); +int ReadCddaSubSony(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +int ReadCddaSub96Sony(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +int ReadCddaSubMMC12(SCSI *usalp, UINT4 *p, unsigned lSector, + unsigned SectorBurstVal); +unsigned ReadTocSony(SCSI *usalp); +unsigned ReadTocMMC(SCSI *usalp); +unsigned ReadTocSCSI(SCSI *usalp); +unsigned ReadFirstSessionTOCSony(SCSI *usalp); +unsigned ReadFirstSessionTOCMMC(SCSI *usalp); +void ReadTocTextSCSIMMC(SCSI *usalp); +int Play_atSCSI(SCSI *usalp, unsigned int from_sector, unsigned int sectors); +int StopPlaySCSI(SCSI *usalp); +void EnableCddaModeSelect(SCSI *usalp, int fAudioMode, unsigned uSectorsize); +int set_sectorsize(SCSI *usalp, unsigned int secsize); +unsigned int +get_orig_sectorsize(SCSI *usalp, unsigned char *m4, unsigned char *m10, + unsigned char *m11); +int heiko_mmc(SCSI *usalp); +void init_scsibuf(SCSI *usalp, unsigned amt); +int myscsierr(SCSI *usalp); + +extern int accepts_fua_bit; +extern unsigned char density; +extern unsigned char orgmode4; +extern unsigned char orgmode10, orgmode11; + diff --git a/icedax/semshm.c b/icedax/semshm.c new file mode 100644 index 0000000..6c6edc7 --- /dev/null +++ b/icedax/semshm.c @@ -0,0 +1,473 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* + * Copyright 1998-2002 Heiko Eissfeldt + */ + +#define IPCTST +#undef IPCTST +/* -------------------------------------------------------------------- */ +/* semshm.c */ +/* -------------------------------------------------------------------- */ +/* int seminstall(key,amount) */ +/* int semrequest(semid,semnum) */ +/* int semrelease(semid,semnum) */ +/* -------------------------------------------------------------------- */ + +#include "config.h" + +#if !defined(HAVE_SMMAP) && !defined(HAVE_USGSHM) && !defined(HAVE_DOSALLOCSHAREDMEM) && !defined(HAVE_AREAS) +#undef FIFO /* We cannot have a FIFO on this platform */ +#endif + +#if !defined(USE_MMAP) && !defined(USE_USGSHM) +#define USE_MMAP +#endif + +#if !defined HAVE_SMMAP && defined FIFO +# undef USE_MMAP +# define USE_USGSHM /* SYSV shared memory is the default */ +#endif + +#ifdef USE_MMAP /* Only want to have one implementation */ +# undef USE_USGSHM /* mmap() is preferred */ +#endif + +#ifdef HAVE_DOSALLOCSHAREDMEM +# undef USE_MMAP +# undef USE_USGSHM +# define USE_OS2SHM +# undef USE_BEOS_AREAS +#endif + +#ifdef HAVE_AREAS +# undef USE_MMAP +# undef USE_USGSHM +# undef USE_OS2SHM +# define USE_BEOS_AREAS +#endif + +#include <stdio.h> +#include <stdxlib.h> +#include <unixstd.h> +#include <fctldefs.h> +#include <errno.h> +#include <standard.h> +#include <schily.h> + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#endif + +#if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1) +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#endif + +#ifdef USE_MMAP +#if defined(HAVE_SMMAP) && defined(USE_MMAP) +#include <mmapdefs.h> +#endif +#endif + +#include <usal/scsitransp.h> + +#ifdef USE_BEOS_AREAS +#include <be/kernel/OS.h> +#endif + +#include "mytype.h" +#include "interface.h" +#include "ringbuff.h" +#include "global.h" +#include "exitcodes.h" +#include "semshm.h" + +#ifdef DEBUG_SHM +char *start_of_shm; +char *end_of_shm; +#endif + +int flush_buffers(void); + + +/*------ Semaphore interfacing (for special cases only) ----------*/ +/*------ Synchronization with pipes is preferred ----------*/ + +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) + +int sem_id; +static int seminstall(key_t key, int amount); + +static int seminstall(key_t key, int amount) +{ + int ret_val; + int semflag; + + semflag = IPC_CREAT | 0600; +#ifdef IPCTST + fprintf(stderr,"seminstall: key: %d, #sems %d, flags %4x\n", + key,amount,semflag); +#endif + ret_val = semget(key,amount,semflag); + if ( ret_val == -1 ) + { + fprintf(stderr,"semget: (Key %lx, #%d) failed: ", + (long)key,amount); + perror(""); + } + return ret_val; +} + +/*-----------------------------------------------------------------*/ +int semrequest(int semid, int semnum) +{ + struct sembuf sops[1]; + int ret_val; + +#ifdef IPCTST + fprintf(stderr,"pid %d, ReQuest id:num %d:%d\n",getpid(),semid,semnum); +#endif + sops[0].sem_op = -1; + sops[0].sem_num = (short) semnum; + sops[0].sem_flg = 0; + + do { + errno = 0; + ret_val = semop(semid,sops,1); + if (ret_val == -1 && errno != EAGAIN && errno != EINTR) + { + fprintf(stderr,"Request Sema %d(%d) failed: ",semid,semnum); + perror(""); + } + } while (errno == EAGAIN || errno == EINTR); + return(ret_val); +} + +/*-----------------------------------------------------------------*/ +int semrelease(int semid, int semnum, int amount) +{ + struct sembuf sops[1]; + int ret_val; + +#ifdef IPCTST + fprintf(stderr,"%d RL %d:%d\n",getpid(),semid,semnum); +#endif + sops[0].sem_op = amount; + sops[0].sem_num = (short) semnum; + sops[0].sem_flg = 0; + ret_val = semop(semid,sops,1); + if ( ret_val == -1 && errno != EAGAIN) + { + fprintf(stderr,"Release Sema %d(%d) failed: ",semid,semnum); + perror(""); + } + return(ret_val); +} + +int flush_buffers() +{ + return 0; +} +#else +/*------ Synchronization with pipes ----------*/ +int pipefdp2c[2]; +int pipefdc2p[2]; + +void init_pipes() +{ + if (pipe(pipefdp2c) < 0) { + perror("cannot create pipe parent to child"); + exit(PIPE_ERROR); + } + if (pipe(pipefdc2p) < 0) { + perror("cannot create pipe child to parent"); + exit(PIPE_ERROR); + } +} + +void init_parent() +{ + close(pipefdp2c[0]); + close(pipefdc2p[1]); +} + +void init_child() +{ + close(pipefdp2c[1]); + close(pipefdc2p[0]); +} + +int semrequest(int dummy, int semnum) +{ + + if (semnum == FREE_SEM /* 0 */) { + int retval; + if ((*total_segments_read) - (*total_segments_written) >= global.buffers) { + /* parent/reader waits for freed buffers from the child/writer */ + *parent_waits = 1; + retval = read(pipefdp2c[0], &dummy, 1) != 1; + return retval; + } + } else { + int retval; + + if ((*total_segments_read) == (*total_segments_written)) { + /* child/writer waits for defined buffers from the parent/reader */ + *child_waits = 1; + retval = read(pipefdc2p[0], &dummy, 1) != 1; + return retval; + } + } + return 0; +} + +/* ARGSUSED */ +int semrelease(int dummy, int semnum, int amount) +{ + if (semnum == FREE_SEM /* 0 */) { + if (*parent_waits == 1) { + int retval; + /* child/writer signals freed buffer to the parent/reader */ + *parent_waits = 0; + retval = write(pipefdp2c[1], "12345678901234567890", amount) != amount; + return retval; + } + } else { + if (*child_waits == 1) { + int retval; + /* parent/reader signals defined buffers to the child/writer */ + *child_waits = 0; + retval = write(pipefdc2p[1], "12345678901234567890", amount) != amount; + return retval; + } + } + return 0; +} + +int flush_buffers() +{ + if ((*total_segments_read) > (*total_segments_written)) { + return write(pipefdc2p[1], "1", 1) != 1; + } + return 0; +} + +#endif + +/*------------------- Shared memory interfacing -----------------------*/ + + + +#if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1) +static int shm_request_nommap(int size, unsigned char **memptr); + +/* request a shared memory block */ +static int shm_request_nommap(int size, unsigned char **memptr) +{ + int ret_val; + int shmflag; + int SHMEM_ID; + int cmd; + struct shmid_ds buf; + key_t key = IPC_PRIVATE; + + shmflag = IPC_CREAT | 0600; + ret_val = shmget(key,size,shmflag); + if ( ret_val == -1 ) + { + perror("shmget"); + return -1; + } + + SHMEM_ID = ret_val; + cmd = IPC_STAT; + ret_val = shmctl(SHMEM_ID,cmd,&buf); +#ifdef IPCTST + fprintf(stderr, "%d: shmctl STAT= %d, SHM_ID: %d, key %ld cuid %d cgid %d mode %3o size %d\n", + getpid(),ret_val,SHMEM_ID, + (long) buf.shm_perm.key,buf.shm_perm.cuid,buf.shm_perm.cgid, + buf.shm_perm.mode,buf.shm_segsz); +#endif + + *memptr = (unsigned char *) shmat(SHMEM_ID, NULL, 0); + if (*memptr == (unsigned char *) -1) { + *memptr = NULL; + fprintf( stderr, "shmat failed for %d bytes\n", size); + return -1; + } + + if (shmctl(SHMEM_ID, IPC_RMID, 0) < 0) { + fprintf( stderr, "shmctl failed to detach shared memory segment\n"); + return -1; + } + + +#ifdef DEBUG_SHM + start_of_shm = *memptr; + end_of_shm = (char *)(*memptr) + size; + + fprintf(stderr, "Shared memory from %p to %p (%d bytes)\n", start_of_shm, end_of_shm, size); +#endif + return 0; +} + + +#endif /* #if defined(HAVE_SHMAT) && (HAVE_SHMAT == 1) */ + + +static int shm_request(int size, unsigned char **memptr); + +#ifdef USE_USGSHM +/* request a shared memory block */ +static int shm_request(int size, unsigned char **memptr) +{ + return shm_request_nommap(size, memptr); +} +#endif + +/* release semaphores */ +void free_sem(void); +void free_sem() +{ +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) + int mycmd; + union my_semun unused_arg; + + mycmd = IPC_RMID; + + /* HP-UX warns here, but 'unused_arg' is not used for this operation */ + /* This warning is difficult to avoid, since the structure of the union + * generally is not known (os dependent). So we cannot initialize it + * properly. + */ + semctl(sem_id,0,mycmd,unused_arg); +#endif + +} + +#ifdef USE_MMAP +#if defined(HAVE_SMMAP) + +int shm_id; +/* request a shared memory block */ +static int shm_request(int size, unsigned char **memptr) +{ + int f; + char *addr; + +#ifdef MAP_ANONYMOUS /* HP/UX */ + f = -1; + addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, f, 0); +#else + if ((f = open("/dev/zero", O_RDWR)) < 0) + comerr("Cannot open '/dev/zero'.\n"); + addr = mmap(0, mmap_sizeparm(size), PROT_READ|PROT_WRITE, MAP_SHARED, f, 0); +#endif + + if (addr == (char *)-1) { +#if defined HAVE_SHMAT && (HAVE_SHMAT == 1) + unsigned char *address; + /* fallback to alternate method */ + if (0 != shm_request_nommap(size, &address) || (addr = (char *)address) == NULL) +#endif + comerr("Cannot get mmap for %d Bytes on /dev/zero.\n", size); + } + close(f); + + if (memptr != NULL) + *memptr = (unsigned char *)addr; + + return 0; +} +#endif /* HAVE_SMMAP */ +#endif /* USE_MMAP */ + +#ifdef USE_OS2SHM + +/* request a shared memory block */ +static int shm_request(int size, unsigned char **memptr) +{ + char *addr; + + /* + * The OS/2 implementation of shm (using shm.dll) limits the size of one + * memory segment to 0x3fa000 (aprox. 4MBytes). Using OS/2 native API we + * no such restriction so I decided to use it allowing fifos of arbitrary size + */ + if(DosAllocSharedMem(&addr,NULL,size,0X100L | 0x1L | 0x2L | 0x10L)) + comerr("DosAllocSharedMem() failed\n"); + + if (memptr != NULL) + *memptr = (unsigned char *)addr; + + return 0; +} +#endif + +#ifdef USE_BEOS_AREAS + +/* request a shared memory block */ +static int shm_request(int size, unsigned char **memptr) +{ + char *addr; + area_id aid; /* positive id of the mapping */ + + /* round up to a multiple of pagesize. */ + size = ((size - 1) | (B_PAGE_SIZE - 1)) + 1; + /* + * request a shared memory area in user space. + */ + aid = create_area(AREA_NAME, /* name of the mapping */ + (void *)&addr, /* address of shared memory */ + B_ANY_ADDRESS, /* type of address constraint */ + size, /* size in bytes (multiple of pagesize) */ + B_NO_LOCK, /* B_FULL_LOCK, */ /* memory locking */ + B_READ_AREA | B_WRITE_AREA); /* read and write permissions */ + + if (aid < B_OK) + comerrno(aid, "create_area() failed\n"); + + if (memptr != NULL) + *memptr = (unsigned char *)addr; + + return 0; +} +#endif + +void *request_shm_sem(unsigned amount_of_sh_mem, unsigned char **pointer) +{ +#if defined(HAVE_SEMGET) && defined(USE_SEMAPHORES) + /* install semaphores for double buffer usage */ + sem_id = seminstall(IPC_PRIVATE,2); + if ( sem_id == -1 ) { + perror("seminstall"); + exit(SEMAPHORE_ERROR); + } + +#endif + +#if defined(FIFO) + if (-1 == shm_request(amount_of_sh_mem, pointer)) { + perror("shm_request"); + exit(SHMMEM_ERROR); + } + + return *pointer; +#else + return NULL; +#endif +} diff --git a/icedax/semshm.h b/icedax/semshm.h new file mode 100644 index 0000000..2007f82 --- /dev/null +++ b/icedax/semshm.h @@ -0,0 +1,43 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)semshm.h 1.3 03/08/29 Copyright 1998,1999 Heiko Eissfeldt */ +#undef DEBUG_SHM +#ifdef DEBUG_SHM +extern char *start_of_shm; +extern char *end_of_shm; +#endif + +#define FREE_SEM 0 +#define DEF_SEM 1 + +#if defined (HAVE_SEMGET) && defined(USE_SEMAPHORES) +extern int sem_id; +#else +#define sem_id 42 /* nearly any other number would do it too */ +void init_pipes(void); +void init_parent(void); +void init_child(void); +#endif + + +#ifdef HAVE_AREAS +/* the name of the shared memory mapping for the FIFO under BeOS. */ +#define AREA_NAME "shmfifo" +#endif + +void free_sem(void); +int semrequest(int semid, int semnum); +int semrelease(int semid, int semnum, int amount); +int flush_buffers(void); +void * request_shm_sem(unsigned amount_of_sh_mem, unsigned char **pointer); + diff --git a/icedax/setuid.c b/icedax/setuid.c new file mode 100644 index 0000000..7f3e63c --- /dev/null +++ b/icedax/setuid.c @@ -0,0 +1,332 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)setuid.c 1.11 06/02/19 Copyright 1998,1999,2004 Heiko Eissfeldt, Copyright 2004-2006 J. Schilling */ +/* Security functions by zblaxell + + If these functions fail, it is because there was an installation error + or a programming error, and we can't be sure about what privileges + we do or do not have. This means we might not be able to recover + the privileges we need to fix anything that may be broken (e.g. the + CDDA state of some interface types), and we may in fact do something + quite dangerous (like write to the WAV file as root). + + In any case, it is unsafe to do anything but exit *now*. Ideally we'd + kill -9 our process group too, just to be sure. Root privileges are not + something you want floating around at random in user-level applications. + + If any signal handlers or child processes are introduced into this + program, it will be necessary to call dontneedroot() or neverneedroot() + on entry, respectively; otherwise, it will be possible to trick + the program into executing the signal handler or child process with + root privileges by sending signals at the right time. + */ + +#include "config.h" +#include <unixstd.h> +#include <stdio.h> +#include <stdxlib.h> + +#include "exitcodes.h" +#include "setuid.h" + +/*#undef DEBUG*/ +/*#define DEBUG*/ + +/* True at return from initsecurity */ +static uid_t real_uid = (uid_t) (-1); +static uid_t effective_uid = (uid_t) (-1); +static gid_t real_gid = (gid_t) (-1); +static gid_t effective_gid = (gid_t) (-1); + +/* Run this at the beginning of the program to initialize this code and + to drop privileges before someone uses them to shoot us in the foot. + Do not pass(go), do not dollars += 200. */ + +void initsecurity() +{ + int leffective_uid; + + alarm(0); /* can be inherited from parent process */ + real_uid = getuid(); + leffective_uid = geteuid(); + if ((int) real_uid != leffective_uid && leffective_uid != 0) { /* sanity check */ + fprintf(stderr, "Warning: setuid but not to root (uid=%ld, euid=%d)\n", (long) real_uid, leffective_uid); + fprintf(stderr, "Dropping setuid privileges now.\n"); + neverneedroot(); + } else { + effective_uid = leffective_uid; + } + real_gid = getgid(); + effective_gid = getegid(); + dontneedroot(); + dontneedgroup(); +} + +/* Temporarily gain root privileges. */ + +#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID) && defined SCO +/* SCO seems to lack the prototypes... */ +int seteuid(uid_t euid); +int setegid(gid_t guid); +#endif + +void needroot(int necessary) +{ +#ifdef DEBUG + fprintf(stderr, "call to needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif + if (effective_uid) { + if (necessary) { + fprintf(stderr, "Fatal error: require root privilege but not setuid root.\n"); + exit(PERM_ERROR); + } else + return; + } + if (real_uid == (uid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + + if (geteuid() == 0) return; /* nothing to do */ + +#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID) + if (seteuid(effective_uid)) { + perror("seteuid in needroot()"); + exit(PERM_ERROR); + } +#else +#if defined (HAVE_SETREUID) + if (setreuid(real_uid, effective_uid)) { + perror("setreuid in needroot()"); + exit(PERM_ERROR); + } +#endif +#endif + if (geteuid() != 0 && necessary) { + fprintf(stderr, "Fatal error: did not get root privilege.\n"); + exit(PERM_ERROR); + } +#ifdef DEBUG + fprintf(stderr, "exit of needroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif +} + +/* Temporarily drop root privileges. */ + +void dontneedroot() +{ +#ifdef DEBUG + fprintf(stderr, "call to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif + if (real_uid == (uid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + if (effective_uid) + return; + if (geteuid() != 0) return; /* nothing to do */ + +#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEUID) + if (seteuid(real_uid)) { + perror("seteuid in dontneedroot()"); + exit(PERM_ERROR); + } +#else +#if defined (HAVE_SETREUID) + if (setreuid(effective_uid, real_uid)) { + perror("setreuid in dontneedroot()"); + exit(PERM_ERROR); + } +#endif +#endif + if (geteuid() != real_uid) { + fprintf(stderr, "Fatal error: did not drop root privilege.\n"); +#ifdef DEBUG + fprintf(stderr, "in to dontneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif + exit(PERM_ERROR); + } +} + +/* Permanently drop root privileges. */ + +void neverneedroot() +{ +#ifdef DEBUG + fprintf(stderr, "call to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif + if (real_uid == (uid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + if (geteuid() == effective_uid) { +#if defined (HAVE_SETUID) + if (setuid(real_uid)) { + perror("setuid in neverneedroot()"); + exit(PERM_ERROR); + } +#endif + } +#if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */ + else { +#if defined (HAVE_SETUID) + if (setuid(real_uid)) { + perror("setuid in neverneedroot()"); + exit(PERM_ERROR); + } +#endif + } +#endif + if (geteuid() != real_uid || getuid() != real_uid) { + fprintf(stderr, "Fatal error: did not drop root privilege.\n"); +#ifdef DEBUG + fprintf(stderr, "in to neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif + exit(PERM_ERROR); + } + effective_uid = real_uid; +#ifdef DEBUG + fprintf(stderr, "exit of neverneedroot (_euid_=%d, uid=%d), current=%d/%d, pid=%d\n", + effective_uid, real_uid, geteuid(), getuid(), getpid()); +#endif +} + +/* Temporarily gain group privileges. */ + +void needgroup(int necessary) +{ +#ifdef DEBUG + fprintf(stderr, "call to needgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n", + effective_gid, real_gid, getegid(), getgid(), getpid()); +#endif + if (real_gid == (gid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + + if (getegid() == effective_gid) return; /* nothing to do */ + +#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID) + if (setegid(effective_gid)) { + perror("setegid in needgroup()"); + exit(PERM_ERROR); + } +#else +#if defined (HAVE_SETREGID) + if (setregid(real_gid, effective_gid)) { + perror("setregid in needgroup()"); + exit(PERM_ERROR); + } +#endif +#endif + if (necessary && getegid() != effective_gid) { + fprintf(stderr, "Fatal error: did not get group privilege.\n"); + exit(PERM_ERROR); + } +} + +/* Temporarily drop group privileges. */ + +void dontneedgroup() +{ +#ifdef DEBUG + fprintf(stderr, "call to dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n", + effective_gid, real_gid, getegid(), getgid(), getpid()); +#endif + if (real_gid == (gid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + if (getegid() != effective_gid) return; /* nothing to do */ +#if defined _POSIX_SAVED_IDS && defined (HAVE_SETEGID) + if (setegid(real_gid)) { + perror("setegid in dontneedgroup()"); + exit(PERM_ERROR); + } +#else +#if defined (HAVE_SETREGID) + if (setregid(effective_gid, real_gid)) { + perror("setregid in dontneedgroup()"); + exit(PERM_ERROR); + } +#endif +#endif + if (getegid() != real_gid) { + fprintf(stderr, "Fatal error: did not drop group privilege.\n"); + exit(PERM_ERROR); + } +#ifdef DEBUG + fprintf(stderr, "exit if dontneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n", + effective_gid, real_gid, getegid(), getgid(), getpid()); +#endif +} + +/* Permanently drop group privileges. */ + +void neverneedgroup() +{ +#ifdef DEBUG + fprintf(stderr, "call to neverneedgroup (egid=%d, gid=%d), current=%d/%d, pid=%d\n", + effective_gid, real_gid, getegid(), getgid(), getpid()); +#endif + if (real_gid == (gid_t) (-1)) { + fprintf(stderr, "Fatal error: initsecurity() not called.\n"); + exit(INTERNAL_ERROR); + } + if (getegid() == effective_gid) { +#if defined (HAVE_SETGID) + if (setgid(real_gid)) { + perror("setgid in neverneedgroup()"); + exit(PERM_ERROR); + } +#endif + } +#if defined(__FreeBSD__) || defined(__DragonFly__) /* XXX this is a big hack and and not a permanent solution */ + else { +#if defined (HAVE_SETGID) + if (setgid(real_gid)) { + perror("setgid in neverneedgroup()"); + exit(PERM_ERROR); + } +#endif + } +#endif + if (getegid() != real_gid || getgid() != real_gid) { + fprintf(stderr, "Fatal error: did not drop group privilege.\n"); + exit(PERM_ERROR); + } + effective_gid = real_gid; +} + +#if defined (HPUX) +int seteuid(uid_t uid) +{ + return setresuid(-1, uid, -1); +} + +int setreuid(uid_t uid1, uid_t uid2) +{ + return setresuid(uid2, uid2, uid1 == uid2 ? uid2 : 0); +} + +int setregid(gid_t gid1, gid_t gid2) +{ + return setresgid(gid2, gid2, gid1 == gid2 ? gid2 : 0); +} +#endif diff --git a/icedax/setuid.h b/icedax/setuid.h new file mode 100644 index 0000000..48a8ae0 --- /dev/null +++ b/icedax/setuid.h @@ -0,0 +1,31 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)setuid.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +/* Security functions */ +void initsecurity(void); + +void needroot(int necessary); +void dontneedroot(void); +void neverneedroot(void); + +void needgroup(int necessary); +void dontneedgroup(void); +void neverneedgroup(void); + +#if defined (HPUX) +#define HAVE_SETREUID +#define HAVE_SETREGID +int seteuid(uid_t uid); +int setreuid(uid_t uid1, uid_t uid2); +int setregid(gid_t gid1, gid_t gid2); +#endif diff --git a/icedax/sha.h b/icedax/sha.h new file mode 100644 index 0000000..ca5e4a0 --- /dev/null +++ b/icedax/sha.h @@ -0,0 +1,102 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sha.h 1.4 03/06/28 Copyright 1998,1999 Heiko Eissfeldt */ +/*____________________________________________________________________________ +// +// CD Index - The Internet CD Index +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id: sha.h,v 1.1.1.2 1999/04/29 00:53:34 marc Exp $ +//____________________________________________________________________________ +*/ +#ifndef SHA_H +#define SHA_H + +/* NIST Secure Hash Algorithm */ +/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */ +/* from Peter C. Gutmann's implementation as found in */ +/* Applied Cryptography by Bruce Schneier */ + +/* This code is in the public domain */ + +/* Useful defines & typedefs */ + +typedef unsigned char BYTE; /* 8-bit quantity */ +typedef unsigned long ULONG; /* 32-or-more-bit quantity */ + +#define SHA_BLOCKSIZE 64 +#define SHA_DIGESTSIZE 20 + +typedef struct { + ULONG digest[5]; /* message digest */ + ULONG count_lo, count_hi; /* 64-bit bit count */ + BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ + int local; /* unprocessed amount in data */ +} SHA_INFO; + +void sha_init(SHA_INFO *); +void sha_update(SHA_INFO *, BYTE *, int); +void sha_final(unsigned char [20], SHA_INFO *); + +#ifdef SHA_FOR_C + +#include <mconfig.h> +#include <stdxlib.h> +#include <stdio.h> + +void sha_stream(unsigned char [20], SHA_INFO *, FILE *); +void sha_print(unsigned char [20]); +char *sha_version(void); +#endif /* SHA_FOR_C */ + +#define SHA_VERSION 1 + +#ifndef WIN32 +#ifdef WORDS_BIGENDIAN +# if SIZEOF_UNSIGNED_LONG_INT == 4 +# define SHA_BYTE_ORDER 4321 +# else +# if SIZEOF_UNSIGNED_LONG_INT == 8 +# define SHA_BYTE_ORDER 87654321 +# endif +# endif +#else +# if SIZEOF_UNSIGNED_LONG_INT == 4 +# define SHA_BYTE_ORDER 1234 +# else +# if SIZEOF_UNSIGNED_LONG_INT == 8 +# define SHA_BYTE_ORDER 12345678 +# endif +# endif +#endif + +#else + +#define SHA_BYTE_ORDER 1234 + +#endif + +#endif /* SHA_H */ diff --git a/icedax/sha_func.c b/icedax/sha_func.c new file mode 100644 index 0000000..06b55ac --- /dev/null +++ b/icedax/sha_func.c @@ -0,0 +1,376 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sha_func.c 1.3 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +/*____________________________________________________________________________ +// +// CD Index - The Internet CD Index +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id: sha_func.c,v 1.2 1999/06/04 14:10:07 marc Exp $ +//____________________________________________________________________________ +*/ +/* NIST Secure Hash Algorithm */ + +/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */ +/* from Peter C. Gutmann's implementation as found in */ +/* Applied Cryptography by Bruce Schneier */ +/* Further modifications to include the "UNRAVEL" stuff, below */ +/* portability modifications Heiko Eissfeldt */ + +/* This code is in the public domain */ + +#include "config.h" +#include <strdefs.h> +#include "sha.h" + +/* UNRAVEL should be fastest & biggest */ +/* UNROLL_LOOPS should be just as big, but slightly slower */ +/* both undefined should be smallest and slowest */ + +#define UNRAVEL +/* #define UNROLL_LOOPS */ + +/* SHA f()-functions */ + +#define f1(x,y,z) ((x & y) | (~x & z)) +#define f2(x,y,z) (x ^ y ^ z) +#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) +#define f4(x,y,z) (x ^ y ^ z) + +/* SHA constants */ + +#define CONST1 ULONG_C(0x5a827999) +#define CONST2 ULONG_C(0x6ed9eba1) +#define CONST3 ULONG_C(0x8f1bbcdc) +#define CONST4 ULONG_C(0xca62c1d6) + +/* truncate to 32 bits -- should be a null op on 32-bit machines */ + +#define T32(x) ((x) & ULONG_C(0xffffffff)) + +/* 32-bit rotate */ + +#define R32(x,n) T32(((x << n) | (x >> (32 - n)))) + +/* the generic case, for when the overall rotation is not unraveled */ + +#define FG(n) \ + T = T32(R32(A,5) + CONCAT(f,n(B,C,D)) + E + *WP++ + CONCAT(CONST,n)); \ + E = D; D = C; C = R32(B,30); B = A; A = T + +/* specific cases, for when the overall rotation is unraveled */ + +#define FA(n) \ + T = T32(R32(A,5) + CONCAT(f,n(B,C,D)) + E + *WP++ + CONCAT(CONST,n)); B = R32(B,30) + +#define FB(n) \ + E = T32(R32(T,5) + CONCAT(f,n(A,B,C)) + D + *WP++ + CONCAT(CONST,n)); A = R32(A,30) + +#define FC(n) \ + D = T32(R32(E,5) + CONCAT(f,n(T,A,B)) + C + *WP++ + CONCAT(CONST,n)); T = R32(T,30) + +#define FD(n) \ + C = T32(R32(D,5) + CONCAT(f,n(E,T,A)) + B + *WP++ + CONCAT(CONST,n)); E = R32(E,30) + +#define FE(n) \ + B = T32(R32(C,5) + CONCAT(f,n(D,E,T)) + A + *WP++ + CONCAT(CONST,n)); D = R32(D,30) + +#define FT(n) \ + A = T32(R32(B,5) + CONCAT(f,n(C,D,E)) + T + *WP++ + CONCAT(CONST,n)); C = R32(C,30) + +/* do SHA transformation */ + +static void sha_transform(SHA_INFO *sha_info); + +static void sha_transform(SHA_INFO *sha_info) +{ + int i; + BYTE *dp; + ULONG T, A, B, C, D, E, W[80], *WP; + + dp = sha_info->data; + +/* +the following makes sure that at least one code block below is +traversed or an error is reported, without the necessity for nested +preprocessor if/else/endif blocks, which are a great pain in the +nether regions of the anatomy... +*/ +#undef SWAP_DONE + +#if (SHA_BYTE_ORDER == 1234) +#define SWAP_DONE + for (i = 0; i < 16; ++i) { + T = *((ULONG *) dp); + dp += 4; + W[i] = ((T << 24) & ULONG_C(0xff000000)) | ((T << 8) & ULONG_C(0x00ff0000)) | + ((T >> 8) & ULONG_C(0x0000ff00)) | ((T >> 24) & ULONG_C(0x000000ff)); + } +#endif /* SHA_BYTE_ORDER == 1234 */ + +#if (SHA_BYTE_ORDER == 4321) +#define SWAP_DONE + for (i = 0; i < 16; ++i) { + T = *((ULONG *) dp); + dp += 4; + W[i] = T32(T); + } +#endif /* SHA_BYTE_ORDER == 4321 */ + +#if (SHA_BYTE_ORDER == 12345678) +#define SWAP_DONE + for (i = 0; i < 16; i += 2) { + T = *((ULONG *) dp); + dp += 8; + W[i] = ((T << 24) & ULONG_C(0xff000000)) | ((T << 8) & ULONG_C(0x00ff0000)) | + ((T >> 8) & ULONG_C(0x0000ff00)) | ((T >> 24) & ULONG_C(0x000000ff)); + T >>= 32; + W[i+1] = ((T << 24) & ULONG_C(0xff000000)) | ((T << 8) & ULONG_C(0x00ff0000)) | + ((T >> 8) & ULONG_C(0x0000ff00)) | ((T >> 24) & ULONG_C(0x000000ff)); + } +#endif /* SHA_BYTE_ORDER == 12345678 */ + +#if (SHA_BYTE_ORDER == 87654321) +#define SWAP_DONE + for (i = 0; i < 16; i += 2) { + T = *((ULONG *) dp); + dp += 8; + W[i] = T32(T >> 32); + W[i+1] = T32(T); + } +#endif /* SHA_BYTE_ORDER == 87654321 */ + +#ifndef SWAP_DONE +error Unknown byte order -- you need to add code here +#endif /* SWAP_DONE */ + + for (i = 16; i < 80; ++i) { + W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; +#if (SHA_VERSION == 1) + W[i] = R32(W[i], 1); +#endif /* SHA_VERSION */ + } + A = sha_info->digest[0]; + B = sha_info->digest[1]; + C = sha_info->digest[2]; + D = sha_info->digest[3]; + E = sha_info->digest[4]; + WP = W; +#ifdef UNRAVEL + FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); + FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); + FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); + FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); + FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); + FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); + FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); + FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); + sha_info->digest[0] = T32(sha_info->digest[0] + E); + sha_info->digest[1] = T32(sha_info->digest[1] + T); + sha_info->digest[2] = T32(sha_info->digest[2] + A); + sha_info->digest[3] = T32(sha_info->digest[3] + B); + sha_info->digest[4] = T32(sha_info->digest[4] + C); +#else /* !UNRAVEL */ +#ifdef UNROLL_LOOPS + FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); + FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); + FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); + FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); + FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); + FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); + FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); + FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); +#else /* !UNROLL_LOOPS */ + for (i = 0; i < 20; ++i) { FG(1); } + for (i = 20; i < 40; ++i) { FG(2); } + for (i = 40; i < 60; ++i) { FG(3); } + for (i = 60; i < 80; ++i) { FG(4); } +#endif /* !UNROLL_LOOPS */ + sha_info->digest[0] = T32(sha_info->digest[0] + A); + sha_info->digest[1] = T32(sha_info->digest[1] + B); + sha_info->digest[2] = T32(sha_info->digest[2] + C); + sha_info->digest[3] = T32(sha_info->digest[3] + D); + sha_info->digest[4] = T32(sha_info->digest[4] + E); +#endif /* !UNRAVEL */ +} + +/* initialize the SHA digest */ + +void sha_init(SHA_INFO *sha_info); + +void sha_init(SHA_INFO *sha_info) +{ + sha_info->digest[0] = ULONG_C(0x67452301); + sha_info->digest[1] = ULONG_C(0xefcdab89); + sha_info->digest[2] = ULONG_C(0x98badcfe); + sha_info->digest[3] = ULONG_C(0x10325476); + sha_info->digest[4] = ULONG_C(0xc3d2e1f0); + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; +} + +/* update the SHA digest */ + +void sha_update(SHA_INFO *sha_info, BYTE *buffer, int count); + +void sha_update(SHA_INFO *sha_info, BYTE *buffer, int count) +{ + int i; + ULONG clo; + + clo = T32(sha_info->count_lo + ((ULONG) count << 3)); + if (clo < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo = clo; + sha_info->count_hi += (ULONG) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy(((BYTE *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + sha_transform(sha_info); + } else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + sha_transform(sha_info); + } + memcpy(sha_info->data, buffer, count); + sha_info->local = count; +} + +/* finish computing the SHA digest */ + +void sha_final(unsigned char digest[20], SHA_INFO *sha_info); + +void sha_final(unsigned char digest[20], SHA_INFO *sha_info) +{ + int count; + ULONG lo_bit_count, hi_bit_count; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((BYTE *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 8) { + memset(((BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); + sha_transform(sha_info); + memset((BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); + } else { + memset(((BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 8 - count); + } + sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff); + sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff); + sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff); + sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff); + sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff); + sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff); + sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff); + sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff); + sha_transform(sha_info); + digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); + digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); + digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); + digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); + digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); + digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); + digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); + digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); + digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); + digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); + digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); + digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); + digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); + digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); + digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); + digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); + digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); +} + +#ifdef SHA_FOR_C + +/* compute the SHA digest of a FILE stream */ + +#define BLOCK_SIZE 8192 + +void sha_stream(unsigned char digest[20], SHA_INFO *sha_info, FILE *fin); + +void sha_stream(unsigned char digest[20], SHA_INFO *sha_info, FILE *fin) +{ + int i; + BYTE data[BLOCK_SIZE]; + + sha_init(sha_info); + while ((i = fread(data, 1, BLOCK_SIZE, fin)) > 0) { + sha_update(sha_info, data, i); + } + sha_final(digest, sha_info); +} + +/* print a SHA digest */ + +void sha_print(unsigned char digest[20]); + +void sha_print(unsigned char digest[20]) +{ + int i, j; + + for (j = 0; j < 5; ++j) { + for (i = 0; i < 4; ++i) { + printf("%02x", *digest++); + } + printf("%c", (j < 4) ? ' ' : '\n'); + } +} + +char *sha_version(void); + +char *sha_version() +{ +#if (SHA_VERSION == 1) + static char *version = "SHA-1"; +#else + static char *version = "SHA"; +#endif + return(version); +} + +#endif /* SHA_FOR_C */ diff --git a/icedax/sndconfig.c b/icedax/sndconfig.c new file mode 100644 index 0000000..ac446fc --- /dev/null +++ b/icedax/sndconfig.c @@ -0,0 +1,607 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sndconfig.c 1.17 04/08/03 Copyright 1998-2004 Heiko Eissfeldt */ +/* os dependent functions */ +#include "config.h" +#include <stdio.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <fctldefs.h> +#include <unixstd.h> +#include <sys/ioctl.h> + +#if !defined __CYGWIN32__ +# include <timedefs.h> +#endif +#include <schily.h> + + +/* soundcard setup */ +#if defined (HAVE_SOUNDCARD_H) || defined (HAVE_LINUX_SOUNDCARD_H) || defined (HAVE_SYS_SOUNDCARD_H) || defined (HAVE_MACHINE_SOUNDCARD_H) +# if defined (HAVE_SOUNDCARD_H) +# include <soundcard.h> +# else +# if defined (HAVE_MACHINE_SOUNDCARD_H) +# include <machine/soundcard.h> +# else +# if defined (HAVE_SYS_SOUNDCARD_H) +# include <sys/soundcard.h> +# else +# if defined (HAVE_LINUX_SOUNDCARD_H) +# include <linux/soundcard.h> +# endif +# endif +# endif +# endif +#endif + +#include "mytype.h" +#include "byteorder.h" +#include "lowlevel.h" +#include "global.h" +#include "sndconfig.h" + +#ifdef ECHO_TO_SOUNDCARD +# if defined(__CYGWIN32__) +# include <windows.h> +# include "mmsystem.h" +# endif + +# if defined(__EMX__) +# define INCL_DOS +# define INCL_OS2MM +# include <os2.h> +# define PPFN _PPFN +# include <os2me.h> +# undef PPFN +static unsigned long DeviceID; + +# define FRAGMENTS 2 +/* playlist-structure */ +typedef struct { + ULONG ulCommand; + ULONG ulOperand1, ulOperand2, ulOperand3; +} PLAYLISTSTRUCTURE; + +static PLAYLISTSTRUCTURE PlayList[FRAGMENTS + 1]; +static unsigned BufferInd; +# endif /* defined __EMX__ */ + +static char snd_device[200] = SOUND_DEV; + +int set_snd_device(const char *devicename) +{ + strncpy(snd_device, devicename, sizeof(snd_device)); + return 0; +} + +# if defined __CYGWIN32__ +static HWAVEOUT DeviceID; +# define WAVEHDRS 3 +static WAVEHDR wavehdr[WAVEHDRS]; +static unsigned lastwav = 0; + +static int check_winsound_caps(int bits, double rate, int channels); + +static int check_winsound_caps(int bits, double rate, int channels) +{ + int result = 0; + + WAVEOUTCAPS caps; + + /* get caps */ + if (waveOutGetDevCaps(0, &caps, sizeof(caps))) { + fprintf(stderr, "cannot get soundcard capabilities!\n"); + return 1; + } + + /* check caps */ + if ((bits == 8 && !(caps.dwFormats & 0x333)) || + (bits == 16 && !(caps.dwFormats & 0xccc))) { + fprintf(stderr, "%d bits sound are not supported\n", bits); + result = 2; + } + + if ((channels == 1 && !(caps.dwFormats & 0x555)) || + (channels == 2 && !(caps.dwFormats & 0xaaa))) { + fprintf(stderr, "%d sound channels are not supported\n", channels); + result = 3; + } + + if ((rate == 44100.0 && !(caps.dwFormats & 0xf00)) || + (rate == 22050.0 && !(caps.dwFormats & 0xf0)) || + (rate == 11025.0 && !(caps.dwFormats & 0xf))) { + fprintf(stderr, "%d sample rate is not supported\n", (int)rate); + result = 4; + } + + return result; +} +# endif /* defined CYGWIN */ +#endif /* defined ECHO_TO_SOUNDCARD */ + +#ifdef HAVE_SUN_AUDIOIO_H +# include <sun/audioio.h> +#endif +#ifdef HAVE_SYS_AUDIOIO_H +# include <sys/audioio.h> +#endif + +#ifdef HAVE_SYS_ASOUNDLIB_H +# include <sys/asoundlib.h> +snd_pcm_t *pcm_handle; +#endif + +#if defined HAVE_OSS && defined SNDCTL_DSP_GETOSPACE +audio_buf_info abinfo; +#endif + +int init_soundcard(double rate, int bits) +{ +#ifdef ECHO_TO_SOUNDCARD + if (global.echo) { +# if defined(HAVE_OSS) && HAVE_OSS == 1 + if (open_snd_device() != 0) { + errmsg("Cannot open sound device '%s'\n", snd_device); + global.echo = 0; + } else { + /* This the sound device initialisation for 4front Open sound drivers */ + + int dummy; + int garbled_rate = rate; + int stereo = (global.channels == 2); + int myformat = bits == 8 ? AFMT_U8 : + (MY_LITTLE_ENDIAN ? AFMT_S16_LE : AFMT_S16_BE); + int mask; + + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETBLKSIZE, &dummy) == -1) { + fprintf(stderr, "Cannot get blocksize for %s\n", snd_device); + global.echo = 0; + } + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SYNC, NULL) == -1) { + fprintf(stderr, "Cannot sync for %s\n", snd_device); + global.echo = 0; + } + +#if defined SNDCTL_DSP_GETOSPACE + if (ioctl(global.soundcard_fd, SNDCTL_DSP_GETOSPACE, &abinfo) == -1) { + fprintf(stderr, "Cannot get input buffersize for %s\n", snd_device); + abinfo.fragments = 0; + } +#endif + + /* check, if the sound device can do the requested format */ + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_GETFMTS, &mask) == -1) { + perror("fatal error:"); + return -1; + } + if ((mask & myformat) == 0) { + fprintf(stderr, "sound format (%d bits signed) is not available\n", bits); + if ((mask & AFMT_U8) != 0) { + bits = 8; + myformat = AFMT_U8; + } + } + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SETFMT, &myformat) == -1) { + fprintf(stderr, "Cannot set %d bits/sample for %s\n",bits, snd_device); + global.echo = 0; + } + + /* limited sound devices may not support stereo */ + if (stereo + && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) { + fprintf(stderr, "Cannot set stereo mode for %s\n", snd_device); + stereo = 0; + } + if (!stereo + && ioctl(global.soundcard_fd, (int)SNDCTL_DSP_STEREO, &stereo) == -1) { + fprintf(stderr, "Cannot set mono mode for %s\n", snd_device); + global.echo = 0; + } + + /* set the sample rate */ + if (ioctl(global.soundcard_fd, (int)SNDCTL_DSP_SPEED, &garbled_rate) == -1) { + fprintf(stderr, "Cannot set rate %d.%2d Hz for %s\n", + (int)rate, (int)(rate*100)%100, snd_device); + global.echo = 0; + } + if ( abs((long)rate - garbled_rate) > rate / 20) { + fprintf(stderr, "sound device: next best sample rate is %d\n",garbled_rate); + } + } + +# else /* HAVE_OSS */ + +# if defined HAVE_SYS_AUDIOIO_H || defined HAVE_SUN_AUDIOIO_H + /* This is the SunOS / Solaris and compatibles sound initialisation */ + + if ((global.soundcard_fd = open(snd_device, O_WRONLY, 0)) == EOF) { + perror(""); + fprintf(stderr, "Cannot open %s\n",snd_device); + global.echo = 0; + } else { + + audio_info_t info; + +# if defined (AUDIO_INITINFO) && defined (AUDIO_ENCODING_LINEAR) + AUDIO_INITINFO(&info); + info.play.sample_rate = rate; + info.play.channels = global.channels; + info.play.precision = bits; + info.play.encoding = AUDIO_ENCODING_LINEAR; + info.play.pause = 0; + info.record.pause = 0; + info.monitor_gain = 0; + if (ioctl(global.soundcard_fd, AUDIO_SETINFO, &info) < 0) { + fprintf(stderr, "Cannot init %s (sun)\n", snd_device); + global.echo = 0; + } +# else + fprintf(stderr, "Cannot init sound device with 44.1 KHz sample rate on %s (sun compatible)\n", snd_device); + global.echo = 0; +# endif + } +# else /* SUN audio */ +# if defined(__CYGWIN32__) + /* Windows sound info */ + + MMRESULT mmres; + WAVEFORMATEX wavform; + + if (waveOutGetNumDevs() < 1) { + fprintf( stderr, "no sound devices available!\n"); + global.echo = 0; + return 1; + } + + /* check capabilities */ + if (check_winsound_caps(bits, rate, global.channels) != 0) { + fprintf( stderr, "soundcard capabilities are not sufficient!\n"); + global.echo = 0; + return 1; + } + + wavform.wFormatTag = WAVE_FORMAT_PCM; + wavform.nChannels = global.channels; + wavform.nSamplesPerSec = (int)rate; + wavform.wBitsPerSample = bits; + wavform.cbSize = sizeof(wavform); + wavform.nAvgBytesPerSec = (int)rate * global.channels * + (wavform.wBitsPerSample / 8); + wavform.nBlockAlign = global.channels * (wavform.wBitsPerSample / 8); + + DeviceID = 0; + mmres = waveOutOpen(&DeviceID, WAVE_MAPPER, &wavform, (unsigned long)WIN_CallBack, 0, CALLBACK_FUNCTION); + if (mmres) { + char erstr[329]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard open error: %s!\n", erstr); + global.echo = 0; + return 1; + } + + global.soundcard_fd = 0; + + /* init all wavehdrs */ + { int i; + for (i=0; i < WAVEHDRS; i++) { + wavehdr[i].dwBufferLength = (global.channels*(bits/ 8)*(int)rate* + global.nsectors)/75; + wavehdr[i].lpData = malloc(wavehdr[i].dwBufferLength); + if (wavehdr[i].lpData == NULL) { + fprintf(stderr, "no memory for sound buffers available\n"); + waveOutReset(0); + waveOutClose(DeviceID); + return 1; + } + + mmres = waveOutPrepareHeader(DeviceID, &wavehdr[i], sizeof(WAVEHDR)); + if (mmres) { + char erstr[129]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard prepare error: %s!\n", erstr); + return 1; + } + + wavehdr[i].dwLoops = 0; + wavehdr[i].dwFlags = WHDR_DONE; + wavehdr[i].dwBufferLength = 0; + } + } + +# else +# if defined(__EMX__) +# if defined (HAVE_MMPM) + /* OS/2 MMPM/2 MCI sound info */ + + MCI_OPEN_PARMS mciOpenParms; + int i; + + /* create playlist */ + for (i = 0; i < FRAGMENTS; i++) { + PlayList[i].ulCommand = DATA_OPERATION; /* play data */ + PlayList[i].ulOperand1 = 0; /* address */ + PlayList[i].ulOperand2 = 0; /* size */ + PlayList[i].ulOperand3 = 0; /* offset */ + } + PlayList[FRAGMENTS].ulCommand = BRANCH_OPERATION; /* jump */ + PlayList[FRAGMENTS].ulOperand1 = 0; + PlayList[FRAGMENTS].ulOperand2 = 0; /* destination */ + PlayList[FRAGMENTS].ulOperand3 = 0; + + memset(&mciOpenParms, 0, sizeof(mciOpenParms)); + mciOpenParms.pszDeviceType = (PSZ) (((unsigned long) MCI_DEVTYPE_WAVEFORM_AUDIO << 16) | (unsigned short) DeviceIndex); + mciOpenParms.pszElementName = (PSZ) & PlayList; + + /* try to open the sound device */ + if (mciSendCommand(0, MCI_OPEN, + MCI_WAIT | MCI_OPEN_SHAREABLE | MCIOPEN_Type_ID, &mciOpenParms, 0) + != MCIERR_SUCCESS) { + /* no sound */ + fprintf( stderr, "no sound devices available!\n"); + global.echo = 0; + return 1; + } + /* try to set the parameters */ + DeviceID = mciOpenParms.usDeviceID; + + { + MCI_WAVE_SET_PARMS mciWaveSetParms; + + memset(&mciWaveSetParms, 0, sizeof(mciWaveSetParms)); + mciWaveSetParms.ulSamplesPerSec = rate; + mciWaveSetParms.usBitsPerSample = bits; + mciWaveSetParms.usChannels = global.channels; + mciWaveSetParms.ulAudio = MCI_SET_AUDIO_ALL; + + /* set play-parameters */ + if (mciSendCommand(DeviceID, MCI_SET, + MCI_WAIT | MCI_WAVE_SET_SAMPLESPERSEC | + MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_CHANNELS, + (PVOID) & mciWaveSetParms, 0)) { + MCI_GENERIC_PARMS mciGenericParms; + fprintf( stderr, "soundcard capabilities are not sufficient!\n"); + global.echo = 0; + /* close */ + mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0); + return 1; + } + } + +# endif /* EMX MMPM OS2 sound */ +# else +# if defined(__QNX__) + + int card = -1; + int dev = 0; + int rtn; + snd_pcm_channel_info_t pi; + snd_pcm_channel_params_t pp; + + if (card == -1) { + rtn = snd_pcm_open_preferred(&pcm_handle, + &card, &dev, SND_PCM_OPEN_PLAYBACK); + if (rtn < 0) { + perror("sound device open"); + return 1; + } + } else { + rtn = snd_pcm_open(&pcm_handle, + card, dev, SND_PCM_OPEN_PLAYBACK); + if (rtn < 0) { + perror("sound device open"); + return 1; + } + } + + memset(&pi, 0, sizeof(pi)); + pi.channel = SND_PCM_CHANNEL_PLAYBACK; + rtn = snd_pcm_plugin_info(pcm_handle, &pi); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_info failed: %s\n", snd_strerror(rtn)); + return 1; + } + + memset(&pp, 0, sizeof(pp)); + pp.mode = SND_PCM_MODE_BLOCK; + pp.channel = SND_PCM_CHANNEL_PLAYBACK; + pp.start_mode = SND_PCM_START_FULL; + pp.stop_mode = SND_PCM_STOP_STOP; + + pp.buf.block.frag_size = pi.max_fragment_size; + pp.buf.block.frags_max = 1; + pp.buf.block.frags_min = 1; + + pp.format.interleave = 1; + pp.format.rate = rate; + pp.format.voices = global.channels; + if (bits == 8) { + pp.format.format = SND_PCM_SFMT_U8; + } else { + pp.format.format = SND_PCM_SFMT_S16_LE; + } + + rtn = snd_pcm_plugin_params(pcm_handle, &pp); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_params failed: %s\n", snd_strerror(rtn)); + return 1; + } + + rtn = snd_pcm_plugin_prepare(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + if (rtn < 0) { + fprintf(stderr, "snd_pcm_plugin_prepare failed: %s\n", snd_strerror(rtn)); + return 1; + } + + global.soundcard_fd = snd_pcm_file_descriptor(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + +# endif /* QNX sound */ +# endif /* EMX OS2 sound */ +# endif /* CYGWIN Windows sound */ +# endif /* else SUN audio */ +# endif /* else HAVE_OSS */ + } +#endif /* ifdef ECHO_TO_SOUNDCARD */ + return 0; +} + +int open_snd_device() +{ +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + int fl; +#endif + +#if defined ECHO_TO_SOUNDCARD && !defined __CYGWIN32__ && !defined __EMX__ + global.soundcard_fd = open(snd_device, O_WRONLY +#ifdef linux + /* Linux BUG: the sound driver open() blocks, if the device is in use. */ + | O_NONBLOCK +#endif + , 0); + +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + fl = fcntl(global.soundcard_fd, F_GETFL, 0); + fl &= ~O_NONBLOCK; + fcntl(global.soundcard_fd, F_SETFL, fl); +#endif + + return (global.soundcard_fd < 0); +#else + return 0; +#endif +} + +int close_snd_device () +{ +#if !defined ECHO_TO_SOUNDCARD + return 0; +#else + +# if defined __CYGWIN32__ + waveOutReset(0); + return waveOutClose(DeviceID); +# else /* !Cygwin32 */ + +# if defined __EMX__ +# if defined HAVE_MMPM + /* close the sound device */ + MCI_GENERIC_PARMS mciGenericParms; + mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, &mciGenericParms, 0); +# else /* HAVE_MMPM */ + return 0; +# endif /* HAVE_MMPM */ +# else /* !EMX */ +# if defined __QNX__ + snd_pcm_plugin_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK); + return snd_pcm_close(pcm_handle); +# else /* !QNX */ + return close(global.soundcard_fd); +# endif /* !QNX */ +# endif /* !EMX */ +# endif /* !Cygwin32 */ +#endif /* ifdef ECHO_TO_SOUNDCARD */ +} + +int write_snd_device(char *buffer, unsigned todo) +{ + int result = 0; +#ifdef ECHO_TO_SOUNDCARD +#if defined __CYGWIN32__ + MMRESULT mmres; + + wavehdr[lastwav].dwBufferLength = todo; + memcpy(wavehdr[lastwav].lpData, buffer, todo); + + mmres = waveOutWrite(DeviceID, &wavehdr[lastwav], sizeof(WAVEHDR)); + if (mmres) { + char erstr[129]; + + waveOutGetErrorText(mmres, erstr, sizeof(erstr)); + fprintf( stderr, "soundcard write error: %s!\n", erstr); + return 1; + } + if (++lastwav >= WAVEHDRS) + lastwav -= WAVEHDRS; + result = mmres; +#else +#if defined __EMX__ + Playlist[BufferInd].ulOperand1 = buffer; + Playlist[BufferInd].ulOperand2 = todo; + Playlist[BufferInd].ulOperand3 = 0; + if (++BufferInd >= FRAGMENTS) + BufferInd -= FRAGMENTS; + + /* no MCI_WAIT here, because application program has to continue */ + memset(&mciPlayParms, 0, sizeof(mciPlayParms)); + if (mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM, &mciPlayParms, 0)) { + fprintf( stderr, "soundcard write error: %s!\n", erstr); + return 1; + } + result = 0; +#else + int retval2; + int towrite; + +#if defined HAVE_OSS && defined SNDCTL_DSP_GETOSPACE + towrite = abinfo.fragments * abinfo.fragsize; + if (towrite == 0) +#endif + towrite = todo; + do { + fd_set writefds[1]; + struct timeval timeout2; + int wrote; + + timeout2.tv_sec = 0; + timeout2.tv_usec = 4*120000; + + FD_ZERO(writefds); + FD_SET(global.soundcard_fd, writefds); + retval2 = select(global.soundcard_fd + 1, + NULL, writefds, NULL, &timeout2); + switch (retval2) { + default: + case -1: perror ("select failed"); + /* fall through */ + case 0: /* timeout */ + result = 2; + goto outside_loop; + case 1: break; + } + if (towrite > todo) { + towrite = todo; + } +#if defined __QNX__ && defined HAVE_SYS_ASOUNDLIB_H + wrote = snd_pcm_plugin_write(pcm_handle, buffer, towrite); +#else + wrote = write(global.soundcard_fd, buffer, towrite); +#endif + if (wrote <= 0) { + perror( "cant write audio"); + result = 1; + goto outside_loop; + } else { + todo -= wrote; + buffer += wrote; + } + } while (todo > 0); +outside_loop: + ; +#endif /* !defined __EMX__ */ +#endif /* !defined __CYGWIN32__ */ +#endif /* ECHO_TO_SOUNDCARD */ + return result; +} + diff --git a/icedax/sndconfig.h b/icedax/sndconfig.h new file mode 100644 index 0000000..1a2e18d --- /dev/null +++ b/icedax/sndconfig.h @@ -0,0 +1,20 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sndconfig.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +#define NONBLOCKING_AUDIO +int set_snd_device(const char *devicename); +int init_soundcard(double rate, int bits); + +int open_snd_device(void); +int close_snd_device(void); +int write_snd_device(char *buffer, unsigned length); diff --git a/icedax/sndfile.h b/icedax/sndfile.h new file mode 100644 index 0000000..73ef9ff --- /dev/null +++ b/icedax/sndfile.h @@ -0,0 +1,36 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sndfile.h 1.4 06/02/19 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2006 J. Schilling */ + +/* + * generic soundfile structure + */ + +#ifndef _SNDFILE_H +#define _SNDFILE_H + +#include <utypes.h> + +struct soundfile { + int (* InitSound)(int audio, long channels, Ulong rate, + long nBitsPerSample, + Ulong expected_bytes); + int (* ExitSound)(int audio, Ulong nBytesDone); + Ulong (* GetHdrSize)(void); + int (* WriteSound)(int audio, unsigned char *buf, Ulong BytesToDo); + Ulong (* InSizeToOutSize)(Ulong BytesToDo); + + int need_big_endian; +}; + +#endif /* _SNDFILE_H */ diff --git a/icedax/sun.c b/icedax/sun.c new file mode 100644 index 0000000..99ff443 --- /dev/null +++ b/icedax/sun.c @@ -0,0 +1,99 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sun.c 1.4 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * + * --------------------------------------------------------------------- + * definitions for sun pcm output + * --------------------------------------------------------------------- + */ + +#include "config.h" +#include "mytype.h" +#include <stdio.h> +#include <unixstd.h> +#include "byteorder.h" +#include "sndfile.h" + +typedef struct SUNHDR { + unsigned int magic; /* dns. a la .snd */ + unsigned int data_location; /* offset to data */ + unsigned int size; /* # of data bytes */ + unsigned int format; /* format code */ + unsigned int sample_rate; /* in Hertz */ + unsigned int channelcount; /* 1 for mono, 2 for stereo */ + char info[8]; /* comments */ +} SUNHDR; + +static SUNHDR sunHdr; + +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes); + +static int InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes) +{ + unsigned long format = nBitsPerSample > 8 ? 0x03 : 0x02; + + sunHdr.magic = cpu_to_le32(UINT4_C(0x646e732e)); + sunHdr.data_location = cpu_to_be32(0x20); + sunHdr.size = cpu_to_be32(expected_bytes); + sunHdr.format = cpu_to_be32(format); + sunHdr.sample_rate = cpu_to_be32(rate); + sunHdr.channelcount = cpu_to_be32(channels); + + return write (audio, &sunHdr, sizeof (sunHdr)); +} + +static int ExitSound(int audio, unsigned long nBytesDone); + +static int ExitSound(int audio, unsigned long nBytesDone) +{ + sunHdr.size = cpu_to_be32(nBytesDone); + + /* goto beginning */ + if (lseek(audio, 0L, SEEK_SET) == -1) { + return 0; + } + return write (audio, &sunHdr, sizeof (sunHdr)); +} + +static unsigned long GetHdrSize(void); + +static unsigned long GetHdrSize() +{ + return sizeof( sunHdr ); +} + +static unsigned long InSizeToOutSize(unsigned long BytesToDo); + +static unsigned long InSizeToOutSize(unsigned long BytesToDo) +{ + return BytesToDo; +} + +struct soundfile sunsound = +{ + InitSound, /* init header method */ + ExitSound, /* exit header method */ + GetHdrSize, /* report header size method */ + /* get sound samples out */ + (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo)) write, + InSizeToOutSize, /* compressed? output file size */ + 1 /* needs big endian samples */ +}; + + diff --git a/icedax/sun.h b/icedax/sun.h new file mode 100644 index 0000000..400fc4a --- /dev/null +++ b/icedax/sun.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)sun.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +extern struct soundfile sunsound; diff --git a/icedax/toc.c b/icedax/toc.c new file mode 100644 index 0000000..e03c23d --- /dev/null +++ b/icedax/toc.c @@ -0,0 +1,3841 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)toc.c 1.57 06/02/19 Copyright 1998-2003 Heiko Eissfeldt */ +/* + * Copyright: GNU Public License 2 applies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * CDDA2WAV (C) Heiko Eissfeldt heiko@hexco.de + * CDDB routines (C) Ti Kan and Steve Scherf + */ +#include "config.h" +#include <stdio.h> +#include <standard.h> +#include <stdxlib.h> +#include <strdefs.h> +#include <utypes.h> +#include <intcvt.h> +#include <unixstd.h> /* sleep */ +#include <ctype.h> +#include <errno.h> +#include <fctldefs.h> +#include <vadefs.h> +#include <schily.h> +#include <libport.h> +#include <sys/ioctl.h> + +#define CD_TEXT +#define CD_EXTRA +#undef DEBUG_XTRA +#undef DEBUG_CDTEXT +#undef DEBUG_CDDBP + + +#include <usal/scsitransp.h> + +#include "mytype.h" +#include "byteorder.h" +#include "interface.h" +#include "icedax.h" +#include "global.h" +#include "sha.h" +#include "base64.h" +#include "toc.h" +#include "exitcodes.h" +#include "ringbuff.h" + +int Get_Mins(unsigned long p_track); +int Get_Secs(unsigned long p_track); +int Get_Frames(unsigned long p_track); +int Get_Flags(unsigned long p_track); +int Get_SCMS(unsigned long p_track); + + +#if defined USE_REMOTE +/* tcp stuff */ +/* fix OS/2 compilation */ +#ifdef __EMX__ +#define gethostid nogethostid +#endif +#include <sys/socket.h> +#undef gethostid +#include <netinet/in.h> +#if defined(HAVE_NETDB_H) && !defined(HOST_NOT_FOUND) && \ + !defined(_INCL_NETDB_H) +#include <netdb.h> +#define _INCL_NETDB_H +#endif +#endif + +int have_CD_text; +int have_multisession; +int have_CD_extra; +int have_CDDB; + +struct iterator; + +static void UpdateTrackData(int p_num); +static void UpdateIndexData(int p_num); +static void UpdateTimeData(int p_min, int p_sec, int p_frm); +static unsigned int is_multisession(void); +static unsigned int get_end_of_last_audio_track(unsigned mult_off); +static int cddb_sum(int n); +static void dump_extra_info(unsigned from); +static int GetIndexOfSector(unsigned sec, unsigned track); +static int patch_cd_extra(unsigned track, unsigned long sector); +static void patch_to_audio(unsigned long p_track); +static int restrict_tracks_illleadout(void); +static void Set_MCN(unsigned char *MCN_arg); +static void Set_ISRC(int track, const unsigned char *ISRC_arg); +static void InitIterator(struct iterator *iter, unsigned long p_track); + +static unsigned char g_track=0xff, g_index=0xff; /* current track, index */ + +/* Conversion function: from logical block adresses to minute,second,frame + */ +int lba_2_msf(long lba, int *m, int *s, int *f) +{ +#ifdef __follow_redbook__ + if (lba >= -150 && lba < 405000) { /* lba <= 404849 */ +#else + if (lba >= -150) { +#endif + lba += 150; + } else if (lba >= -45150 && lba <= -151) { + lba += 450150; + } else + return 1; + + *m = lba / 60 / 75; + lba -= (*m)*60*75; + *s = lba / 75; + lba -= (*s)*75; + *f = lba; + + return 0; +} + +/* print the track currently read */ +static void UpdateTrackData(int p_num) +{ + if (global.quiet == 0) { + fprintf (stderr, "\ntrack: %.2d, ", p_num); fflush(stderr); + } + g_track = (unsigned char) p_num; +} + + +/* print the index currently read */ +static void UpdateIndexData(int p_num) +{ + if (global.quiet == 0) { + fprintf (stderr, "index: %.2d\n", p_num); fflush(stderr); + } + g_index = (unsigned char) p_num; +} + + +/* print the time of track currently read */ +static void UpdateTimeData(int p_min, int p_sec, int p_frm) +{ + if (global.quiet == 0) { + fprintf (stderr, "time: %.2d:%.2d.%.2d\r", p_min, p_sec, p_frm); + fflush(stderr); + } +} + +void AnalyzeQchannel(unsigned frame) +{ + subq_chnl *sub_ch; + + if (trackindex_disp != 0) { + sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA,0); + /* analyze sub Q-channel data */ + if (sub_ch->track != g_track || + sub_ch->index != g_index) { + UpdateTrackData (sub_ch->track); + UpdateIndexData (sub_ch->index); + } + } + frame += 150; + UpdateTimeData ((unsigned char) (frame / (60*75)), + (unsigned char) ((frame % (60*75)) / 75), + (unsigned char) (frame % 75)); +} + +unsigned cdtracks = 0; + +int no_disguised_audiotracks(void) +{ + /* we can assume no audio tracks according to toc here. */ + /* read a data sector from the first data track */ + unsigned char p[3000]; + int retval; + get_scsi_p()->silent++; + retval = 1 == ReadCdRomData(get_scsi_p(), p, Get_StartSector(1), 1); + get_scsi_p()->silent--; + if (retval == 0) { + int i; +fprintf(stderr, "Warning: wrong track types found: patching to audio...\n"); + for (i = 0; i < cdtracks; i++) + patch_to_audio(i); + } + return retval; +} + + +#undef SIM_ILLLEADOUT +int ReadToc(void) +{ + int retval = (*doReadToc)( get_scsi_p() ); +#if defined SIM_ILLLEADOUT + g_toc[cdtracks+1] = 20*75; +#endif + return retval; +} + +static int can_read_illleadout(void); + +static int can_read_illleadout(void) +{ + SCSI *usalp = get_scsi_p(); + + UINT4 buffer [CD_FRAMESIZE_RAW/4]; + if (global.illleadout_cd == 0) return 0; + + usalp->silent++; + global.reads_illleadout = + ReadCdRom(usalp, buffer, Get_AudioStartSector(CDROM_LEADOUT), 1); + usalp->silent--; + return global.reads_illleadout; +} + + +unsigned find_an_off_sector(unsigned lSector, unsigned SectorBurstVal); + +unsigned find_an_off_sector(unsigned lSector, unsigned SectorBurstVal) +{ + long track_of_start = Get_Track(lSector); + long track_of_end = Get_Track(lSector + SectorBurstVal -1); + long start = Get_AudioStartSector(track_of_start); + long end = Get_EndSector(track_of_end); + + if (lSector - start > end - lSector + SectorBurstVal -1) + return start; + else + return end; +} + +#ifdef CD_TEXT +#include "scsi_cmds.h" +#endif + + +int handle_cdtext(void) +{ +#ifdef CD_TEXT + if (bufferTOC[0] == 0 && bufferTOC[1] == 0) { + have_CD_text = 0; + return have_CD_text; + } + + /* do a quick scan over all pack type indicators */ + { + int i; + int count_fails = 0; + int len = (bufferTOC[0] << 8) | bufferTOC[1]; + + len = min(len, 2048); + for (i = 0; i < len-4; i += 18) { + if (bufferTOC[4+i] < 0x80 || bufferTOC[4+i] > 0x8f) { + count_fails++; + } + } + have_CD_text = len > 4 && count_fails < 3; + } + +#else + have_CD_text = 0; +#endif + return have_CD_text; +} + + +#ifdef CD_TEXT +#include "cd_text.c" +#endif + + +#if defined CDROMMULTISESSION +static int tmp_fd; +#endif + +#ifdef CD_EXTRA +#include "cd_extra.c" +#endif + +static unsigned session_start; +/* + A Cd-Extra is detected, if it is a multisession CD with + only audio tracks in the first session and a data track + in the last session. + */ +static unsigned is_multisession(void) +{ + unsigned mult_off; +#if defined CDROMMULTISESSION + /* + * FIXME: we would have to do a ioctl (CDROMMULTISESSION) + * for the cdrom device associated with the generic device + * not just AUX_DEVICE + */ + struct cdrom_multisession ms_str; + + if (interface == GENERIC_SCSI) + tmp_fd = open (global.aux_name, O_RDONLY); + else + tmp_fd = global.cooked_fd; + + if (tmp_fd != -1) { + int result; + + ms_str.addr_format = CDROM_LBA; + result = ioctl(tmp_fd, CDROMMULTISESSION, &ms_str); + if (result == -1) { + if (global.verbose != 0) + perror("multi session ioctl not supported: "); + } else { +#ifdef DEBUG_XTRA + fprintf(stderr, "current ioctl multisession_offset = %u\n", ms_str.addr.lba); +#endif + if (interface == GENERIC_SCSI) + close (tmp_fd); + if (ms_str.addr.lba > 0) + return ms_str.addr.lba; + } + } +#endif + mult_off = 0; + if (LastAudioTrack() + 1 == FirstDataTrack()) { + mult_off = Get_StartSector(FirstDataTrack()); + } + +#ifdef DEBUG_XTRA + fprintf(stderr, "current guessed multisession_offset = %u\n", mult_off); +#endif + return mult_off; +} + +#define SESSIONSECTORS (152*75) +/* + The solution is to read the Table of Contents of the first + session only (if the drive permits that) and directly use + the start of the leadout. If this is not supported, we subtract + a constant of SESSIONSECTORS sectors (found heuristically). + */ +static unsigned get_end_of_last_audio_track(unsigned mult_off) +{ + unsigned retval; + + /* Try to read the first session table of contents. + This works for Sony and mmc type drives. */ + if (ReadLastAudio && (retval = ReadLastAudio(get_scsi_p())) != 0) { + return retval; + } else { + return mult_off - SESSIONSECTORS; + } +} + +static void dump_cdtext_info(void); + +#if defined CDDB_SUPPORT +static void emit_cddb_form(char *fname_baseval); +#endif + +#if defined CDINDEX_SUPPORT +static void emit_cdindex_form(char *fname_baseval); +#endif + + +typedef struct TOC { /* structure of table of contents (cdrom) */ + unsigned char reserved1; + unsigned char bFlags; + unsigned char bTrack; + unsigned char reserved2; + unsigned int dwStartSector; + int mins; + int secs; + int frms; + unsigned char ISRC[16]; + int SCMS; +} TOC; + + +/* Flags contains two fields: + bits 7-4 (ADR) + : 0 no sub-q-channel information + : 1 sub-q-channel contains current position + : 2 sub-q-channel contains media catalog number + : 3 sub-q-channel contains International Standard + Recording Code ISRC + : other values reserved + bits 3-0 (Control) : + bit 3 : when set indicates there are 4 audio channels else 2 channels + bit 2 : when set indicates this is a data track else an audio track + bit 1 : when set indicates digital copy is permitted else prohibited + bit 0 : when set indicates pre-emphasis is present else not present + */ + +#define GETFLAGS(x) ((x)->bFlags) +#define GETTRACK(x) ((x)->bTrack) +#define GETSTART(x) ((x)->dwStartSector) +#define GETMINS(x) ((x)->mins) +#define GETSECS(x) ((x)->secs) +#define GETFRAMES(x) ((x)->frms) +#define GETISRC(x) ((x)->ISRC) + +#define IS__PREEMPHASIZED(p) ( (GETFLAGS(p) & 0x10) != 0) +#define IS__INCREMENTAL(p) ( (GETFLAGS(p) & 0x10) != 0) +#define IS__COPYRESTRICTED(p) (!(GETFLAGS(p) & 0x20) != 0) +#define IS__COPYRIGHTED(p) (!(GETFLAGS(p) & 0x20) != 0) +#define IS__DATA(p) ( (GETFLAGS(p) & 0x40) != 0) +#define IS__AUDIO(p) (!(GETFLAGS(p) & 0x40) != 0) +#define IS__QUADRO(p) ( (GETFLAGS(p) & 0x80) != 0) + +/* + * Iterator interface inspired from Java + */ +struct iterator { + int index; + int startindex; + void (*reset)(struct iterator *this); + struct TOC *(*getNextTrack)(struct iterator *this); + int (*hasNextTrack)(struct iterator *this); +}; + + + + +/* The Table of Contents needs to be corrected if we + have a CD-Extra. In this case all audio tracks are + followed by a data track (in the second session). + Unlike for single session CDs the end of the last audio + track cannot be set to the start of the following + track, since the lead-out and lead-in would then + errenously be part of the audio track. This would + lead to read errors when trying to read into the + lead-out area. + So the length of the last track in case of Cd-Extra + has to be fixed. + */ +unsigned FixupTOC(unsigned no_tracks) +{ + unsigned mult_off; + unsigned offset = 0; + int j = -1; + unsigned real_end = 2000000; + + /* get the multisession offset in sectors */ + mult_off = is_multisession(); + + /* if the first track address had been the victim of an underflow, + * set it to zero. + */ + if (Get_StartSector(1) > Get_StartSector(LastTrack())) { + fprintf(stderr, "Warning: first track has negative start sector! Setting to zero.\n"); + toc_entry( 1, Get_Flags(1), Get_Tracknumber(1), Get_ISRC(1), 0, 0, 2, 0 ); + } + +#ifdef DEBUG_XTRA + fprintf(stderr, "current multisession_offset = %u\n", mult_off); +#endif + dump_cdtext_info(); + + if (mult_off > 100) { /* the offset has to have a minimum size */ + + /* believe the multisession offset :-) */ + /* adjust end of last audio track to be in the first session */ + real_end = get_end_of_last_audio_track(mult_off); +#ifdef DEBUG_XTRA + fprintf(stderr, "current end = %u\n", real_end); +#endif + + j = FirstDataTrack(); + if (LastAudioTrack() + 1 == j) { + long sj = Get_StartSector(j); + if (sj > (long)real_end) { + session_start = mult_off; + have_multisession = sj; + +#ifdef CD_EXTRA + offset = Read_CD_Extra_Info(sj); + + if (offset != 0) { + have_CD_extra = sj; + dump_extra_info(offset); + } +#endif + } + } + } + if (global.cddbp) { +#if defined USE_REMOTE + if (global.disctitle == NULL) { + have_CDDB = !request_titles(); + } +#else + fprintf(stderr, "Cannot lookup titles: no cddbp support included!\n"); +#endif + } +#if defined CDINDEX_SUPPORT || defined CDDB_SUPPORT + if (have_CD_text || have_CD_extra || have_CDDB) { + unsigned long count_audio_tracks = 0; + static struct iterator i; + if (i.reset == NULL) + InitIterator(&i, 1); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + if (IS__AUDIO(p)) count_audio_tracks++; + } + + if (count_audio_tracks > 0 && global.no_cddbfile == 0) { +#if defined CDINDEX_SUPPORT + emit_cdindex_form(global.fname_base); +#endif +#if defined CDDB_SUPPORT + emit_cddb_form(global.fname_base); +#endif + } + } +#endif + if (have_multisession) { + /* set start of track to beginning of lead-out */ + patch_cd_extra(j, real_end); +#if defined CD_EXTRA && defined DEBUG_XTRA + fprintf(stderr, "setting end of session (track %d) to %u\n", j, real_end); +#endif + } + return offset; +} + +static int cddb_sum(int n) +{ + int ret; + + for (ret = 0; n > 0; n /= 10) { + ret += (n % 10); + } + + return ret; +} + +void calc_cddb_id(void) +{ + UINT4 i; + UINT4 t = 0; + UINT4 n = 0; + + for (i = 1; i <= cdtracks; i++) { + n += cddb_sum(Get_StartSector(i)/75 + 2); + } + + t = Get_StartSector(i)/75 - Get_StartSector(1)/75; + + global.cddb_id = (n % 0xff) << 24 | (t << 8) | cdtracks; +} + + +#undef TESTCDINDEX +#ifdef TESTCDINDEX +void TestGenerateId(void) +{ + SHA_INFO sha; + unsigned char digest[20], *base64; + unsigned long size; + + sha_init(&sha); + sha_update(&sha, (unsigned char *)"0123456789", 10); + sha_final(digest, &sha); + + base64 = rfc822_binary((char *)digest, 20, &size); + if (strncmp((char*) base64, "h6zsF82dzSCnFsws9nQXtxyKcBY-", size)) + { + free(base64); + + fprintf(stderr, "The SHA-1 hash function failed to properly generate the\n"); + fprintf(stderr, "test key.\n"); + exit(INTERNAL_ERROR); + } + free(base64); +} +#endif + +void calc_cdindex_id() +{ + SHA_INFO sha; + unsigned char digest[20], *base64; + unsigned long size; + unsigned i; + char temp[9]; + +#ifdef TESTCDINDEX + TestGenerateId(); + g_toc[1].bTrack = 1; + cdtracks = 15; + g_toc[cdtracks].bTrack = 15; + i = 1; + g_toc[i++].dwStartSector = 0U; + g_toc[i++].dwStartSector = 18641U; + g_toc[i++].dwStartSector = 34667U; + g_toc[i++].dwStartSector = 56350U; + g_toc[i++].dwStartSector = 77006U; + g_toc[i++].dwStartSector = 106094U; + g_toc[i++].dwStartSector = 125729U; + g_toc[i++].dwStartSector = 149785U; + g_toc[i++].dwStartSector = 168885U; + g_toc[i++].dwStartSector = 185910U; + g_toc[i++].dwStartSector = 205829U; + g_toc[i++].dwStartSector = 230142U; + g_toc[i++].dwStartSector = 246659U; + g_toc[i++].dwStartSector = 265614U; + g_toc[i++].dwStartSector = 289479U; + g_toc[i++].dwStartSector = 325732U; +#endif + sha_init(&sha); + sprintf(temp, "%02X", Get_Tracknumber(1)); + sha_update(&sha, (unsigned char *)temp, 2); + sprintf(temp, "%02X", Get_Tracknumber(cdtracks)); + sha_update(&sha, (unsigned char *)temp, 2); + + /* the position of the leadout comes first. */ + sprintf(temp, "%08lX", 150 + Get_StartSector(CDROM_LEADOUT)); + sha_update(&sha, (unsigned char *)temp, 8); + + /* now 99 tracks follow with their positions. */ + for (i = 1; i <= cdtracks; i++) { + sprintf(temp, "%08lX", 150+Get_StartSector(i)); + sha_update(&sha, (unsigned char *)temp, 8); + } + for (i++ ; i <= 100; i++) { + sha_update(&sha, (unsigned char *)"00000000", 8); + } + sha_final(digest, &sha); + + base64 = rfc822_binary((char *)digest, 20, &size); + global.cdindex_id = base64; +} + + +#if defined CDDB_SUPPORT + +#ifdef PROTOTYPES +static void escape_and_split(FILE *channel, const char *args, ...) +#else +/*VARARGS3*/ +static void escape_and_split(FILE *channel, const char *args, va_dcl va_alist) +#endif +{ + va_list marker; + + int prefixlen; + int len; + char *q; + +#ifdef PROTOTYPES + va_start(marker, args); +#else + va_start(marker); +#endif + + prefixlen = strlen(args); + len = prefixlen; + fputs(args, channel); + + q = va_arg(marker, char *); + while (*q != '\0') { + while (*q != '\0') { + len += 2; + if (*q == '\\') + fputs("\\\\", channel); + else if (*q == '\t') + fputs("\\t", channel); + else if (*q == '\n') + fputs("\\n", channel); + else { + fputc(*q, channel); + len--; + } + if (len > 78) { + fputc('\n', channel); + fputs(args, channel); + len = prefixlen; + } + q++; + } + q = va_arg(marker, char *); + } + fputc('\n', channel); + + va_end(marker); +} + +static void emit_cddb_form(char *fname_baseval) +{ + static struct iterator i; + unsigned first_audio; + FILE *cddb_form; + char fname[200]; + char *pp; + + if (fname_baseval == NULL || fname_baseval[0] == 0) + return; + + if (!strcmp(fname_baseval,"standard_output")) return; + InitIterator(&i, 1); + + strncpy(fname, fname_baseval, sizeof(fname) -1); + fname[sizeof(fname) -1] = 0; + pp = strrchr(fname, '.'); + if (pp == NULL) { + pp = fname + strlen(fname); + } + strncpy(pp, ".cddb", sizeof(fname) - 1 - (pp - fname)); + + cddb_form = fopen(fname, "w"); + if (cddb_form == NULL) return; + + first_audio = FirstAudioTrack(); + fprintf( cddb_form, "# xmcd\n#\n"); + fprintf( cddb_form, "# Track frame offsets:\n#\n"); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + if (GETTRACK(p) == CDROM_LEADOUT) break; + fprintf( cddb_form, + "# %lu\n", 150 + Get_AudioStartSector(GETTRACK(p))); + } + + fprintf( cddb_form, "#\n# Disc length: %lu seconds\n#\n", + (150 + Get_StartSector(CDROM_LEADOUT)) / 75); + fprintf( cddb_form, "# Revision: %u\n", global.cddb_revision ); + fprintf( cddb_form, "# Submitted via: icedax " VERSION "\n" ); + + fprintf( cddb_form, "DISCID=%08lx\n", (unsigned long)global.cddb_id); + + if (global.disctitle == NULL && global.creator == NULL) { + fprintf( cddb_form, "DTITLE=\n"); + } else { + if (global.creator == NULL) { + escape_and_split( cddb_form, "DTITLE=", global.disctitle, ""); + } else if (global.disctitle == NULL) { + escape_and_split( cddb_form, "DTITLE=", global.creator, ""); + } else { + escape_and_split( cddb_form, "DTITLE=", global.creator, " / ", global.disctitle, ""); + } + } + if (global.cddb_year != 0) + fprintf( cddb_form, "DYEAR=%4u\n", global.cddb_year); + else + fprintf( cddb_form, "DYEAR=\n"); + fprintf( cddb_form, "DGENRE=%s\n", global.cddb_genre); + + i.reset(&i); + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + int ii; + + ii = GETTRACK(p); + if (ii == CDROM_LEADOUT) break; + + if (global.tracktitle[ii] != NULL) { + char prefix[10]; + sprintf(prefix, "TTITLE%d=", ii-1); + escape_and_split( cddb_form, prefix, global.tracktitle[ii], ""); + } else { + fprintf( cddb_form, "TTITLE%d=\n", ii-1); + } + } + + if (global.copyright_message == NULL) { + fprintf( cddb_form, "EXTD=\n"); + } else { + escape_and_split( cddb_form, "EXTD=", "Copyright ", global.copyright_message, ""); + } + + i.reset(&i); + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + int ii; + + ii = GETTRACK(p); + + if (ii == CDROM_LEADOUT) break; + + fprintf( cddb_form, "EXTT%d=\n", ii-1); + } + fprintf( cddb_form, "PLAYORDER=\n"); + fclose( cddb_form ); +} + +#if defined USE_REMOTE +#include <pwd.h> + +static int readn(register int fd, register char *ptr, register int nbytes) +{ + int nread; + + nread = read(fd, ptr, nbytes); +#ifdef DEBUG_CDDBP + if (nread > 0) { + fprintf(stderr, "READ :(%d)", nread); + write(2, ptr, nread); + } +#endif + if (nread < 0) { + perror("socket read error: "); + fprintf(stderr, "fd=%d, ptr=%p, nbytes=%d\n", fd, ptr, nbytes); + } + + return nread; +} + +static ssize_t writez(int fd, const char *ptr) +{ + size_t nleft, nbytes; + + nleft = nbytes = strlen(ptr); + + while (nleft > 0) { + ssize_t nwritten = write(fd, ptr, nleft); + if (nwritten <= 0) { + return nwritten; /* return error */ + } +#ifdef DEBUG_CDDBP + fprintf(stderr, "WRITE:%s\n", ptr); +#endif + + nleft -= nwritten; + ptr += nwritten; + } + + return nbytes - nleft; +} + +#define SOCKBUFF 2048 + +static void filter_nonprintable(char *c, size_t l) +{ + size_t i; + for(i = 0; i < l; ++i) { + if(!isprint(c[i]) && !isspace(c[i])) { + c[i] = '_'; + } + } +} + + +int process_cddb_titles(int sock_fd, char *inbuff, int readbytes); +int process_cddb_titles(int sock_fd, char *inbuff, int readbytes) +{ + int finished = 0; + char *p = inbuff; + int ind = 0; + unsigned char ** target = &global.creator; + + do { + while (readbytes > 0) { + /* do we have a complete line in the buffer? */ + p = (char *)memchr(inbuff+ind, '\n', readbytes); + if (p == NULL) break; + + /* look for the terminator first */ + if (!strncmp(".\r\n", inbuff+ind, 3)) { + finished = 1; + break; + } + /* kill carriage return */ + if (p > inbuff+ind && *(p-1) == '\r') { + *(p-1) = '\0'; + } + /* kill line feed */ + *p = '\0'; + + /* handle escaped characters */ + + { + char *q = inbuff+ind; + while (*q) { + if (*q++ == '\\' && *q != '\0') { + if (*q == '\\') { + readbytes--; + p--; + memmove(q, q+1, readbytes - (q-inbuff-ind)); + } else if (*q == 'n') { + *(q-1) = '\n'; + readbytes--; + p--; + memmove(q, q+1, readbytes - (q-inbuff-ind)); + } else if (*q == 't') { + *(q-1) = '\t'; + readbytes--; + p--; + memmove(q, q+1, readbytes - (q-inbuff-ind)); + } + } + } + + } + + /* handle multi line entries concatenate fields */ + +/* TODO if the delimiter is split into two lines, it is not recognized. */ + if (!strncmp(inbuff+ind, "DTITLE=", 7)) { + char *res = strstr(inbuff+ind+7, " / "); + int clen; + char *q; + + if (res == NULL) { + /* no limiter found yet */ + /* copy until the end */ + q = p; + } else { + /* limiter found */ + /* copy until the limiter */ + q = res; + *q = '\0'; + } + + clen = q - (inbuff+ind+7); + if (*target == NULL) { + *target = malloc(clen+1); + if (*target != NULL) + **target = '\0'; + } else { + *target = realloc(*target, strlen((char *)*target) + clen - 1); + } + if (*target != NULL) { + strcat((char *)*target, inbuff+ind+7); + } + + /* handle part after the delimiter, if present */ + if (res != NULL) { + target = (unsigned char **)&global.disctitle; + /* skip the delimiter */ + q += 3; + clen = p - q; + if (*target == NULL) { + *target = malloc(clen+1); + if (*target != NULL) + **target = '\0'; + } + if (*target != NULL) { + strcat((char *)*target, q); + } + } + } else if (!strncmp(inbuff+ind, "TTITLE", 6)) { + char *q = (char *)memchr(inbuff+ind, '=', readbytes); + unsigned tno; + + if (q != NULL) { + *q = '\0'; + tno = (unsigned)atoi(inbuff+ind+6); + tno++; + if (tno < 100) { + if (global.tracktitle[tno] == NULL) { + global.tracktitle[tno] = malloc( p - q + 1 ); + if (global.tracktitle[tno] != NULL) + *(global.tracktitle[tno]) = '\0'; + } else { + global.tracktitle[tno] = realloc(global.tracktitle[tno], strlen((char *)global.tracktitle[tno]) + p - q + 1 ); + } + if (global.tracktitle[tno] != NULL) { + strcat((char *)global.tracktitle[tno], q+1); + } + } + } + } else if (!strncmp(inbuff+ind, "DYEAR", 5)) { + char *q = (char *)memchr(inbuff+ind, '=', readbytes); + if (q++ != NULL) { + sscanf(q, "%d", &global.cddb_year); + } + } else if (!strncmp(inbuff+ind, "DGENRE", 6)) { + char *q = (char *)memchr(inbuff+ind, '=', readbytes); + if (q++ != NULL) { + /* patch from Joe Nuzman, thanks */ + /* might have significant whitespace */ + strncpy(global.cddb_genre, q, sizeof(global.cddb_genre)-1); + /* always have a terminator */ + global.cddb_genre[sizeof(global.cddb_genre)-1] = '\0'; + } + } else if (!strncmp(inbuff+ind, "# Revision: ", 12)) { + char *q = inbuff+ind+11; + sscanf(q, "%d", &global.cddb_revision); + global.cddb_revision++; + } + readbytes -= (p - inbuff -ind) + 1; + ind = (p - inbuff) + 1; + } + if (!finished) { + int newbytes; + memmove(inbuff, inbuff+ind, readbytes); + newbytes = readn(sock_fd, inbuff+readbytes, SOCKBUFF-readbytes); + if (newbytes < 0) { + fprintf(stderr, "Could not read from socket.\n"); + return 0; /* Caller checks for != 1 */ + } + filter_nonprintable(inbuff+readbytes, newbytes); + if (newbytes <= 0) + break; + readbytes += newbytes; + ind = 0; + } + } while (!(finished || readbytes == 0)); + return finished; +} + +static int handle_userchoice(char *p, unsigned size); + +static int handle_userchoice(char *p, unsigned size) +{ + unsigned nr = 0; + unsigned user_choice; + int i; + char *q; + char *o; + + /* count lines. */ + q = p; + while ((q = (char *)memchr(q, '\n', size - (q-p))) != NULL) { + nr++; + q++; + } + if (nr > 1) nr--; + + /* handle escaped characters */ + + { + char *r = p; + while (*r) { + if (*r++ == '\\' && *r != '\0') { + if (*r == '\\') { + size--; + memmove(r, r+1, size - (r-p)); + } else if (*r == 'n') { + *(r-1) = '\n'; + size--; + memmove(r, r+1, size - (r-p)); + } else if (*r == 't') { + *(r-1) = '\t'; + size--; + memmove(r, r+1, size - (r-p)); + } + } + } + } + + /* list entries. */ + q = p; + fprintf(stderr, "%u entries found:\n", nr); + for (q = (char *)memchr(q, '\n', size - (q-p)), o = p, i = 0; i < nr; i++) { + *q = '\0'; + fprintf(stderr, "%02u: %s\n", i, o); + o = q+1; + q = (char *)memchr(q, '\n', size - (q-p)); + } + fprintf(stderr, "%02u: ignore\n", i); + + /* get user response. */ + do { + fprintf(stderr, "please choose one (0-%u): ", nr); + scanf("%u", &user_choice); /* FIXME: check return value */ + } while (user_choice > nr); + + if (user_choice == nr) + return -1; + + /* skip to choice. */ + q = p; + for (i = 0; i <= (int)user_choice - 1; i++) { + q = (char *)memchr(q, '\0', size - (q-p)) + 1; + } + return q-p; +} + +/* request disc and track titles from a cddbp server. + * + * return values: + * 0 titles have been found exactly (success) + * -1 some communication error happened. + * 1 titles have not been found. + * 2 multiple fuzzy matches have been found. + */ +int +request_titles(void) +{ + int retval = 0; + int sock_fd; + struct sockaddr_in sa; + struct hostent *he; + struct servent *se; + struct passwd *pw = getpwuid(getuid()); + char hostname[HOST_NAME_MAX]; + char inbuff[SOCKBUFF]; + char outbuff[SOCKBUFF]; + int i; + char category[64]; + unsigned cat_offset; + unsigned disc_id; + ssize_t readbytes; + + sock_fd = socket(AF_INET, SOCK_STREAM, 0); + if (sock_fd < 0) { + perror("cddb socket failed: "); + retval = -1; + goto errout; + } + + /* TODO fallbacks + * freedb.freedb.org + * de.freedb.org + * at.freedb.org + */ + if (global.cddbp_server != NULL) + he = gethostbyname(global.cddbp_server); + else + he = gethostbyname(CDDBHOST /*"freedb.freedb.org"*/); + + if (he == NULL) { + perror("cddb cannot resolve freedb host: "); + he = malloc(sizeof(struct hostent)); + memset(he, 0 , sizeof(struct hostent)); + he->h_length = 4; + he->h_addrtype = AF_INET; + he->h_addr_list = malloc(4); + he->h_addr_list[0] = malloc(4); + ((struct in_addr *)(he->h_addr_list[0]))->s_addr = + /* kingfisher.berlios.de freedb.freedb.de */ + htonl(UINT_C(0xc3254d85)); /*0xc2610412*/ + he->h_name = "freedb.freedb.org"; +#if 0 + retval = -1; + goto errout; +#endif + } + + /* save result data IMMEDIATELY!! */ + memset(&sa, 0 , sizeof(struct sockaddr_in)); + sa.sin_family = he->h_addrtype; /* AF_INET; */ + sa.sin_addr.s_addr = ((struct in_addr *)((he->h_addr_list)[0]))->s_addr; + + se = NULL; + if (global.cddbp_port == NULL) + se = getservbyname("cddbp-alt", "tcp"); + + if (se == NULL) { + if (global.cddbp_port == NULL) { + se = getservbyname("cddbp", "tcp"); + } + if (se == NULL) { + se = malloc(sizeof(struct servent)); + memset(se, 0 , sizeof(struct servent)); + se->s_port = htons(CDDBPORT /*8880*/); +#if 0 + perror("cddb cannot resolve cddbp or cddbp-alt port:\n "); + retval = -1; + goto errout; +#endif + } + } + if (global.cddbp_port != NULL) { + se->s_port = htons(atoi(global.cddbp_port)); + } + + sa.sin_port = se->s_port; + +/* TODO timeout */ + if (0 > connect(sock_fd, (struct sockaddr *)&sa, + sizeof(struct sockaddr_in))) { + perror("cddb connect failed: "); + retval = -1; + goto errout; + } + + /* read banner */ + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + + if (strncmp(inbuff, "200 ", 4) && strncmp(inbuff, "201 ", 4)) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, readbytes); + fprintf(stderr, "bad status from freedb server during sign-on banner: %s\n", inbuff); + retval = -1; + goto errout; + } + + /* say hello */ + hostname[0] = '\0'; + if (0 > gethostname(hostname, sizeof(hostname))) + strcpy(hostname, "unknown_host"); + hostname[sizeof(hostname)-1] = '\0'; + writez(sock_fd, "cddb hello "); + if (pw != NULL) { + BOOL space_err = FALSE; + BOOL ascii_err = FALSE; + /* change spaces to underscores */ + char *q = pw->pw_name; + while (*q != '\0') { + if (*q == ' ') { + if (!space_err) { + space_err = TRUE; + errmsgno(EX_BAD, + "Warning: Space in user name '%s'.\n", + pw->pw_name); + } + *q = '_'; + } + if (*q < ' ' || *q > '~') { + if (!ascii_err) { + ascii_err = TRUE; + errmsgno(EX_BAD, + "Warning: Nonascii character in user name '%s'.\n", + pw->pw_name); + } + *q = '_'; + } + q++; + } + writez(sock_fd, pw->pw_name); + writez(sock_fd, " "); + } else { + writez(sock_fd, "unknown "); + } + + /* change spaces to underscores */ + { + char *q = hostname; + BOOL space_err = FALSE; + BOOL ascii_err = FALSE; + + while (*q != '\0') { + if (*q == ' ') { + if (!space_err) { + space_err = TRUE; + errmsgno(EX_BAD, + "Warning: Space in hostname '%s'.\n", + hostname); + } + *q = '_'; + } + if (*q < ' ' || *q > '~') { + if (!ascii_err) { + ascii_err = TRUE; + errmsgno(EX_BAD, + "Warning: Nonascii character in hostname '%s'.\n", + hostname); + } + *q = '_'; + } + q++; + } + } + + writez(sock_fd, hostname); + writez(sock_fd, " icedax " VERSION "\n"); + + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + if (strncmp(inbuff, "200 ", 4)) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, readbytes); + fprintf(stderr, "bad status from freedb server during hello: %s\n", inbuff); + retval = -1; + goto signoff; + } + + /* enable new protocol variant. Weird command here, no cddb prefix ?!?! */ + writez(sock_fd, "proto\n"); + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + /* check for errors and maximum supported protocol level */ + if (strncmp(inbuff, "201 ", 4) > 0) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, readbytes); + fprintf(stderr, "bad status from freedb server during proto command: %s\n", inbuff); + retval = -1; + goto signoff; + } + + /* check the supported protocol level */ + if (!memcmp(inbuff, "200 CDDB protocol level: current 1, supported ", 46)) { + char *q = strstr(inbuff, " supported "); + unsigned pr_level; + + if (q != NULL) { + q += 11; + sscanf(q, "%u\n", &pr_level); + if (pr_level > 1) { + if (pr_level > 5) + pr_level = 5; + sprintf(inbuff, "proto %1u\n", pr_level); + writez(sock_fd, inbuff); + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + /* check for errors and maximum supported protocol level */ + if (strncmp(inbuff, "201 ", 4) > 0) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, + readbytes); + fprintf(stderr, "bad status from freedb server during proto x: %s\n", inbuff); + retval = -1; + goto signoff; + } + } + } + } + + /* format query string */ + /* query */ +#define CDDPB_INCLUDING_DATATRACKS +#ifdef CDDPB_INCLUDING_DATATRACKS + sprintf(outbuff, "cddb query %08lx %ld ", (unsigned long)global.cddb_id, LastTrack() - FirstTrack() + 1); + /* first all leading datatracks */ + { + int j = FirstAudioTrack(); + if (j < 0) + j = LastTrack() +1; + for (i = FirstTrack(); i < j; i++) { + sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_StartSector(i)); + } + } +#else + sprintf(outbuff, "cddb query %08lx %ld ", global.cddb_id, LastAudioTrack() - FirstAudioTrack() + 1); +#endif + /* all audio tracks */ + for (i = FirstAudioTrack(); i != -1 && i <= LastAudioTrack(); i++) { + sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_AudioStartSector(i)); + } +#ifdef CDDPB_INCLUDING_DATATRACKS + /* now all trailing datatracks */ + for (; i != -1 && i <= LastTrack(); i++) { + sprintf(outbuff + strlen(outbuff), "%ld ", 150 + Get_StartSector(i)); + } + sprintf(outbuff + strlen(outbuff), "%lu\n", + (150 + Get_StartSector(CDROM_LEADOUT)) / 75); +#else + sprintf(outbuff + strlen(outbuff), "%lu\n", + (150 + Get_LastSectorOnCd(FirstAudioTrack())) / 75); +#endif +/* strcpy(outbuff, "cddb query 9709210c 12 150 12010 33557 50765 65380 81467 93235 109115 124135 137732 152575 166742 2339\n"); */ +/* strcpy(outbuff, "cddb query 03015501 1 296 344\n"); */ + writez(sock_fd, outbuff); + + readbytes = readn(sock_fd, inbuff, sizeof(inbuff) - 1); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, readbytes); + cat_offset = 4; + if (!strncmp(inbuff, "210 ", 4) + || !strncmp(inbuff, "211 ", 4)) { + /* Check if there are really multiple entries. */ + char *p = (char *)memchr(inbuff, '\n', readbytes-1); + + if (p != NULL) cat_offset = p+1 - inbuff; + /* first entry */ + if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p); + /* second entry */ + if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p); + /* . */ + if (p) p = (char *)memchr(p+1, '\n', inbuff+readbytes - p); + if (p) { + /* multiple entries */ + switch (global.cddbp) { + case 2: /* take the first entry */ + break; + case 1: /* ask user */ + if (!global.gui) { + int userret = handle_userchoice(inbuff+cat_offset, readbytes - cat_offset); + if (userret == -1) { + /* ignore any selection */ + retval = -1; + goto signoff; + } + cat_offset += userret; + } + break; + default: + fprintf(stderr, "multiple entries found: %s\n", inbuff); + retval = 2; + goto signoff; + } + } + + } else if (strncmp(inbuff, "200 ", 4)) { + if (!strncmp(inbuff, "202 ", 4)) { + fprintf(stderr, "no cddb entry found: %s\n", inbuff); + retval = 1; + } else { + fprintf(stderr, "bad status from freedb server during query: %s\n%s", inbuff, outbuff); + retval = -1; + } + goto signoff; + } + sscanf(inbuff + cat_offset, "%s %x", category, &disc_id ); + + + /* read */ + sprintf(inbuff, "cddb read %s %08x\n", category, disc_id); + writez(sock_fd, inbuff); + + /* read status and first buffer size. */ + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + filter_nonprintable(inbuff, readbytes); + if (strncmp(inbuff, "210 ", 4)) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + fprintf(stderr, "bad status from freedb server during read: %s\n", inbuff); + retval = -1; + goto signoff; + } + + if (1 != process_cddb_titles(sock_fd, inbuff, readbytes)) { + fprintf(stderr, "cddb read finished not correctly!\n"); + } + +signoff: + /* sign-off */ + writez(sock_fd, "quit\n"); + readbytes = readn(sock_fd, inbuff, sizeof(inbuff)); + if (readbytes < 0) { + fprintf(stderr, "Could not read from socket\n"); + retval = -1; + goto errout; + } + if (strncmp(inbuff, "230 ", 4)) { + if(readbytes == sizeof(inbuff)) + --readbytes; + inbuff[readbytes] = '\0'; + filter_nonprintable(inbuff, readbytes); + fprintf(stderr, "bad status from freedb server during quit: %s\n", inbuff); + goto errout; + } + +errout: + close(sock_fd); + return retval; +} +#endif +#endif + +#if defined CDINDEX_SUPPORT + +static int IsSingleArtist(void); + +/* check, if there are more than one track creators */ +static int IsSingleArtist(void) +{ + static struct iterator i; + InitIterator(&i, 1); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + int ii; + + if (IS__DATA(p) || GETTRACK(p) == CDROM_LEADOUT) continue; + + ii = GETTRACK(p); + if (global.creator && global.trackcreator[ii] + && strcmp((char *) global.creator, + (char *) global.trackcreator[ii]) != 0) + return 0; + } + return 1; +} + +static const char *a2h[255-191] = { +"À", +"Á", +"Â", +"Ã", +"Ä", +"Å", +"Æ", +"Ç", +"È", +"É", +"Ê", +"Ë", +"Ì", +"Í", +"Î", +"Ï", +"Ð", +"Ñ", +"Ò", +"Ó", +"Ô", +"Õ", +"Ö", +"×", +"Ø", +"Ù", +"Ú", +"Û", +"Ü", +"Ý", +"Þ", +"ß", +"à", +"á", +"â", +"ã", +"ä", +"å", +"æ", +"ç", +"è", +"é", +"ê", +"ë", +"ì", +"í", +"î", +"ï", +"ð", +"ñ", +"ò", +"ó", +"ô", +"õ", +"ö", +"÷", +"ø", +"ù", +"ú", +"û", +"ü", +"ý", +"þ", +"ÿ", +}; + +static char *ascii2html(unsigned char *inp) +{ + static size_t buflen = 256; + static char *outline = 0; + size_t pos = 0; + size_t l=0; + + /* init */ + if(!outline) { + outline = malloc(buflen); + if(outline == 0) { + fprintf(stderr, "error: memory exhausted\n"); + _exit(EXIT_FAILURE); + } + } + + outline[pos] = '\0'; + + while (*inp != '\0') { + + /* Pick the sequence to insert */ + const char *insert; + char b[2]; + const int c = (unsigned char)*inp; + switch(c) { + case '"': insert = """; break; + case '&': insert = "&"; break; + case '<': insert = "<"; break; + case '>': insert = ">"; break; + case 160: insert = " "; break; + default: { + if(c < 192) { + b[0] = c; + b[1] = '\0'; + insert = b; + } else { + insert = a2h[c - 192]; + } + } + }; + + /* Resize buffer */ + l = strlen(insert); + while(pos + l + 1 >= buflen) { + outline = realloc(outline, buflen *= 2); + if(outline == 0) { + fprintf(stderr, "error: memory exhausted\n"); + _exit(EXIT_FAILURE); + } + } + + /* Copy in */ + strcpy(&outline[pos], insert); + pos += l; + + ++inp; + } + + return outline; +} + +static void emit_cdindex_form(char *fname_baseval) +{ + FILE *cdindex_form; + char fname[200]; + char *pp; + + if (fname_baseval == NULL || fname_baseval[0] == 0) + return; + + strncpy(fname, fname_baseval, sizeof(fname) -1); + fname[sizeof(fname) -1] = 0; + pp = strrchr(fname, '.'); + if (pp == NULL) { + pp = fname + strlen(fname); + } + strncpy(pp, ".cdindex", sizeof(fname) - 1 - (pp - fname)); + + cdindex_form = fopen(fname, "w"); + if (cdindex_form == NULL) return; + +#define CDINDEX_URL "http://www.musicbrainz.org/dtd/CDInfo.dtd" + + /* format XML page according to cdindex DTD (see www.musicbrainz.org) */ + fprintf( cdindex_form, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<!DOCTYPE CDInfo SYSTEM \"%s\">\n\n<CDInfo>\n", + CDINDEX_URL); + + fprintf( cdindex_form, " <Title>%s</Title>\n", + global.disctitle ? ascii2html(global.disctitle) : ""); + /* + * In case of mixed mode and Extra-CD, nonaudio tracks are included! + */ + fprintf( cdindex_form, " <NumTracks>%d</NumTracks>\n\n", cdtracks); + fprintf( cdindex_form, " <IdInfo>\n <DiskId>\n <Id>%s</Id>\n </DiskId>\n", global.cdindex_id); + + fprintf( cdindex_form, " </IdInfo>\n\n"); + + if (IsSingleArtist()) { + static struct iterator i; + InitIterator(&i, 1); + + fprintf( cdindex_form, " <SingleArtistCD>\n <Artist>%s</Artist>\n", + global.creator ? ascii2html(global.creator) : ""); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + int ii = GETTRACK(p); + + if (ii == CDROM_LEADOUT) break; + if (IS__AUDIO(p)) { + fprintf( cdindex_form, + " <Track Num=\"%d\">\n <Name>%s</Name>\n </Track>\n", + ii, global.tracktitle[ii] ? ascii2html(global.tracktitle[ii]) : ""); + } else { + fprintf( cdindex_form, + " <Track Num=\"%d\">\n <Name>data track</Name>\n </Track>\n", + ii ); + } + } + fprintf( cdindex_form, " </SingleArtistCD>\n"); + } else { + static struct iterator i; + InitIterator(&i, 1); + + fprintf( cdindex_form, " <MultipleArtistCD>\n"); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + int ii = GETTRACK(p); + + if (ii == CDROM_LEADOUT) break; + if (IS__AUDIO(p)) { + fprintf( cdindex_form, " <Artist>%s</Artist>\n", + global.trackcreator[ii] ? ascii2html(global.trackcreator[ii]) : ""); + fprintf( cdindex_form, " <Name>%s</Name>\n </Track>\n", + global.tracktitle[ii] ? ascii2html(global.tracktitle[ii]) : ""); + } else { + fprintf( cdindex_form, + " <Artist>data track</Artist>\n <Name>data track</Name>\n </Track>\n"); + } + } + fprintf( cdindex_form, " </MultipleArtistCD>\n"); + } + fprintf( cdindex_form, "</CDInfo>\n"); + + fclose( cdindex_form ); +} +#endif + +static void dump_cdtext_info(void) +{ +#ifdef CD_TEXT + /* interpret the contents of CD Text information based on an early draft + of SCSI-3 mmc version 2 from jan 2, 1998 + CD Text information consists of a text group containing up to + 8 language blocks containing up to + 255 Pack data chunks of + 18 bytes each. + So we have at most 36720 bytes to cope with. + */ + { + short int datalength; + unsigned char *p = bufferTOC; + unsigned char lastline[255*12]; + int lastitem = -1; + int itemcount = 0; + int inlinecount = 0; + int outlinecount = 0; + + lastline[0] = '\0'; + datalength = ((p[0] << 8) + p[1]) - 2; + datalength = min(datalength, 2048-4); + p += 4; + for (;datalength > 0; + datalength -= sizeof (cdtextpackdata), + p += sizeof (cdtextpackdata)) { + unsigned char *zeroposition; + + /* handle one packet of CD Text Information Descriptor Pack Data */ + /* this is raw R-W subchannel data converted to 8 bit values. */ + cdtextpackdata *c = (cdtextpackdata *)p; + int dbcc; + int crc_error; + unsigned tracknr; + +#ifdef DEBUG_CDTEXT + fprintf(stderr, "datalength =%d\n", datalength); +#endif + crc_error = !cdtext_crc_ok(c); + + if (lastitem != c->headerfield[0]) { + itemcount = 0; + lastitem = c->headerfield[0]; + } + + tracknr = c->headerfield[1] & 0x7f; + dbcc = ((unsigned)(c->headerfield[3] & 0x80)) >> 7; /* double byte character code */ + +#if defined DEBUG_CDTEXT + { + int extension_flag; + int sequence_number; + int block_number; + int character_position; + + extension_flag = ((unsigned)(c->headerfield[1] & 0x80)) >> 7; + sequence_number = c->headerfield[2]; + block_number = ((unsigned)(c->headerfield[3] & 0x30)) >> 4; /* language */ + character_position = c->headerfield[3] & 0x0f; + + fprintf(stderr, "CDText: ext_fl=%d, trnr=%u, seq_nr=%d, dbcc=%d, block_nr=%d, char_pos=%d\n", + extension_flag, tracknr, sequence_number, dbcc, block_number, character_position); + } +#endif + + /* print ASCII information */ + memcpy(lastline+inlinecount, c->textdatafield, 12); + inlinecount += 12; + zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount); + while (zeroposition != NULL) { + process_header(c, tracknr, dbcc, lastline+outlinecount); + outlinecount += zeroposition - (lastline+outlinecount) + 1; + +#if defined DEBUG_CDTEXT + fprintf(stderr, "\tin=%d, out=%d, items=%d, trcknum=%u\n", inlinecount, outlinecount, itemcount, tracknr); +{ int q; for (q= outlinecount; q < inlinecount; q++) fprintf (stderr, "%c", lastline[q] ? lastline[q] : 'ß'); fputs("\n", stderr); } +#else + if (DETAILED) { + if (crc_error) fputs(" ! uncorr. CRC-Error", stderr); + fputs("\n", stderr); + } +#endif + + itemcount++; + if (itemcount > (int)cdtracks + || (c->headerfield[0] == 0x8f + || (c->headerfield[0] <= 0x8d && c->headerfield[0] >= 0x86))) { + outlinecount = inlinecount; + break; + } + tracknr++; + zeroposition = (unsigned char *)memchr(lastline+outlinecount, '\0', inlinecount-outlinecount); + } + } + } +#endif +} + + + +static void dump_extra_info(unsigned int from) +{ +#ifdef CD_EXTRA + unsigned char *p; + unsigned pos, length; + + if (from == 0) return; + + p = Extra_buffer + 48; + while (*p != '\0') { + pos = GET_BE_UINT_FROM_CHARP(p+2); + length = GET_BE_UINT_FROM_CHARP(p+6); + if (pos == (unsigned)-1) { + pos = from+1; + } else { + pos += session_start; + } + +#ifdef DEBUG_XTRA + if (global.gui == 0 && global.verbose != 0) { + fprintf(stderr, "Language: %c%c (as defined by ISO 639)", *p, *(p+1)); + fprintf(stderr, " at sector %u, len=%u (sessionstart=%u)", pos, length, session_start); + fputs("\n", stderr); + } +#endif + /* dump this entry */ + Read_Subinfo(pos, length); + p += 10; + + if (p + 9 > (Extra_buffer + CD_FRAMESIZE)) + break; + } +#endif +} + +static char *quote(unsigned char *string); + +static char *quote(unsigned char *string) +{ + static char result[200]; + unsigned char *p = (unsigned char *)result; + + while (*string) { + if (*string == '\'' || *string == '\\') { + *p++ = '\\'; + } + *p++ = *string++; + } + *p = '\0'; + + return result; +} + + + +static void DisplayToc_with_gui(unsigned long dw); + +static void DisplayToc_with_gui(unsigned long dw) +{ + unsigned mins; + unsigned secnds; + unsigned frames; + int count_audio_trks; + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + mins = dw / ( 60*75 ); + secnds = ( dw % ( 60*75 ) ) / 75; + frames = ( dw % 75 ); + + /* summary */ + count_audio_trks = 0; + + if ((global.verbose & SHOW_STARTPOSITIONS) != 0) { + if (global.illleadout_cd != 0 && have_CD_extra == 0) { + fprintf( stderr, "Tracks:%u > %u:%02u.%02u\n", cdtracks, mins, secnds, frames ); + } else { + fprintf( stderr, "Tracks:%u %u:%02u.%02u\n", cdtracks, mins, secnds, frames ); + } + } + + if (global.quiet == 0) { + fprintf( stderr, "CDINDEX discid: %s\n", global.cdindex_id); + fprintf( stderr, "CDDB discid: 0x%08lx", (unsigned long) global.cddb_id); + + if (have_CDDB != 0) { + fprintf(stderr, " CDDBP titles: resolved\n"); + } else { + fprintf(stderr, "\n"); + } + if (have_CD_text != 0) { + fprintf(stderr, "CD-Text: detected\n"); + dump_cdtext_info(); + } else { + fprintf(stderr, "CD-Text: not detected\n"); + } + if (have_CD_extra != 0) { + fprintf(stderr, "CD-Extra: detected\n"); + dump_extra_info(have_CD_extra); + } else { + fprintf(stderr, "CD-Extra: not detected\n"); + } + + fprintf( stderr, + "Album title: '%s'", (void *)global.disctitle != NULL + ? quote(global.disctitle) : ""); + + fprintf( stderr, " from '%s'\n", (void *)global.creator != NULL + ? quote(global.creator) : ""); + } + count_audio_trks = 0; + + + if ((global.verbose & (SHOW_TOC | SHOW_STARTPOSITIONS | SHOW_SUMMARY | SHOW_TITLES)) != 0 + && i.hasNextTrack(&i)) { + TOC *o = i.getNextTrack(&i); + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + int from; + from = GETTRACK(o); + + fprintf(stderr, "T%02d:", from); + + if (IS__DATA(o)) { + /* + * Special case of cd extra + */ + unsigned int real_start = have_CD_extra + ? have_CD_extra : GETSTART(o); + + + dw = (unsigned long) (GETSTART(p) - real_start); + + mins = dw / ( 60*75 ); + secnds = ( dw % ( 60*75 )) / 75; + frames = ( dw % 75 ); + + if ( global.verbose & SHOW_STARTPOSITIONS ) + fprintf(stderr, + " %7u", + real_start + ); + + if ( global.verbose & SHOW_TOC ) + fprintf(stderr, + " %2u:%02u.%02u", + mins, secnds, frames + ); + + if ( global.verbose & SHOW_SUMMARY ) + fprintf(stderr, + " data %s %s N/A", + + /* how recorded */ + IS__INCREMENTAL(o) + ? "incremental" : "uninterrupted", + + /* copy-permission */ + IS__COPYRIGHTED(o) + ? "copydenied" : "copyallowed" + ); + fputs("\n", stderr); + } else { + dw = (unsigned long) (GETSTART(p) - GETSTART(o)); + mins = dw / ( 60*75 ); + secnds = ( dw % ( 60*75 )) / 75; + frames = ( dw % 75 ); + + if ( global.verbose & SHOW_STARTPOSITIONS ) + fprintf(stderr, + " %7u", + GETSTART(o) + ); + + if ( global.verbose & SHOW_TOC ) + fprintf(stderr, + " %2u:%02u.%02u", + mins, secnds, frames + ); + + if ( global.verbose & SHOW_SUMMARY ) + fprintf(stderr, + " audio %s %s %s", + + /* how recorded */ + IS__PREEMPHASIZED(o) + ? "pre-emphasized" : "linear", + + /* copy-permission */ + IS__COPYRIGHTED(o) + ? "copydenied" : "copyallowed", + + /* channels */ + IS__QUADRO(o) + ? "quadro" : "stereo"); + + /* Title */ + if ( global.verbose & SHOW_TITLES ) { + fprintf(stderr, + " title '%s' from ", + + (void *) global.tracktitle[GETTRACK(o)] != NULL + ? quote(global.tracktitle[GETTRACK(o)]) : "" + ); + + fprintf(stderr, + "'%s'", + + (void *) global.trackcreator[GETTRACK(o)] != NULL + ? quote(global.trackcreator[GETTRACK(o)]) : "" + ); + } + fputs("\n", stderr); + count_audio_trks++; + } + o = p; + } /* while */ + if ( global.verbose & SHOW_STARTPOSITIONS ) + if (GETTRACK(o) == CDROM_LEADOUT) { + fprintf(stderr, "Leadout: %7u\n", GETSTART(o)); + } + } /* if */ +} + +static void DisplayToc_no_gui(unsigned long dw); + +static void DisplayToc_no_gui(unsigned long dw) +{ + unsigned mins; + unsigned secnds; + unsigned frames; + int count_audio_trks; + unsigned ii = 0; + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + mins = dw / ( 60*75 ); + secnds = ( dw % ( 60*75 ) ) / 75; + frames = ( dw % 75 ); + + /* summary */ + count_audio_trks = 0; + + if (i.hasNextTrack(&i)) { + TOC *o = i.getNextTrack(&i); + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + int from; + from = GETTRACK(o); + + + while ( p != NULL && GETTRACK(p) != CDROM_LEADOUT + && GETFLAGS(o) == GETFLAGS(p) ) { + o = p; + p = i.getNextTrack(&i); + } + if ((global.verbose & SHOW_SUMMARY) == 0) continue; + + if (IS__DATA(o)) { + fputs( " DATAtrack recorded copy-permitted tracktype\n" , stderr); + fprintf(stderr, + " %2d-%2d %13.13s %14.14s data\n", + from, + GETTRACK(o), + /* how recorded */ + IS__INCREMENTAL(o) + ? "incremental" : "uninterrupted", + + /* copy-perm */ + IS__COPYRIGHTED(o) ? "no" : "yes" + ); + } else { + fputs( "AUDIOtrack pre-emphasis copy-permitted tracktype channels\n" , stderr); + fprintf(stderr, + " %2d-%2d %12.12s %14.14s audio %1c\n", + from, + GETTRACK(o), + IS__PREEMPHASIZED(o) + ? "yes" : "no", + IS__COPYRIGHTED(o) ? "no" : "yes", + IS__QUADRO(o) ? '4' : '2' + ); + count_audio_trks++; + } + o = p; + } + } + if ((global.verbose & SHOW_STARTPOSITIONS) != 0) { + if (global.illleadout_cd != 0 && have_multisession == 0) { + + fprintf ( stderr, + "Table of Contents: total tracks:%u, (total time more than %u:%02u.%02u)\n", + cdtracks, mins, secnds, frames ); + } else { + fprintf ( stderr, + "Table of Contents: total tracks:%u, (total time %u:%02u.%02u)\n", + cdtracks, mins, secnds, frames ); + } + } + + i.reset(&i); + if ((global.verbose & SHOW_TOC) != 0 && + i.hasNextTrack(&i)) { + TOC *o = i.getNextTrack(&i); + + for (; i.hasNextTrack(&i);) { + TOC *p = i.getNextTrack(&i); + + if ( GETTRACK(o) <= MAXTRK ) { + unsigned char brace1, brace2; + unsigned trackbeg; + trackbeg = have_multisession && IS__DATA(o) ? have_multisession : GETSTART(o); + + dw = (unsigned long) (GETSTART(p) - trackbeg); + mins = dw / ( 60*75 ); + secnds = ( dw % ( 60*75 )) / 75; + frames = ( dw % 75 ); + + if ( IS__DATA(o) ) { + /* data track display */ + brace1 = '['; + brace2 = ']'; + } else if (have_multisession + && GETTRACK(o) == LastAudioTrack()) { + /* corrected length of + * last audio track in cd extra + */ + brace1 = '|'; + brace2 = '|'; + } else { + /* audio track display */ + brace1 = '('; + brace2 = ')'; + } + fprintf ( stderr, + " %2u.%c%2u:%02u.%02u%c", + GETTRACK(o), + brace1, + mins, secnds, frames, + brace2 + ); + ii++; + + if ( ii % 5 == 0 ) + fputs( ",\n", stderr ); + else if (ii != cdtracks) + fputc ( ',', stderr ); + } + o = p; + } /* for */ + if ( (ii % 5) != 0 ) + fputs( "\n", stderr ); + + } /* if */ + + if ((global.verbose & SHOW_STARTPOSITIONS) != 0) { + fputs ("\nTable of Contents: starting sectors\n", stderr); + + ii = 0; + i.reset(&i); + if (i.hasNextTrack(&i)) { + TOC *o = i.getNextTrack(&i); + for ( ; i.hasNextTrack(&i);) { + TOC *p = i.getNextTrack(&i); + fprintf ( stderr, + " %2u.(%8u)", + GETTRACK(o), + have_multisession + && GETTRACK(o) == FirstDataTrack() + ? have_multisession + : GETSTART(o) +#ifdef DEBUG_CDDB + +150 +#endif + ); + + ii++; + if ( (ii) % 5 == 0 ) + fputs( ",\n", stderr ); + else + fputc ( ',', stderr ); + o = p; + } + fprintf ( stderr, " lead-out(%8u)", GETSTART(o)); + fputs ("\n", stderr); + } + } + if (global.quiet == 0) { + fprintf(stderr, "CDINDEX discid: %s\n", global.cdindex_id); + fprintf( stderr, "CDDB discid: 0x%08lx", (unsigned long) global.cddb_id); + + if (have_CDDB != 0) { + fprintf(stderr, " CDDBP titles: resolved\n"); + } else { + fprintf(stderr, "\n"); + } + if (have_CD_text != 0) { + fprintf(stderr, "CD-Text: detected\n"); + } else { + fprintf(stderr, "CD-Text: not detected\n"); + } + if (have_CD_extra != 0) { + fprintf(stderr, "CD-Extra: detected\n"); + } else { + fprintf(stderr, "CD-Extra: not detected\n"); + } + } + if ((global.verbose & SHOW_TITLES) != 0) { + int maxlen = 0; + + if ( global.disctitle != NULL ) { + fprintf( stderr, "Album title: '%s'", global.disctitle); + if ( global.creator != NULL ) { + fprintf( stderr, "\t[from %s]", global.creator); + } + fputs("\n", stderr); + } + + i.reset(&i); + for ( ; i.hasNextTrack(&i);) { + TOC *p = i.getNextTrack(&i); + int jj = GETTRACK(p); + + if ( global.tracktitle[jj] != NULL ) { + int len = strlen((char *)global.tracktitle[jj]); + maxlen = max(maxlen, len); + } + } + maxlen = (maxlen + 12 + 8 + 7)/8; + + i.reset(&i); + for ( ; i.hasNextTrack(&i); ) { + TOC *p = i.getNextTrack(&i); + int jj; + + if (IS__DATA(p)) + continue; + + jj = GETTRACK(p); + + if (jj == CDROM_LEADOUT) + break; + + if ( maxlen != 3 ) { + if ( global.tracktitle[jj] != NULL ) { + fprintf( stderr, "Track %2u: '%s'", jj, global.tracktitle[jj]); + } else { + fprintf( stderr, "Track %2u: '%s'", jj, ""); + } + if ( global.trackcreator[jj] != NULL + && global.trackcreator[jj][0] != '\0' +#if 1 + && (global.creator == NULL + || 0 != strcmp((char *)global.creator,(char *)global.trackcreator[jj])) +#endif + ) { + int j; + char *o = global.tracktitle[jj] != NULL + ? (char *)global.tracktitle[jj] + : ""; + for ( j = 0; + j < (maxlen - ((int)strlen(o) + 12)/8); + j++) + fprintf(stderr, "\t"); + fprintf( stderr, "[from %s]", global.trackcreator[jj]); + } + fputs("\n", stderr); + } + } + } +} + +void DisplayToc(void) +{ + unsigned long dw; + + /* special handling of pseudo-red-book-audio cds */ + if (cdtracks > 1 + && Get_StartSector(CDROM_LEADOUT) < Get_StartSector(cdtracks)) { + global.illleadout_cd = 1; + can_read_illleadout(); + } + + + /* get total time */ + if (global.illleadout_cd == 0) + dw = (unsigned long) Get_StartSector(CDROM_LEADOUT) - Get_StartSector(1); + else + dw = (unsigned long) Get_StartSector(cdtracks ) - Get_StartSector(1); + + if ( global.gui == 0 ) { + /* table formatting when in cmdline mode */ + DisplayToc_no_gui( dw ); + } else if (global.gui == 1) { + /* line formatting when in gui mode */ + DisplayToc_with_gui( dw ); + } + + if (global.illleadout_cd != 0) { + if (global.quiet == 0) { + fprintf(stderr, "CD with illegal leadout position detected!\n"); + } + + if (global.reads_illleadout == 0) { + /* limit accessible tracks + * to lowered leadout position + */ + restrict_tracks_illleadout(); + + if (global.quiet == 0) { + fprintf(stderr, + "The cdrom drive firmware does not permit access beyond the leadout position!\n"); + } + if (global.verbose & (SHOW_ISRC | SHOW_INDICES)) { + global.verbose &= ~(SHOW_ISRC | SHOW_INDICES); + fprintf(stderr, "Switching index scan and ISRC scan off!\n"); + } + + if (global.quiet == 0) { + fprintf(stderr, + "Audio extraction will be limited to track %ld with maximal %ld sectors...\n", + LastTrack(), + Get_EndSector(LastTrack())+1 + ); + } + } else { + /* The cdrom drive can read beyond the + * indicated leadout. We patch a new leadout + * position to the maximum: + * 99 minutes, 59 seconds, 74 frames + */ + patch_real_end(150 + (99*60+59)*75 + 74); + if (global.quiet == 0) { + fprintf(stderr, + "Restrictions apply, since the size of the last track is unknown!\n"); + } + } + } +} + +static void Read_MCN_toshiba(subq_chnl **sub_ch); + +static void Read_MCN_toshiba(subq_chnl **sub_ch) +{ + if (Toshiba3401() != 0 && global.quiet == 0 + && ((*sub_ch) != 0 + || (((subq_catalog *)(*sub_ch)->data)->mc_valid & 0x80))) { + /* no valid MCN yet. do more searching */ + long h = Get_AudioStartSector(1); + + while (h <= Get_AudioStartSector(1) + 100) { + if (Toshiba3401()) + ReadCdRom(get_scsi_p(), RB_BASE->data, h, global.nsectors); + (*sub_ch) = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER,0); + if ((*sub_ch) != NULL) { + subq_catalog *subq_cat; + + subq_cat = (subq_catalog *) (*sub_ch)->data; + if ((subq_cat->mc_valid & 0x80) != 0) { + break; + } + } + h += global.nsectors; + } + } +} + +static void Get_Set_MCN(void); + +static void Get_Set_MCN(void) +{ + subq_chnl *sub_ch; + subq_catalog *subq_cat = NULL; + fprintf(stderr, "scanning for MCN..."); + + sub_ch = ReadSubQ(get_scsi_p(), GET_CATALOGNUMBER,0); + +#define EXPLICIT_READ_MCN_ISRC 1 +#if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */ + Read_MCN_toshiba( &sub_ch ); +#endif + + if (sub_ch != NULL) + subq_cat = (subq_catalog *)sub_ch->data; + + if (sub_ch != NULL + && (subq_cat->mc_valid & 0x80) != 0 + && global.quiet == 0) { + + /* unified format guesser: + * format MCN all digits in bcd + * 1 13 + * A: ab cd ef gh ij kl m0 0 0 0 0 0 0 Plextor 6x Rel. 1.02 + * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m Toshiba 3401 + * C: AS AS AS AS AS AS AS AS AS AS AS AS AS ASCII SCSI-2 Plextor 4.5x and 6x Rel. 1.06 + */ + unsigned char *cp = subq_cat->media_catalog_number; + if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12]) + && ((cp[0] & 0xf0) | (cp[1] & 0xf0) + | (cp[2] & 0xf0) | (cp[3] & 0xf0) + | (cp[4] & 0xf0) | (cp[5] & 0xf0) + | (cp[6] & 0xf0))) { + /* reformat A: to B: */ + cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf; + cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf; + cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf; + cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf; + cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf; + cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf; + cp[ 0] = cp[0] >> 4; + } + + if (!isdigit(cp[0]) + && (memcmp(subq_cat->media_catalog_number, + "\0\0\0\0\0\0\0\0\0\0\0\0\0", 13) != 0)) { + sprintf((char *) + subq_cat->media_catalog_number, + "%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X%1.1X", + subq_cat->media_catalog_number [0], + subq_cat->media_catalog_number [1], + subq_cat->media_catalog_number [2], + subq_cat->media_catalog_number [3], + subq_cat->media_catalog_number [4], + subq_cat->media_catalog_number [5], + subq_cat->media_catalog_number [6], + subq_cat->media_catalog_number [7], + subq_cat->media_catalog_number [8], + subq_cat->media_catalog_number [9], + subq_cat->media_catalog_number [10], + subq_cat->media_catalog_number [11], + subq_cat->media_catalog_number [12] + ); + } + + if (memcmp(subq_cat->media_catalog_number,"0000000000000",13) + != 0) { + Set_MCN(subq_cat->media_catalog_number); + } + } +} + + +static void Read_ISRC_toshiba(subq_chnl **sub_ch, unsigned tr); + +static void Read_ISRC_toshiba(subq_chnl **sub_ch, unsigned tr) +{ + if (Toshiba3401() != 0) { + int j; + j = (Get_AudioStartSector(tr)/100 + 1) * 100; + do { + ReadCdRom(get_scsi_p(), RB_BASE->data, j, global.nsectors); + *sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC, Get_Tracknumber(tr)); + if (*sub_ch != NULL) { + subq_track_isrc * subq_tr; + + subq_tr = (subq_track_isrc *) (*sub_ch)->data; + if (subq_tr != NULL && (subq_tr->tc_valid & 0x80) != 0) + break; + } + j += global.nsectors; + } while (j < (Get_AudioStartSector(tr)/100 + 1) * 100 + 100); + } +} + + +static void Get_Set_ISRC(unsigned tr); + +static void Get_Set_ISRC(unsigned tr) +{ + subq_chnl *sub_ch; + subq_track_isrc * subq_tr; + + fprintf(stderr, "\rscanning for ISRCs: %d ...", tr); + + subq_tr = NULL; + sub_ch = ReadSubQ(get_scsi_p(), GET_TRACK_ISRC, tr); + +#if EXPLICIT_READ_MCN_ISRC == 1 /* TOSHIBA HACK */ + Read_ISRC_toshiba( &sub_ch, tr ); +#endif + + if (sub_ch != NULL) + subq_tr = (subq_track_isrc *)sub_ch->data; + + if (sub_ch != NULL && (subq_tr->tc_valid & 0x80) + && global.quiet == 0) { + unsigned char p_start[16]; + unsigned char *p = p_start; + unsigned char *cp = subq_tr->track_isrc; + + /* unified format guesser: + * there are 60 bits and 15 bytes available. + * 5 * 6bit-items + two zero fill bits + 7 * 4bit-items + * + * A: ab cd ef gh ij kl mn o0 0 0 0 0 0 0 0 Plextor 6x Rel. 1.02 + * B: 0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k 0l 0m 0n 0o Toshiba 3401 + * C: AS AS AS AS AS AS AS AS AS AS AS AS AS AS AS ASCII SCSI-2 + * eg 'G''B''-''A''0''7''-''6''8''-''0''0''2''7''0' makes most sense + * D: 'G''B''A''0''7''6''8''0''0''2''7''0'0 0 0 Plextor 6x Rel. 1.06 and 4.5x R. 1.01 and 1.04 + */ + + /* Check for format A: */ + if (!(cp[8] | cp[9] | cp[10] | cp[11] | cp[12] | cp[13] | cp[14]) && + ((cp[0] & 0xf0) | (cp[1] & 0xf0) | (cp[2] & 0xf0) | + (cp[3] & 0xf0) | (cp[4] & 0xf0) | (cp[5] & 0xf0) | + (cp[6] & 0xf0) | (cp[7] & 0xf0))) { +#if DEBUG_ISRC + fprintf(stderr, "a!\t"); +#endif + /* reformat A: to B: */ + cp[14] = cp[7] >> 4; cp[13] = cp[6] & 0xf; + cp[12] = cp[6] >> 4; cp[11] = cp[5] & 0xf; + cp[10] = cp[5] >> 4; cp[ 9] = cp[4] & 0xf; + cp[ 8] = cp[4] >> 4; cp[ 7] = cp[3] & 0xf; + cp[ 6] = cp[3] >> 4; cp[ 5] = cp[2] & 0xf; + cp[ 4] = cp[2] >> 4; cp[ 3] = cp[1] & 0xf; + cp[ 2] = cp[1] >> 4; cp[ 1] = cp[0] & 0xf; + cp[ 0] = cp[0] >> 4; +#if DEBUG_ISRC + fprintf(stderr, "a->b: %15.15s\n", cp); +#endif + } + + /* Check for format B: + * If not yet in ASCII format, do the conversion + */ + if (cp[0] < '0' && cp[1] < '0') { + /* coding table for International Standard Recording Code */ + static char bin2ISRC[] = { + '0','1','2','3','4','5','6','7','8','9', /* 10 */ + ':',';','<','=','>','?','@', /* 17 */ + 'A','B','C','D','E','F','G','H','I','J','K', /* 28 */ + 'L','M','N','O','P','Q','R','S','T','U','V', /* 39 */ + 'W','X','Y','Z', /* 43 */ +#if 1 + '[','\\',']','^','_','`', /* 49 */ + 'a','b','c','d','e','f','g','h','i','j','k', /* 60 */ + 'l','m','n','o' /* 64 */ +#endif + }; + + /* build 6-bit vector of coded values */ + unsigned ind; + int bits; + +#if DEBUG_ISRC + fprintf(stderr, "b!\n"); +#endif + ind = (cp[0] << 26) + + (cp[1] << 22) + + (cp[2] << 18) + + (cp[3] << 14) + + (cp[4] << 10) + + (cp[5] << 6) + + (cp[6] << 2) + + (cp[7] >> 2); + + if ((cp[7] & 3) == 3) { + if (global.verbose) { + fprintf(stderr, + "Recorder-ID encountered: "); + for (bits = 0; bits < 30; bits +=6) { + unsigned binval = (ind & (ULONG_C(0x3f) << (24-bits))) + >> (24-bits); + if ((binval < sizeof(bin2ISRC)) && + (binval <= 9 || binval >= 16)) { + fprintf(stderr, "%X", bin2ISRC[binval]); + } + } + + fprintf(stderr, "%.1X%.1X%.1X%.1X%.1X%.1X%.1X", + subq_tr->track_isrc [8] & 0x0f, + subq_tr->track_isrc [9] & 0x0f, + subq_tr->track_isrc [10] & 0x0f, + subq_tr->track_isrc [11] & 0x0f, + subq_tr->track_isrc [12] & 0x0f, + subq_tr->track_isrc [13] & 0x0f, + subq_tr->track_isrc [14] & 0x0f + ); + fprintf(stderr, "\n"); + } + return; + } + if ((cp[7] & 3) != 0) { + fprintf(stderr, "unknown mode 3 entry C1=0x%02x, C2=0x%02x\n", + (cp[7] >> 1) & 1, cp[7] & 1); + return; + } + + /* decode ISRC due to IEC 908 */ + for (bits = 0; bits < 30; bits +=6) { + unsigned binval = (ind & ((unsigned long) 0x3fL << (24L-bits))) >> (24L-bits); + if ((binval >= sizeof(bin2ISRC)) || + (binval > 9 && binval < 16)) { + /* Illegal ISRC, dump and skip */ + int y; + + Get_ISRC(tr)[0] = '\0'; + fprintf(stderr, "\nIllegal ISRC for track %d, skipped: ", tr); + for (y = 0; y < 15; y++) { + fprintf(stderr, "%02x ", cp[y]); + } + fputs("\n", stderr); + return; + } + *p++ = bin2ISRC[binval]; + + /* insert a dash after two country characters for legibility */ + if (bits == 6) + *p++ = '-'; + } + + /* format year and serial number */ + sprintf ((char *)p, "-%.1X%.1X-%.1X%.1X%.1X%.1X%.1X", + subq_tr->track_isrc [8] & 0x0f, + subq_tr->track_isrc [9] & 0x0f, + subq_tr->track_isrc [10] & 0x0f, + subq_tr->track_isrc [11] & 0x0f, + subq_tr->track_isrc [12] & 0x0f, + subq_tr->track_isrc [13] & 0x0f, + subq_tr->track_isrc [14] & 0x0f + ); +#if DEBUG_ISRC + fprintf(stderr, "b: %15.15s!\n", p_start); +#endif + } else { + /* It might be in ASCII, surprise */ + int ii; + for (ii = 0; ii < 12; ii++) { + if (cp[ii] < '0' || cp[ii] > 'Z') { + break; + } + } + if (ii != 12) { + int y; + + Get_ISRC(ii)[0] = '\0'; + fprintf(stderr, "\nIllegal ISRC for track %d, skipped: ", ii+1); + for (y = 0; y < 15; y++) { + fprintf(stderr, "%02x ", cp[y]); + } + fputs("\n", stderr); + return; + } + +#if DEBUG_ISRC + fprintf(stderr, "ascii: %15.15s!\n", cp); +#endif + for (ii = 0; ii < 12; ii++) { +#if 1 + if ((ii == 2 || ii == 5 || ii == 7) && cp[ii] != ' ') + *p++ = '-'; +#endif + *p++ = cp[ii]; + } + if (p - p_start >= 16) + *(p_start + 15) = '\0'; + else + *p = '\0'; + } + + if (memcmp(p_start,"00-000-00-00000",15) != 0) { + Set_ISRC(tr, p_start); + } + } +} + +/* get and display Media Catalog Number ( one per disc ) + * and Track International Standard Recording Codes (for each track) + */ +void Read_MCN_ISRC(void) +{ + if ((global.verbose & SHOW_MCN) != 0) { + + if (Get_MCN()[0] == '\0') { + Get_Set_MCN(); + } + + if (Get_MCN()[0] != '\0') + fprintf(stderr, "\rMedia catalog number: %13.13s\n", Get_MCN()); + else + fprintf(stderr, "\rNo media catalog number present.\n"); + } + + + + if ((global.verbose & SHOW_ISRC) != 0) { + static struct iterator i; + + InitIterator(&i, 1); + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + unsigned ii = GETTRACK(p); + + if (ii == CDROM_LEADOUT) break; + + if (!IS__AUDIO(p)) + continue; + + if (GETISRC(p)[0] == '\0') { + Get_Set_ISRC(ii); + } + + if (GETISRC(p)[0] != '\0') { + fprintf (stderr, "\rT: %2d ISRC: %15.15s\n", ii, GETISRC(p)); + fflush(stderr); + } + } /* for all tracks */ + + fputs("\n", stderr); + } /* if SHOW_ISRC */ +} + +static int playing = 0; + +static subq_chnl *ReadSubChannel(unsigned sec); + +static subq_chnl *ReadSubChannel(unsigned sec) +{ + subq_chnl *sub_ch; + + /* + * For modern drives implement a direct method. If the drive supports + * reading of subchannel data, do direct reads. + */ + if (ReadSubChannels != NULL) { + get_scsi_p()->silent++; + sub_ch = ReadSubChannels(get_scsi_p(), sec); + get_scsi_p()->silent--; + if (sub_ch == NULL /*&& (usal_sense_key(get_scsi_p()) == 5)*/) { + /* command is not implemented */ + ReadSubChannels = NULL; +#if defined DEBUG_SUB +fprintf(stderr, "\nCommand not implemented: switching ReadSubChannels off !\n"); +#endif + goto fallback; + } + + /* check the adress mode field */ + if ((sub_ch->control_adr & 0x0f) == 0) { + /* no Q mode information present at all, weird */ + sub_ch->control_adr = 0xAA; + } + + if ((int)(sub_ch->control_adr & 0x0f) > 0x01) { + /* this sector just has no position information. + * we try the one before and then the one after. + */ + if (sec > 1) { + sec -= 1; + sub_ch = ReadSubChannels(get_scsi_p(), sec); + if (sub_ch == NULL) return NULL; + sec += 1; + } + if ((sub_ch->control_adr & 0x0f) != 0x01) { + sec += 2; + sub_ch = ReadSubChannels(get_scsi_p(), sec); + if (sub_ch == NULL) return NULL; + sec -= 2; + } + } + + /* check adress mode field for position information */ + if ((sub_ch->control_adr & 0x0f) == 0x01) { + return sub_ch; + } + ReadSubChannels = NULL; +fprintf(stderr, "\nCould not get position information (%02x) for sectors %d, %d, %d: switching ReadSubChannels off !\n", sub_ch->control_adr &0x0f, sec-1, sec, sec+2); + } + + /* + * We rely on audio sectors here!!! + * The only method that worked even with my antique Toshiba 3401, + * is playing the sector and then request the subchannel afterwards. + */ +fallback: + /* We need a conformed audio track here! */ + + /* Fallback to ancient method */ + if (-1 == Play_at(get_scsi_p(), sec, 1)) { + return NULL; + } + playing = 1; + sub_ch = ReadSubQ(get_scsi_p(), GET_POSITIONDATA,0); + return sub_ch; +} + +static int ReadSubControl(unsigned sec); +static int ReadSubControl(unsigned sec) +{ + subq_chnl *sub_ch = ReadSubChannel(sec); + if (sub_ch == NULL) return -1; + + return sub_ch->control_adr & 0xf0; +} + +static int HaveSCMS(unsigned StartSector); +static int HaveSCMS(unsigned StartSector) +{ + int i; + int cr; + int copy_bits_set = 0; + + for (i = 0; i < 8; i++) { + cr = ReadSubControl(StartSector + i); + if (cr == -1) continue; + (cr & 0x20) ? copy_bits_set++ : 0; + } + return (copy_bits_set >= 1 && copy_bits_set < 8); +} + +void Check_Toc(void) +{ + /* detect layout */ + + /* detect tracks */ +} + +static int GetIndexOfSector(unsigned sec, unsigned track) +{ + subq_chnl *sub_ch = ReadSubChannel(sec); + if (sub_ch == NULL) { + if ((long)sec == Get_EndSector(track)) { + fprintf(stderr, "Driver and/or firmware bug detected! Drive cannot play the very last sector (%u)!\n", sec); + } + return -1; + } + + /* can we trust that these values are hex and NOT bcd? */ + if ((sub_ch->track >= 0x10) && (sub_ch->track - track > 5)) { + /* change all values from bcd to hex */ + sub_ch->track = (sub_ch->track >> 4)*10 + (sub_ch->track & 0x0f); + sub_ch->index = (sub_ch->index >> 4)*10 + (sub_ch->index & 0x0f); + } + +#if 1 + /* compare tracks */ + if (sub_ch->index != 0 && track != sub_ch->track) { + if (global.verbose) fprintf(stderr, "\ntrack mismatch: %1d, in-track subchannel: %1d (index %1d, sector %1d)\n", + track, sub_ch->track, sub_ch->index, sec); + } +#endif + + /* compare control field with the one from the TOC */ + if ((Get_Flags(track) & 0xf0) != (sub_ch->control_adr & 0xf0)) { + int diffbits = (Get_Flags(track) & 0xf0) ^ (sub_ch->control_adr & 0xf0); + if ((diffbits & 0x80) == 0x80) { + /* broadcast difference */ + if (global.verbose) fprintf(stderr, "broadcast type conflict detected -> TOC:%s, subchannel:%s\n", + (sub_ch->control_adr & 0x80) == 0 ? "broadcast" : "nonbroadcast" + ,(sub_ch->control_adr & 0x80) != 0 ? "broadcast" : "nonbroadcast" + ); + } + if ((diffbits & 0x40) == 0x40) { + /* track type difference */ + if (global.verbose) fprintf(stderr, "track type conflict detected -> TOC:%s, subchannel:%s\n", + (sub_ch->control_adr & 0x40) == 0 ? "data" : "audio" + ,(sub_ch->control_adr & 0x40) != 0 ? "data" : "audio" + ); + } + if ((diffbits & 0x20) == 0x20 && !Get_SCMS(track)) { + /* copy permission difference is a sign for SCMS + * and is treated elsewhere. */ + if (global.verbose) fprintf(stderr, "difference: TOC:%s, subchannel:%s\ncorrecting TOC...\n", + (sub_ch->control_adr & 0x20) == 0 ? "unprotected" : "copyright protected", + (sub_ch->control_adr & 0x20) != 0 ? "unprotected" : "copyright protected" + ); + toc_entry(track, + (Get_Flags(track) & 0xDF) | (sub_ch->control_adr & 0x20), + Get_Tracknumber(track), + Get_ISRC(track), + Get_AudioStartSector(track), + Get_Mins(track), + Get_Secs(track), + Get_Frames(track) + ); + } + if ((diffbits & 0x10) == 0x10) { + /* preemphasis difference */ + if (global.verbose) fprintf(stderr, "difference: TOC:%s, subchannel:%s preemphasis\ncorrecting TOC...\n", + (sub_ch->control_adr & 0x10) == 0 ? "with" : "without", + (sub_ch->control_adr & 0x10) != 0 ? "with" : "without" + ); + toc_entry(track, + (Get_Flags(track) & 0xEF) | (sub_ch->control_adr & 0x10), + Get_Tracknumber(track), + Get_ISRC(track), + Get_AudioStartSector(track), + Get_Mins(track), + Get_Secs(track), + Get_Frames(track) + ); + } + + } + + return sub_ch ? sub_ch->index == 244 ? 1 : sub_ch->index : -1; +} + +static int ScanBackwardFrom(unsigned sec, unsigned limit, int *where, + unsigned track); + +static int ScanBackwardFrom(unsigned sec, unsigned limit, int *where, + unsigned track) +{ + unsigned lastindex = 0; + unsigned mysec = sec; + + /* try to find the transition of index n to index 0, + * if the track ends with an index 0. + */ + while ((lastindex = GetIndexOfSector(mysec, track)) == 0) { + if (mysec < limit+75) { + break; + } + mysec -= 75; + } + if (mysec == sec) { + /* there is no pre-gap in this track */ + if (where != NULL) *where = -1; + } else { + /* we have a pre-gap in this track */ + + if (lastindex == 0) { + /* we did not cross the transition yet -> search backward */ + do { + if (mysec < limit+1) { + break; + } + mysec --; + } while ((lastindex = GetIndexOfSector(mysec,track)) == 0); + if (lastindex != 0) { + /* successful */ + mysec ++; + /* register mysec as transition */ + if (where != NULL) *where = (int) mysec; + } else { + /* could not find transition */ + if (!global.quiet) + fprintf(stderr, + "Could not find index transition for pre-gap.\n"); + if (where != NULL) *where = -1; + } + } else { + int myindex = -1; + /* we have crossed the transition -> search forward */ + do { + if (mysec >= sec) { + break; + } + mysec ++; + } while ((myindex = GetIndexOfSector(mysec,track)) != 0); + if (myindex == 0) { + /* successful */ + /* register mysec as transition */ + if (where != NULL) *where = (int) mysec; + } else { + /* could not find transition */ + if (!global.quiet) + fprintf(stderr, + "Could not find index transition for pre-gap.\n"); + if (where != NULL) *where = -1; + } + } + } + return lastindex; +} + +#ifdef USE_LINEAR_SEARCH +static int linear_search(int searchInd, unsigned int Start, unsigned int End, + unsigned track); + +static int linear_search(int searchInd, unsigned int Start, unsigned int End, + unsigned track) +{ + int l = Start; + int r = End; + + for (; l <= r; l++ ) { + int ind; + + ind = GetIndexOfSector(l, track); + if ( searchInd == ind ) { + break; + } + } + if ( l <= r ) { + /* Index found. */ + return l; + } + + return -1; +} +#endif + +#ifndef USE_LINEAR_SEARCH +#undef DEBUG_BINSEARCH +static int binary_search(int searchInd, unsigned int Start, unsigned int End, + unsigned track); + +static int binary_search(int searchInd, unsigned Start, unsigned End, + unsigned track) +{ + int l = Start; + int r = End; + int x = 0; + int ind; + + while ( l <= r ) { + x = ( l + r ) / 2; + /* try to avoid seeking */ + ind = GetIndexOfSector(x, track); + if ( searchInd == ind ) { + break; + } else { + if ( searchInd < ind ) r = x - 1; + else l = x + 1; + } + } +#ifdef DEBUG_BINSEARCH +fprintf(stderr, "(%d,%d,%d > ",l,x,r); +#endif + if ( l <= r ) { + /* Index found. Now find the first position of this index */ + /* l=LastPos x=found r=NextPos */ + r = x; + while ( l < r-1 ) { + x = ( l + r ) / 2; + /* try to avoid seeking */ + ind = GetIndexOfSector(x, track); + if ( searchInd == ind ) { + r = x; + } else { + l = x; + } +#ifdef DEBUG_BINSEARCH +fprintf(stderr, "%d -> ",x); +#endif + } +#ifdef DEBUG_BINSEARCH +fprintf(stderr, "%d,%d)\n",l,r); +#endif + if (searchInd == GetIndexOfSector(l, track)) + return l; + else + return r; + } + + return -1; +} +#endif + + +static void register_index_position(int IndexOffset, + index_list **last_index_entry); + +static void register_index_position(int IndexOffset, + index_list **last_index_entry) +{ + index_list *indexentry; + + /* register higher index entries */ + if (*last_index_entry != NULL) { + indexentry = (index_list *) malloc( sizeof(index_list) ); + } else { + indexentry = NULL; + } + if (indexentry != NULL) { + indexentry->next = NULL; + (*last_index_entry)->next = indexentry; + *last_index_entry = indexentry; + indexentry->frameoffset = IndexOffset; +#if defined INFOFILES + } else { + fprintf( stderr, "No memory for index lists. Index positions\nwill not be written in info file!\n"); +#endif + } +} + +static void Set_SCMS(unsigned long p_track); + +#undef DEBUG_INDLIST +/* experimental code */ +/* search for indices (audio mode required) */ +unsigned ScanIndices(unsigned track, unsigned cd_index, int bulk) +{ + /* scan for indices. */ + /* look at last sector of track. */ + /* when the index is not equal 1 scan by bipartition + * for offsets of all indices */ + + unsigned starttrack, endtrack; + unsigned startindex, endindex; + + unsigned j; + int LastIndex=0; + int n_0_transition; + unsigned StartSector; + unsigned retval = 0; + + index_list *baseindex_pool; + index_list *last_index_entry; + + SCSI *usalp = get_scsi_p(); + + static struct iterator i; + InitIterator(&i, 1); + + EnableCdda(usalp, 0, 0); + EnableCdda(usalp, 1, CD_FRAMESIZE_RAW + 16); + + if (!global.quiet && !(global.verbose & SHOW_INDICES)) + fprintf(stderr, "seeking index start ..."); + + if (bulk != 1) { + starttrack = track; endtrack = track; + } else { + starttrack = 1; endtrack = cdtracks; + } + baseindex_pool = (index_list *) malloc( sizeof(index_list) * (endtrack - starttrack + 1)); +#ifdef DEBUG_INDLIST + fprintf(stderr, "index0-mem-pool %p\n", baseindex_pool); +#endif + + + while (i.hasNextTrack(&i)) { + struct TOC *p = i.getNextTrack(&i); + unsigned ii = GETTRACK(p); + + if ( ii < starttrack || IS__DATA(p) ) + continue; /* skip nonaudio tracks */ + + if ( ii > endtrack ) + break; + + if ( global.verbose & SHOW_INDICES ) { + if (global.illleadout_cd && global.reads_illleadout && ii == endtrack) { + fprintf(stderr, "Analysis of track %d skipped due to unknown length\n", ii); + } + } + if (global.illleadout_cd && global.reads_illleadout + && ii == endtrack) continue; + + StartSector = Get_AudioStartSector(ii); + if (HaveSCMS(StartSector)) { + Set_SCMS(ii); + } + if ( global.verbose & SHOW_INDICES ) { + fprintf( stderr, "\rindex scan: %d...", ii ); + fflush (stderr); + } + LastIndex = ScanBackwardFrom(Get_EndSector(ii), StartSector, &n_0_transition, ii); + if (LastIndex > 99) continue; + + if (baseindex_pool != NULL) { +#ifdef DEBUG_INDLIST +#endif + /* register first index entry for this track */ + baseindex_pool[ii - starttrack].next = NULL; + baseindex_pool[ii - starttrack].frameoffset = StartSector; + global.trackindexlist[ii] = &baseindex_pool[ii - starttrack]; +#ifdef DEBUG_INDLIST +#endif + } else { + global.trackindexlist[ii] = NULL; + } + last_index_entry = global.trackindexlist[ii]; + + if (LastIndex < 2) { + register_index_position(n_0_transition, &last_index_entry); + continue; + } + + if ((global.verbose & SHOW_INDICES) && LastIndex > 1) + fprintf(stderr, "\rtrack %2d has %d indices, index table (pairs of 'index: frame offset')\n", ii, LastIndex); + + startindex = 0; + endindex = LastIndex; + + for (j = startindex; j <= endindex; j++) { + int IndexOffset; + + /* this track has indices */ + +#ifdef USE_LINEAR_SEARCH + /* do a linear search */ + IndexOffset = linear_search(j, StartSector, Get_EndSector(ii), ii); +#else + /* do a binary search */ + IndexOffset = binary_search(j, StartSector, Get_EndSector(ii), ii); +#endif + + if (IndexOffset != -1) { + StartSector = IndexOffset; + } + + if (j == 1) + last_index_entry->frameoffset = IndexOffset; + else if (j > 1) + register_index_position(IndexOffset, &last_index_entry); + + if ( IndexOffset == -1 ) { + if (global.verbose & SHOW_INDICES) { + if (global.gui == 0) { + fprintf(stderr, "%2u: N/A ",j); + if (((j + 1) % 8) == 0) fputs("\n", stderr); + } else { + fprintf(stderr, "\rT%02d I%02u N/A\n",ii,j); + } + } + } else { + if (global.verbose & SHOW_INDICES) { + if (global.gui == 0) { + fprintf(stderr, + "%2u:%6lu ", + j, + IndexOffset-Get_AudioStartSector(ii) + ); + if (((j + 1) % 8) == 0) fputs("\n", stderr); + } else { + fprintf(stderr, + "\rT%02d I%02u %06lu\n", + ii, + j, + IndexOffset-Get_AudioStartSector(ii) + ); + } + } + + if (track == ii && cd_index == j) { + retval = IndexOffset-Get_AudioStartSector(ii); + } + } /* if IndexOffset */ + } /* for index */ + register_index_position(n_0_transition, &last_index_entry); + + /* sanity check. clear all consecutive nonindex entries (frameoffset -1) from the end. */ + { + index_list *ip = global.trackindexlist[ii]; + index_list *iq = NULL; + index_list *lastgood = iq; + + while (ip != NULL) + { + if (ip->frameoffset == -1) + { + /* no index available */ + if (lastgood == NULL) + { + /* if this is the first one in a sequence, store predecessor */ + lastgood = iq; + } + } else { + /* this is a valid index, reset marker */ + lastgood = NULL; + } + + iq = ip; + ip = ip->next; + } + /* terminate chain at the last well defined entry. */ + if (lastgood != NULL) + lastgood->next = NULL; + } + + if (global.gui == 0 && (global.verbose & SHOW_INDICES) + && ii != endtrack) + fputs("\n", stderr); + } /* for tracks */ + if (global.gui == 0 && (global.verbose & SHOW_INDICES)) + fputs("\n", stderr); + if (playing != 0) StopPlay(get_scsi_p()); + + EnableCdda(usalp, 0, 0); + EnableCdda(usalp, 1, CD_FRAMESIZE_RAW); + + return retval; +} + +static unsigned char MCN[14]; + +static void Set_MCN(unsigned char *MCN_arg) +{ + memcpy(MCN, MCN_arg, 14); + MCN[13] = '\0'; +} + +unsigned char *Get_MCN(void) +{ + return MCN; +} + + +static TOC g_toc [MAXTRK+1]; /* hidden track + 100 regular tracks */ + +/*#define IS_AUDIO(i) (!(g_toc[i].bFlags & 0x40))*/ + +int +TOC_entries(unsigned tracks, unsigned char *a, unsigned char *b, int binvalid) +{ + int i; + for (i = 1; i <= (int)tracks; i++) { + unsigned char *p; + unsigned long dwStartSector; + + if (binvalid) { + p = a + 8*(i-1); + + g_toc[i].bFlags = p[1]; + g_toc[i].bTrack = p[2]; + g_toc[i].ISRC[0] = 0; + dwStartSector = a_to_u_4_byte(p+4); + g_toc[i].dwStartSector = dwStartSector; + lba_2_msf((long)dwStartSector, + &g_toc[i].mins, + &g_toc[i].secs, + &g_toc[i].frms); + } else { + p = b + 8*(i-1); + g_toc[i].bFlags = p[1]; + g_toc[i].bTrack = p[2]; + g_toc[i].ISRC[0] = 0; + if ((int)((p[5]*60 + p[6])*75 + p[7]) >= 150) { + g_toc[i].dwStartSector = (p[5]*60 + p[6])*75 + p[7] -150; + } else { + g_toc[i].dwStartSector = 0; + } + g_toc[i].mins = p[5]; + g_toc[i].secs = p[6]; + g_toc[i].frms = p[7]; + } + } + return 0; +} + +void toc_entry(unsigned nr, unsigned flag, unsigned tr, unsigned char *ISRC, + unsigned long lba, int m, int s, int f) +{ + if (nr > MAXTRK) return; + + g_toc[nr].bFlags = flag; + g_toc[nr].bTrack = tr; + if (ISRC) { + strncpy((char *)g_toc[nr].ISRC, (char *)ISRC, + sizeof(g_toc[nr].ISRC) -1); + g_toc[nr].ISRC[sizeof(g_toc[nr].ISRC) -1] = '\0'; + } + g_toc[nr].dwStartSector = lba; + g_toc[nr].mins = m; + g_toc[nr].secs = s; + g_toc[nr].frms = f; +} + +int patch_real_end(unsigned long sector) +{ + g_toc[cdtracks+1].dwStartSector = sector; + return 0; +} + +static int patch_cd_extra(unsigned track, unsigned long sector) +{ + if (track <= cdtracks) + g_toc[track].dwStartSector = sector; + return 0; +} + +static int restrict_tracks_illleadout(void) +{ + struct TOC *o = &g_toc[cdtracks+1]; + int i; + for (i = cdtracks; i >= 0; i--) { + struct TOC *p = &g_toc[i]; + if (GETSTART(o) > GETSTART(p)) break; + } + patch_cd_extra(i+1, GETSTART(o)); + cdtracks = i; + + return 0; +} + +static void Set_ISRC(int track, const unsigned char *ISRC_arg) +{ + if (track <= (int)cdtracks) { + memcpy(Get_ISRC(track), ISRC_arg, 16); + } +} + + +unsigned char *Get_ISRC(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].ISRC; + return NULL; +} + +static void patch_to_audio(unsigned long p_track) +{ + if (p_track <= cdtracks) + g_toc[p_track].bFlags &= ~0x40; +} + +int Get_Flags(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].bFlags; + return -1; +} + +int Get_Mins(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].mins; + return -1; +} + +int Get_Secs(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].secs; + return -1; +} + +int Get_Frames(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].frms; + return -1; +} + +int Get_Preemphasis(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].bFlags & 0x10; + return -1; +} + +static void Set_SCMS(unsigned long p_track) +{ + g_toc[p_track].SCMS = 1; +} + +int Get_SCMS(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].SCMS; + return -1; +} + +int Get_Copyright(unsigned long p_track) +{ + if (p_track <= cdtracks) { + if (g_toc[p_track].SCMS) return 1; + return ((int)g_toc[p_track].bFlags & 0x20) >> 4; + } + return -1; +} + +int Get_Datatrack(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].bFlags & 0x40; + return -1; +} + +int Get_Channels(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].bFlags & 0x80; + return -1; +} + +int Get_Tracknumber(unsigned long p_track) +{ + if (p_track <= cdtracks) + return g_toc[p_track].bTrack; + return -1; +} + +static int useHiddenTrack(void) +{ + return 0; +} + + + +static void it_reset(struct iterator *this); + +static void it_reset(struct iterator *this) +{ + this->index = this->startindex; +} + + +static int it_hasNextTrack(struct iterator *this); +static struct TOC *it_getNextTrack(struct iterator *this); + +static int it_hasNextTrack(struct iterator *this) +{ + return this->index <= (int)cdtracks+1; +} + + + +static struct TOC *it_getNextTrack(struct iterator *this) +{ + /* if ( (*this->hasNextTrack)(this) == 0 ) return NULL; */ + if ( this->index > (int)cdtracks+1 ) return NULL; + + return &g_toc[ this->index++ ]; +} + + +static void InitIterator(struct iterator *iter, unsigned long p_track) +{ + if (iter == NULL) return; + + iter->index = iter->startindex = useHiddenTrack() ? 0 : p_track; + iter->reset = it_reset; + iter->getNextTrack = it_getNextTrack; + iter->hasNextTrack = it_hasNextTrack; +} + +#if 0 +static struct iterator *NewIterator(void); + +static struct iterator *NewIterator () +{ + struct iterator *retval; + + retval = malloc (sizeof(struct iterator)); + if (retval != NULL) { + InitIterator(retval, 1); + } + return retval; +} +#endif + +long Get_AudioStartSector(unsigned long p_track) +{ +#if 1 + if (p_track == CDROM_LEADOUT) + p_track = cdtracks + 1; + + if (p_track <= cdtracks +1 + && IS__AUDIO(&g_toc[p_track])) + return GETSTART(&g_toc[p_track]); +#else + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, p_track); + else i.reset(&i); + + if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT; + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + + if (GETTRACK(p) == p_track) { + if (IS__DATA(p)) { + return -1; + } + return GETSTART(p); + } + } +#endif + return -1; +} + + +long Get_StartSector(unsigned long p_track) +{ +#if 1 + if (p_track == CDROM_LEADOUT) + p_track = cdtracks + 1; + + if (p_track <= cdtracks +1) + return GETSTART(&g_toc[p_track]); +#else + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, p_track); + else i.reset(&i); + + if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT; + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + + if (GETTRACK(p) == p_track) { + return GETSTART(p); + } + } +#endif + return -1; +} + + +long Get_EndSector(unsigned long p_track) +{ +#if 1 + if (p_track <= cdtracks) + return GETSTART(&g_toc[p_track+1])-1; +#else + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, p_track); + else i.reset(&i); + + if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT; + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + if (GETTRACK(p) == p_track) { + p = i.getNextTrack(&i); + if (p == NULL) { + return -1; + } + return GETSTART(p)-1; + } + } +#endif + return -1; +} + +long FirstTrack(void) +{ + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + if (i.hasNextTrack(&i)) { + return GETTRACK(i.getNextTrack(&i)); + } + return -1; +} + +long FirstAudioTrack(void) +{ + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + unsigned ii = GETTRACK(p); + + if (ii == CDROM_LEADOUT) break; + if (IS__AUDIO(p)) { + return ii; + } + } + return -1; +} + +long FirstDataTrack(void) +{ + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + if (IS__DATA(p)) { + return GETTRACK(p); + } + } + return -1; +} + +long LastTrack(void) +{ + return g_toc[cdtracks].bTrack; +} + +long LastAudioTrack(void) +{ + long j = -1; + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + if (IS__AUDIO(p) && (GETTRACK(p) != CDROM_LEADOUT)) { + j = GETTRACK(p); + } + } + return j; +} + +long Get_LastSectorOnCd(unsigned long p_track) +{ + long LastSec = 0; + static struct iterator i; + + if (global.illleadout_cd && global.reads_illleadout) + return 150+(99*60+59)*75+74; + + if (i.reset == NULL) InitIterator(&i, p_track); + else i.reset(&i); + + if (p_track == cdtracks + 1) p_track = CDROM_LEADOUT; + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + + if (GETTRACK(p) < p_track) + continue; + + LastSec = GETSTART(p); + + if (IS__DATA(p)) break; + } + return LastSec; +} + +int Get_Track(unsigned long sector) +{ + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, 1); + else i.reset(&i); + + if (i.hasNextTrack(&i)) { + TOC *o = i.getNextTrack(&i); + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + if ((GETSTART(o) <= sector) && (GETSTART(p) > sector)) { + if (IS__DATA(o)) { + return -1; + } else { + return GETTRACK(o); + } + } + o = p; + } + } + return -1; +} + +int CheckTrackrange(unsigned long from, unsigned long upto) +{ + static struct iterator i; + if (i.reset == NULL) InitIterator(&i, from); + else i.reset(&i); + + while (i.hasNextTrack(&i)) { + TOC *p = i.getNextTrack(&i); + + if (GETTRACK(p) < from) + continue; + + if (GETTRACK(p) == upto) + return 1; + + /* data tracks terminate the search */ + if (IS__DATA(p)) + return 0; + } + /* track not found */ + return 0; +} + +#ifdef USE_PARANOIA +long cdda_disc_firstsector(void *d); + +long cdda_disc_firstsector(void *d) +{ + return Get_StartSector(FirstAudioTrack()); +} + +int cdda_tracks(void *d); + +int cdda_tracks(void *d) +{ + return LastAudioTrack() - FirstAudioTrack() +1; +} + +int cdda_track_audiop(void *d, int track); + +int cdda_track_audiop(void *d, int track) +{ + return Get_Datatrack(track) == 0; +} + +long cdda_track_firstsector(void *d, int track); + +long cdda_track_firstsector(void *d, int track) +{ + return Get_AudioStartSector(track); +} + +long cdda_track_lastsector(void *d, int track); + +long cdda_track_lastsector(void *d, int track) +{ + return Get_EndSector(track); +} + +long cdda_disc_lastsector(void *d); + +long cdda_disc_lastsector(void *d) +{ + return Get_LastSectorOnCd(cdtracks) - 1; +} + +int cdda_sector_gettrack(void *d,long sector); + +int cdda_sector_gettrack(void *d, long sector) +{ + return Get_Track(sector); +} + +#endif diff --git a/icedax/toc.h b/icedax/toc.h new file mode 100644 index 0000000..84da13a --- /dev/null +++ b/icedax/toc.h @@ -0,0 +1,69 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)toc.h 1.9 06/02/19 Copyright 1998,1999 Heiko Eissfeldt, Copyright 2006 J. Schilling */ + +#define MAXTRK 100 /* maximum of audio tracks (without a hidden track) */ + +extern unsigned cdtracks; +extern int have_multisession; +extern int have_CD_extra; +extern int have_CD_text; +extern int have_CDDB; + +#if !defined(HAVE_NETDB_H) +#undef USE_REMOTE +#else +#define USE_REMOTE 1 +extern int request_titles(void); +#endif + +extern int ReadToc(void); +extern void Check_Toc(void); +extern int TOC_entries(unsigned tracks, + unsigned char *a, unsigned char *b, + int bvalid); +extern void toc_entry(unsigned nr, unsigned flag, unsigned tr, + unsigned char *ISRC, + unsigned long lba, int m, int s, int f); +extern int patch_real_end(unsigned long sector); +extern int no_disguised_audiotracks(void); + +extern int Get_Track(unsigned long sector); +extern long FirstTrack(void); +extern long LastTrack(void); +extern long FirstAudioTrack(void); +extern long FirstDataTrack(void); +extern long LastAudioTrack(void); +extern long Get_EndSector(unsigned long p_track); +extern long Get_StartSector(unsigned long p_track); +extern long Get_AudioStartSector(unsigned long p_track); +extern long Get_LastSectorOnCd(unsigned long p_track); +extern int CheckTrackrange(unsigned long from, unsigned long upto); + +extern int Get_Preemphasis(unsigned long p_track); +extern int Get_Channels(unsigned long p_track); +extern int Get_Copyright(unsigned long p_track); +extern int Get_Datatrack(unsigned long p_track); +extern int Get_Tracknumber(unsigned long p_track); +extern unsigned char *Get_MCN(void); +extern unsigned char *Get_ISRC(unsigned long p_track); + +extern unsigned find_an_off_sector(unsigned lSector, unsigned SectorBurstVal); +extern void DisplayToc(void); +extern unsigned FixupTOC(unsigned no_tracks); +extern void calc_cddb_id(void); +extern void calc_cdindex_id(void); +extern void Read_MCN_ISRC(void); +extern unsigned ScanIndices(unsigned trackval, unsigned indexval, int bulk); +extern int handle_cdtext(void); +extern int lba_2_msf(long lba, int *m, int *s, int *f); diff --git a/icedax/version.sed b/icedax/version.sed new file mode 100644 index 0000000..d0752df --- /dev/null +++ b/icedax/version.sed @@ -0,0 +1,4 @@ +/cdr_version\[\] = /{ + s/.*"\(.*\)";/\1/ + p +} diff --git a/icedax/wav.c b/icedax/wav.c new file mode 100644 index 0000000..b30ed9b --- /dev/null +++ b/icedax/wav.c @@ -0,0 +1,157 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)wav.c 1.4 01/10/27 Copyright 1998,1999 Heiko Eissfeldt */ +/*** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) by Heiko Eissfeldt + * + * + */ +#include "config.h" +#include <stdio.h> +#include <unixstd.h> +#include "byteorder.h" +#include "sndfile.h" + +/*** + * --------------------------------------------------------------------- + * definitions for RIFF-output (from windows MMSYSTEM) + * --------------------------------------------------------------------- + */ + +typedef unsigned int FOURCC; /* a four character code */ + +typedef struct CHUNKHDR { + FOURCC ckid; /* chunk ID */ + unsigned int dwSize; /* chunk size */ +} CHUNKHDR; + +/* flags for 'wFormatTag' field of WAVEFORMAT */ +#define WAVE_FORMAT_PCM 1 + +/* specific waveform format structure for PCM data */ +typedef struct pcmwaveformat_tag { + unsigned short wFormatTag; /* format type */ + unsigned short nChannels; /* number of channels (i.e. mono, stereo, etc.) */ + unsigned int nSamplesPerSec; /* sample rate */ + unsigned int nAvgBytesPerSec;/* for buffer size estimate */ + unsigned short nBlockAlign; /* block size of data */ + unsigned short wBitsPerSample; +} PCMWAVEFORMAT; +typedef PCMWAVEFORMAT *PPCMWAVEFORMAT; + + +/* MMIO macros */ +#define mmioFOURCC(ch0, ch1, ch2, ch3) \ + ((unsigned int)(unsigned char)(ch0) | ((unsigned int)(unsigned char)(ch1) << 8) | \ + ((unsigned int)(unsigned char)(ch2) << 16) | ((unsigned int)(unsigned char)(ch3) << 24)) + +#define FOURCC_RIFF mmioFOURCC ('R', 'I', 'F', 'F') +#define FOURCC_LIST mmioFOURCC ('L', 'I', 'S', 'T') +#define FOURCC_WAVE mmioFOURCC ('W', 'A', 'V', 'E') +#define FOURCC_FMT mmioFOURCC ('f', 'm', 't', ' ') +#define FOURCC_DATA mmioFOURCC ('d', 'a', 't', 'a') + + +/* simplified Header for standard WAV files */ +typedef struct WAVEHDR { + CHUNKHDR chkRiff; + FOURCC fccWave; + CHUNKHDR chkFmt; + unsigned short wFormatTag; /* format type */ + unsigned short nChannels; /* number of channels (i.e. mono, stereo, etc.) */ + unsigned int nSamplesPerSec; /* sample rate */ + unsigned int nAvgBytesPerSec;/* for buffer estimation */ + unsigned short nBlockAlign; /* block size of data */ + unsigned short wBitsPerSample; + CHUNKHDR chkData; +} WAVEHDR; + +#define IS_STD_WAV_HEADER(waveHdr) ( \ + waveHdr.chkRiff.ckid == FOURCC_RIFF && \ + waveHdr.fccWave == FOURCC_WAVE && \ + waveHdr.chkFmt.ckid == FOURCC_FMT && \ + waveHdr.chkData.ckid == FOURCC_DATA && \ + waveHdr.wFormatTag == WAVE_FORMAT_PCM) + +static WAVEHDR waveHdr; + +static int _InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes); + +static int _InitSound(int audio, long channels, unsigned long rate, + long nBitsPerSample, unsigned long expected_bytes) +{ + unsigned long nBlockAlign = channels * ((nBitsPerSample + 7) / 8); + unsigned long nAvgBytesPerSec = nBlockAlign * rate; + unsigned long temp = expected_bytes + sizeof(WAVEHDR) - sizeof(CHUNKHDR); + + waveHdr.chkRiff.ckid = cpu_to_le32(FOURCC_RIFF); + waveHdr.fccWave = cpu_to_le32(FOURCC_WAVE); + waveHdr.chkFmt.ckid = cpu_to_le32(FOURCC_FMT); + waveHdr.chkFmt.dwSize = cpu_to_le32(sizeof (PCMWAVEFORMAT)); + waveHdr.wFormatTag = cpu_to_le16(WAVE_FORMAT_PCM); + waveHdr.nChannels = cpu_to_le16(channels); + waveHdr.nSamplesPerSec = cpu_to_le32(rate); + waveHdr.nBlockAlign = cpu_to_le16(nBlockAlign); + waveHdr.nAvgBytesPerSec = cpu_to_le32(nAvgBytesPerSec); + waveHdr.wBitsPerSample = cpu_to_le16(nBitsPerSample); + waveHdr.chkData.ckid = cpu_to_le32(FOURCC_DATA); + waveHdr.chkRiff.dwSize = cpu_to_le32(temp); + waveHdr.chkData.dwSize = cpu_to_le32(expected_bytes); + + return write (audio, &waveHdr, sizeof (waveHdr)); +} + +static int _ExitSound(int audio, unsigned long nBytesDone); + +static int _ExitSound(int audio, unsigned long nBytesDone) +{ + unsigned long temp = nBytesDone + sizeof(WAVEHDR) - sizeof(CHUNKHDR); + + waveHdr.chkRiff.dwSize = cpu_to_le32(temp); + waveHdr.chkData.dwSize = cpu_to_le32(nBytesDone); + + /* goto beginning */ + if (lseek(audio, 0L, SEEK_SET) == -1) { + return 0; + } + return write (audio, &waveHdr, sizeof (waveHdr)); +} + +static unsigned long _GetHdrSize(void); + +static unsigned long _GetHdrSize(void) +{ + return sizeof( waveHdr ); +} + +static unsigned long InSizeToOutSize(unsigned long BytesToDo); + +static unsigned long InSizeToOutSize(unsigned long BytesToDo) +{ + return BytesToDo; +} + +struct soundfile wavsound = +{ + _InitSound, /* init header method */ + _ExitSound, /* exit header method */ + _GetHdrSize, /* report header size method */ + /* get sound samples out */ + (int (*)(int audio, unsigned char *buf, unsigned long BytesToDo)) write, + InSizeToOutSize, /* compressed? output file size */ + 0 /* needs big endian samples */ +}; + + diff --git a/icedax/wav.h b/icedax/wav.h new file mode 100644 index 0000000..e1a90d1 --- /dev/null +++ b/icedax/wav.h @@ -0,0 +1,14 @@ +/* + * This file has been modified for the cdrkit suite. + * + * The behaviour and appearence of the program code below can differ to a major + * extent from the version distributed by the original author(s). + * + * For details, see Changelog file distributed with the cdrkit package. If you + * received this file from another source then ask the distributing person for + * a log of modifications. + * + */ + +/* @(#)wav.h 1.2 99/12/19 Copyright 1998,1999 Heiko Eissfeldt */ +extern struct soundfile wavsound; |