home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume28 / cdreader / part01 < prev    next >
Encoding:
Text File  |  1992-03-14  |  56.0 KB  |  1,720 lines

  1. Newsgroups: comp.sources.misc
  2. From: pwolfe@blizzard.kai.com (Patrick Wolfe)
  3. Subject:  v28i082:  cdreader - Audio CD player for SGI's, Part01/01
  4. Message-ID: <1992Mar7.183159.22096@sparky.imd.sterling.com>
  5. X-Md4-Signature: 0e5751a4b4f3c064ea19f7aeb703e90e
  6. Date: Sat, 7 Mar 1992 18:31:59 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: pwolfe@blizzard.kai.com (Patrick Wolfe)
  10. Posting-number: Volume 28, Issue 82
  11. Archive-name: cdreader/part01
  12. Environment: SGI
  13.  
  14. Cdreader plays an audio compact disc on Silicon Graphics workstations with an
  15. Audio Processor (the SGI Indigo, for example).  Cdreader compiles only under
  16. release 4.0.1 (or later) of the Irix operating system.
  17.  
  18. Version 1.4 sports an X11/Motif interface, and a new "shuffle" function.
  19.  
  20. This is NOT just like SGI's "cdplayer" program, which simply commands the CD
  21. drive to play an audio CD, and sits back to watch.  In that case, the digital
  22. CD data is converted to analog inside the CDrom drive, and the analog audio
  23. output is sent to the headphone jack on the front and the audio out jacks on
  24. the back of the drive.  Without headphones or a stereo, you can't hear anything.
  25. Even with them, the sound is very quiet, and somewhat distorted.
  26.  
  27. Cdreader uses SGI's libcdaudio routines to read the digital data directly from
  28. the CD, and sends it to the Audio Processor for conversion to analog audio
  29. data.  You can listen on the Indigo's monophonic speaker, or even better, buy a
  30. cable with a stereo mini-plug on one end, and two phono plugs on the other, and
  31. connect from your Indigo's lineout jack to your stereo amplifier's cd-in (or
  32. tape-in) jacks.  Enjoy!
  33.  
  34.         Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  35.  
  36. --- cut here --- cut here --- cut here --- cut here --- cut here ---
  37. #! /bin/sh
  38. # This is a shell archive.  Remove anything before this line, then feed it
  39. # into a shell via "sh file" or similar.  To overwrite existing files,
  40. # type "sh file -c".
  41. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  42. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  43. # Contents:  Makefile Readme cdreader.1 cdreader.c cdreader.icon
  44. # Wrapped by kent@sparky on Sat Mar  7 12:27:41 1992
  45. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  46. echo If this archive is complete, you will see the following message:
  47. echo '          "shar: End of archive 1 (of 1)."'
  48. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'Makefile'\"
  50. else
  51.   echo shar: Extracting \"'Makefile'\" \(3078 characters\)
  52.   sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  53. X#    Makefile for cdreader
  54. X
  55. X#    IRIX401_CDREADDA_BUG - workaround for bug in CDreadda() routine
  56. X#        as distributed in Irix 4.0.1, and supposed to be fixed in
  57. X#        the next Irix release.  See cdreader.c for details.
  58. X#        AFTER this bug is fixed, remove this option and recompile!
  59. XDEFS = -DIRIX401_CDREADDA_BUG
  60. X
  61. XCFLAGS = -O -s $(DEFS)
  62. X#CFLAGS = -g -DTESTING $(DEFS)
  63. X
  64. X# SGI CD Audio library routines
  65. XCDLIBS = -lcdaudio -lds
  66. X
  67. X# SGI Audio Processor library routines
  68. XAUDIOLIBS = -laudio
  69. X
  70. X# X11/Motif window libraries
  71. X#    The shared libraries make for a smaller executable, and are PREFERRED,
  72. X#    but then the program will only run on systems that have them installed
  73. X
  74. X# shared libraries make an executable that's only 168 Kb!
  75. XXLIBS = -lXm_s -lXt_s -lX11_s -lPW
  76. X
  77. X# non shared libraries make an executable that's over 1 Mb tall!
  78. X#XLIBS = -lXm -lXt -lX11 -lPW
  79. X
  80. XLIBS = $(XLIBS) $(CDLIBS) $(AUDIOLIBS) -lc_s
  81. XFILES = Readme cdreader.c Makefile cdreader.icon cdreader.1
  82. XBIN = /usr/local/bin
  83. XICONDIR = /usr/lib/images
  84. XMANDIR = /usr/catman/local/man1
  85. X
  86. Xall: cdreader
  87. X
  88. Xcdreader: cdreader.o
  89. X    rm -f cdreader
  90. X    $(CC) -o cdreader $(CFLAGS) cdreader.o $(LIBS)
  91. X
  92. Xcdreader.1nr: cdreader.1
  93. X    nroff -man cdreader.1 > cdreader.1nr
  94. X
  95. Xinstall: $(BIN)/cdreader $(MANDIR)/cdreader.1 $(ICONDIR)/cdreader.icon
  96. X
  97. X$(BIN)/cdreader: cdreader
  98. X    rm -f $(BIN)/cdreader
  99. X    cp cdreader $(BIN)
  100. X    chmod 755 $(BIN)/cdreader
  101. X    ls -l $(BIN)/cdreader
  102. X
  103. X$(MANDIR)/cdreader.1: cdreader.1
  104. X    rm -f $(MANDIR)/cdreader.1
  105. X    cp cdreader.1 $(MANDIR)/cdreader.1
  106. X    chmod 644 $(MANDIR)/cdreader.1
  107. X    ls -l $(MANDIR)/cdreader.1
  108. X
  109. X$(ICONDIR)/cdreader.icon: cdreader.icon
  110. X    rm -f $(ICONDIR)/cdreader.icon
  111. X    cp cdreader.icon $(ICONDIR)/cdreader.icon
  112. X    chmod 644 $(ICONDIR)/cdreader.icon
  113. X    ls -l $(ICONDIR)/cdreader.icon
  114. X
  115. Xdeinstall:
  116. X    rm -f $(BIN)/cdreader
  117. X
  118. Xlint:
  119. X    lint -uvxz cdreader.c
  120. X
  121. Xshar: $(FILES)
  122. X    rm -f cdreader.shar
  123. X    shar $(FILES) > cdreader.shar
  124. X    ls -l cdreader.shar
  125. X
  126. Xclean:
  127. X    rm -f a.out core mklog cdreader cdreader.shar *.o
  128. X
  129. X#
  130. X# Original Author:  Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  131. X#
  132. X# This software is Copyright (c) 1992 by Patrick J. Wolfe.
  133. X#
  134. X# Permission is hereby granted to copy, distribute or otherwise 
  135. X# use any part of this package as long as you do not try to make 
  136. X# money from it or pretend that you wrote it.  This copyright 
  137. X# notice must be maintained in any copy made.
  138. X#
  139. X# Use of this software constitutes acceptance for use in an AS IS 
  140. X# condition. There are NO warranties with regard to this software.  
  141. X# In no event shall the author be liable for any damages whatsoever 
  142. X# arising out of or in connection with the use or performance of this 
  143. X# software.  Any use of this software is at the user's own risk.
  144. X#
  145. X# If you make modifications to this software that you feel 
  146. X# increases it usefulness for the rest of the community, please 
  147. X# email the changes, enhancements, bug fixes as well as any and 
  148. X# all ideas to me. This software is going to be maintained and 
  149. X# enhanced as deemed necessary by the community.
  150. X#              
  151. X#              Patrick J. Wolfe
  152. X#              uunet!kailand!pwolfe
  153. X#              pwolfe@kai.com
  154. X#
  155. END_OF_FILE
  156.   if test 3078 -ne `wc -c <'Makefile'`; then
  157.     echo shar: \"'Makefile'\" unpacked with wrong size!
  158.   fi
  159.   # end of 'Makefile'
  160. fi
  161. if test -f 'Readme' -a "${1}" != "-c" ; then 
  162.   echo shar: Will not clobber existing file \"'Readme'\"
  163. else
  164.   echo shar: Extracting \"'Readme'\" \(8070 characters\)
  165.   sed "s/^X//" >'Readme' <<'END_OF_FILE'
  166. X------------------------------------------------------------------------------
  167. X            WHAT IS CDREADER?
  168. X
  169. XCdreader plays an audio compact disc on Silicon Graphics workstations with an
  170. XAudio Processor (the SGI Indigo, for example).  Cdreader compiles only under
  171. Xrelease 4.0.1 (or later) of the Irix operating system.
  172. X
  173. XVersion 1.4 sports an X11/Motif interface, and a new "shuffle" function.
  174. X
  175. XThis is NOT just like SGI's "cdplayer" program, which simply commands the CD
  176. Xdrive to play an audio CD, and sits back to watch.  In that case, the digital
  177. XCD data is converted to analog inside the CDrom drive, and the analog audio
  178. Xoutput is sent to the headphone jack on the front and the audio out jacks on
  179. Xthe back of the drive.  Without headphones or a stereo, you can't hear anything.
  180. XEven with them, the sound is very quiet, and somewhat distorted.
  181. X
  182. XCdreader uses SGI's libcdaudio routines to read the digital data directly from
  183. Xthe CD, and sends it to the Audio Processor for conversion to analog audio
  184. Xdata.  You can listen on the Indigo's monophonic speaker, or even better, buy a
  185. Xcable with a stereo mini-plug on one end, and two phono plugs on the other, and
  186. Xconnect from your Indigo's lineout jack to your stereo amplifier's cd-in (or
  187. Xtape-in) jacks.  Enjoy!
  188. X
  189. XWARNING!  If you were just using SGI's "cdplayer" program, turn down the volume
  190. Xbefore starting "cdreader" or you'll risk damaging your equipment (and ears)!
  191. X
  192. XCdreader will probably only work with an SGI's cdrom drive.  The program will
  193. Xtell you if your cdrom drive doesn't support reading audio over the SCSI bus.
  194. XIt uses about 5-6% of the cpu, and 4% of the SCSI bus bandwidth.  Use of other
  195. Xprograms which change the audio processor's parameters is discouraged (but sure
  196. Xcan make you laugh).
  197. X
  198. XThe schedctl() system call in cdreader will (silently) fail unless the program
  199. Xis installed setuid root, or your kernel configuration is modified to allow
  200. Xnon-root users to use non-degrading priorities.  See the SCHEDCTL(2) and
  201. XAUTOCONFIG(1M) manpages, and the Irix Programming Guide Vol 2, section 14.2.3
  202. Xfor complete details.  That's what I did, and it's pretty easy!  Basically,
  203. Xbecome superuser, edit /usr/sysgen/master.d/disp, find the variable
  204. X"ndpri_hilim", change it's value to "NDPHIMAX", run "autoconfig" and reboot.
  205. X
  206. XSome people think the delay is caused by disk I/O, but believe me it's not.
  207. XThat's what I thought, originally, but Mark Callow of SGI corrected me, and
  208. Xput me onto the fixes.
  209. X
  210. XI wrote cdreader on a 16 Mb SGI Indigo running Irix 4.0.1.
  211. X
  212. X        Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  213. X
  214. X------------------------------------------------------------------------------
  215. X            RELEASE NOTES:
  216. X
  217. XVERSION 1.4:
  218. X
  219. XDistributed to comp.sources.misc.
  220. X
  221. XAdded shuffle, tracks and info buttons.  Shuffle plays the whole disc, but in
  222. Xrandom order.  Tracks displays the list and length of tracks, like "cdinfo"
  223. Xdid.  Info displays some information about the program and programmer.  Also,
  224. Xupdated the online help screen to be more useful.
  225. X
  226. XAlso, reorganized code so that the program "should" run on any sgi irix 4.0.1
  227. Xsystem, whether you have a cd drive and audio processor or not.  Of course, it
  228. Xwon't do you any good, but those folks interested in using this program as an
  229. Xexample for X11/Motif programming won't mind too much.
  230. X
  231. XPut all of the commonly used messages and words in defines, for easy
  232. Xcustomization and translation to foreign languages.
  233. X
  234. XFixed next and prev buttons to work in stopped mode, for selecting which track
  235. Xto start playing on.
  236. X
  237. XDiscovered what happens when you have the highest priority task on your system
  238. Xgo into a cpu loop.  I know, I know, I shouldn't put bugs in my programs.  It's
  239. Xunproductive.
  240. X
  241. XVERSION 1.3:
  242. X
  243. XSports an X11/Motif user interface.  Much nicer.  Also displays program status
  244. Xin a window above the buttons.  Not distributed.
  245. X
  246. XVERSION 1.2:
  247. X
  248. XSports an X11 user interface (using Athena Widgets).  Much nicer, but not
  249. Xperfect.  I like being to pause it without killing it.  Not distributed.
  250. X
  251. XCdreader now has a nice Motif style user interface.  I removed all of the debug
  252. Xcode and command line options, since mostly people just want to play cd's from
  253. Xstart to end, possibly pausing at random points.  At least, that's all I do.
  254. XSorry, no "scan" buttons.  How much did you pay for this program anyway?
  255. X
  256. XVERSION 1.1:
  257. X
  258. XThis version was posted to comp.sys.sgi.
  259. X
  260. XCdreader has been improved in that it buffers up enough audio data to eliminate
  261. Xpractically all pauses in the music that occurred previously.  I was informed
  262. Xthat these were apparently due to cpu conflicts during large amounts of
  263. Xgraphics scrolling.
  264. X
  265. XVERSION 1.0:
  266. X
  267. XThis version was uploaded to uunet's ~ftp/tmp directory via anonymous ftp
  268. X(don't bother checking, it's not there anymore) and announced in comp.sys.sgi.
  269. X
  270. XIt was my first (barely) working version of this program.
  271. X
  272. X------------------------------------------------------------------------------
  273. X            MISC NOTES:
  274. X
  275. XThere is a minor error in Irix 4.0.1's cdaudio.h include file which causes
  276. Xwarning messages complaining about an extra comma.  Ignore them, or fix the
  277. Xinclude file.  Also, some manpages for CD routines are incorrect, or contain
  278. Xtypos.  These are all supposed to be fixed in the next Irix release.
  279. X
  280. XWhile working on cdreader, I discovered a problem in the SGI CD audio library
  281. Xroutine CDreadda().  See comments in the source code.  I've been told that this
  282. Xis fixed in the next Irix release, so after you upgrade, be sure to remove the
  283. X-DIRIX401_CDREADDA_BUG from the Makefile and recompile.
  284. X
  285. XThere is a 2-4 second delay for anything to happen (play, pause, stop).
  286. XThat's because of the huge audio buffer being used.
  287. X
  288. XA couple advantages of my cdreader over SGI's cdplayer program:
  289. X
  290. X- There is a noticible clicking noise coming out of my cdrom drive's audio
  291. X  jacks (where the audio output comes when running SGI's cdplayer).  This is
  292. X  not the clicking that some people describe when the audio pauses due to cpu
  293. X  scheduling conflicts, it's some distortion, apparently from the cdrom drive
  294. X  motor.  I don't know if this problem is common to all cdrom drives, but it
  295. X  sure is annoying.  Cdreader's output is the DAC jacks on the back of the
  296. X  Indigo, and doesn't have this problem.
  297. X
  298. X- When using SGI's cdplayer, the volume coming out of the audio jacks on the
  299. X  back of the SGI CDrom drive is very low.  You really have to jack up the
  300. X  volume on your amp higher than normal.
  301. X
  302. X- The CD doesn't spin while in "stopped" or "paused" modes.
  303. X
  304. XTHANK YOU SGI, for making such wonderful libraries available.  They make
  305. Xmy Indigo an extremely fun machine to use.
  306. X
  307. X        Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  308. X        System Programmer/Operations Manager, Kuck & Associates
  309. X
  310. X
  311. X------------------------------------------------------------------------------
  312. X            LEGAL JUNK:
  313. X
  314. X/*
  315. X * Original Author:  Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  316. X *
  317. X * This software is Copyright (c) 1992 by Patrick J. Wolfe.
  318. X *
  319. X * Permission is hereby granted to copy, distribute or otherwise 
  320. X * use any part of this package as long as you do not try to make 
  321. X * money from it or pretend that you wrote it.  This copyright 
  322. X * notice must be maintained in any copy made.
  323. X *
  324. X * Use of this software constitutes acceptance for use in an AS IS 
  325. X * condition. There are NO warranties with regard to this software.  
  326. X * In no event shall the author be liable for any damages whatsoever 
  327. X * arising out of or in connection with the use or performance of this 
  328. X * software.  Any use of this software is at the user's own risk.
  329. X *
  330. X * If you make modifications to this software that you feel 
  331. X * increases it usefulness for the rest of the community, please 
  332. X * email the changes, enhancements, bug fixes as well as any and 
  333. X * all ideas to me. This software is going to be maintained and 
  334. X * enhanced as deemed necessary by the community.
  335. X *              
  336. X *              Patrick J. Wolfe
  337. X *              uunet!kailand!pwolfe
  338. X *              pwolfe@kai.com
  339. X */
  340. X------------------------------------------------------------------------------
  341. END_OF_FILE
  342.   if test 8070 -ne `wc -c <'Readme'`; then
  343.     echo shar: \"'Readme'\" unpacked with wrong size!
  344.   fi
  345.   # end of 'Readme'
  346. fi
  347. if test -f 'cdreader.1' -a "${1}" != "-c" ; then 
  348.   echo shar: Will not clobber existing file \"'cdreader.1'\"
  349. else
  350.   echo shar: Extracting \"'cdreader.1'\" \(2203 characters\)
  351.   sed "s/^X//" >'cdreader.1' <<'END_OF_FILE'
  352. X.TH CDREADER 1 "V1.4" "Usenet Software" "Usenet software"
  353. X
  354. X.SH NAME
  355. Xcdreader \- play an audio compact disc through the audio processor
  356. X
  357. X.SH SYNOPSIS
  358. X.B cdreader
  359. X
  360. X.SH DESCRIPTION
  361. X.B Cdreader
  362. Xplays an audio compact disc through the audio processor. 
  363. X
  364. XIt opens a window with several buttons, whose function is similar to those on a
  365. Xaudio CD player.  Above the buttons is a message display, where the state of
  366. Xthe program is displayed.  When playing music, the track number and length
  367. Xappear here.
  368. X
  369. X.B Cdreader
  370. Xperforms much better when installed setuid root, or if you
  371. Xreconfigure your Irix operating system to allow non-root
  372. Xusers to use non-degrading priorities.  See the
  373. X.I schedctl(2)
  374. Xand
  375. X.I autoconfig(1M)
  376. Xmanpages, and the
  377. X.I Irix Programming Guide Vol 2
  378. Xsection 14.2.3 for complete details (It's easy).
  379. X
  380. XThere is a 2-4 second delay for anything to happen (Play, Pause, Stop).  This
  381. Xis because of the large audio buffer being used.  It takes time to fill it up
  382. Xand empty it out.  Other than that, and the weird things the buttons do
  383. Xoccationally, everything works fine.
  384. X
  385. X.SH "BUTTONS"
  386. XSeveral buttons appear in the main
  387. X.B Cdreader
  388. Xwindow.  They are:
  389. X
  390. X.TP
  391. X.I Play
  392. XIf stopped, begins playing the first track of an audio CD.
  393. XIf paused, continues where you left off.
  394. X.TP
  395. X.I Pause
  396. XSuspends audio playback.  Press Play to continue.
  397. X.TP
  398. X.I Shuffle
  399. XBegins playing all the tracks on the CD, but in a random order.
  400. X.TP
  401. X.I Stop
  402. XStops audio playback.  Resets the current location to the
  403. Xfirst track of the CD.
  404. X.TP
  405. X.I Prev
  406. Xswitches to the beginning of the previous track.
  407. X.TP
  408. X.I Next
  409. Xswitches to the beginning of the next track.  If you press
  410. XNext while on the last track, playback stops.
  411. X.TP
  412. X.I Tracks
  413. Xdisplays a list of tracks and their lengths.  Sorry, but the
  414. Xnames of the songs is NOT encoded on the CD.  Bummer.
  415. X.TP
  416. X.I Eject
  417. XCauses the CD caddy to be ejected from the CDrom drive.
  418. X.TP
  419. X.I Quit
  420. Xcloses the window and terminates the cdreader program.
  421. X.TP
  422. X.I Info
  423. Xdisplays information about the program and programmer.
  424. X.TP
  425. X.I Help
  426. Xdisplays an online help window
  427. X
  428. X.SH "SEE ALSO"
  429. Xcdplayer(1), apanel(1)
  430. X
  431. X.SH "AUTHOR"
  432. X.B Cdreader
  433. Xis Copyright (c) 1992 by Patrick J. Wolfe,
  434. X(pwolfe@kai.com, uunet!kailand!pwolfe).
  435. END_OF_FILE
  436.   if test 2203 -ne `wc -c <'cdreader.1'`; then
  437.     echo shar: \"'cdreader.1'\" unpacked with wrong size!
  438.   fi
  439.   # end of 'cdreader.1'
  440. fi
  441. if test -f 'cdreader.c' -a "${1}" != "-c" ; then 
  442.   echo shar: Will not clobber existing file \"'cdreader.c'\"
  443. else
  444.   echo shar: Extracting \"'cdreader.c'\" \(34681 characters\)
  445.   sed "s/^X//" >'cdreader.c' <<'END_OF_FILE'
  446. X/*
  447. X *    cdreader - Plays an audio CD through the SGI Audio Processor.
  448. X *    You can play CDs through the monophonic speaker on your SGI Indigo,
  449. X *    or you can connect an amp to the line-out jacks for some
  450. X *    REAL quality sound.
  451. X *
  452. X *    Original Author:  Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  453. X *    This software is Copyright (c) 1992 by Patrick J. Wolfe.
  454. X *    See the end of this file for the complete copyright notice.
  455. X */
  456. X
  457. X#define VERSION "1.4"
  458. X
  459. X#include <stdio.h>
  460. X#include <stdlib.h>
  461. X#include <sys/types.h>
  462. X    /* for errno */
  463. X#include <errno.h>
  464. X    /* for signal() */
  465. X#include <signal.h>
  466. X    /* for getopt() */
  467. X#include <getopt.h>
  468. X    /* for CD*() routines */
  469. X#include <cdaudio.h>
  470. X    /* for AL*() routines */
  471. X#include <audio.h>
  472. X    /* for schedctl() */
  473. X#include <limits.h>
  474. X#include <sys/prctl.h>
  475. X#include <sys/schedctl.h>
  476. X    /* for X11/Motif interface */
  477. X#include <X11/Intrinsic.h>
  478. X#include <Xm/Xm.h>
  479. X#include <Xm/CascadeB.h>
  480. X#include <Xm/Frame.h>
  481. X#include <Xm/MainW.h>
  482. X#include <Xm/PushB.h>
  483. X#include <Xm/PushBG.h>
  484. X#include <Xm/RowColumn.h>
  485. X#include <Xm/MessageB.h>
  486. X#include <Xm/Form.h>
  487. X
  488. X#ifdef WATCH_ABUF
  489. X    /* for setitimer */
  490. X#include <sys/time.h>
  491. Xint monitor_interval = 15;    /* number of seconds between abufs left reports */
  492. Xint show_bufsleft = 0;        /* flag to indicate that it's time to report */
  493. Xint total_samps = 0;        /* number of samples the audio buffer will hold */
  494. X#endif /* WATCH_ABUF */
  495. X
  496. X/*
  497. X *    Most of the common messages are here, for easy customization and
  498. X *    translation for foreign languages.  We're not ALL ignorant bastards.
  499. X */
  500. X
  501. X    /* button labels */
  502. X#define PLAY_NAME "Play"
  503. X#define PREV_NAME "Prev"
  504. X#define PAUSE_NAME "Pause"
  505. X#define NEXT_NAME "Next"
  506. X#define SHUFFLE_NAME "Shuffle"
  507. X#define TRACKS_NAME "Tracks"
  508. X#define STOP_NAME "Stop"
  509. X#define EJECT_NAME "Eject"
  510. X#define QUIT_NAME "Quit"
  511. X#define INFO_NAME "Info"
  512. X#define HELP_NAME "Help"
  513. X
  514. X    /* status messages */
  515. Xchar *Playing_Msg = "Playing Track";
  516. Xchar *Stopped_Msg = "Stopped";
  517. Xchar *Paused_Msg = "Paused at Track";
  518. Xchar *Total_Msg = "Total time on disk";
  519. Xchar *Track_Word = "Track";
  520. Xchar *Length_Word = "Length";
  521. X
  522. X    /* error messages */
  523. Xchar *DISC_NOT_READY = "Disc Not Ready";
  524. Xchar *CANNOT_READ_SCSI = "\
  525. XYour cheapo CDrom drive does NOT support reading audio data\n\
  526. Xacross the SCSI bus.  You should have bought one from SGI!";
  527. Xchar *TOO_MANY_TRACKS = "Too many audio tracks on this disc!\nrecompile with larger MAX_TRACK_INFO.";
  528. Xchar *CDOPEN_FAILED = "CDopen failed\nCannot Open CDrom device";
  529. Xchar *CDGETSTATUS_FAILED = "CDgetstatus failed\nCannot get status of CDrom device";
  530. Xchar *CDGETTRACKINFO_FAILED = "CDgettrackinfo failed";
  531. Xchar *CDSEEKTRACK_FAILED = "CDseektrack failed\nCannot find track";
  532. Xchar *CDEJECT_FAILED = "cannot eject disc - not stopped";
  533. X
  534. X
  535. X
  536. X#define SAMPLES_PER_FRAME    (CDDA_DATASIZE/2)
  537. X
  538. X/* valid states for main process loop control */
  539. X#define STOPPED        0    /* we are stopped */
  540. X#define PAUSED        1    /* we were playing, and are now paused */
  541. X#define PLAYING        2    /* we are playing music */
  542. X#define STARTING    3    /* start playing at beginning of the disk */
  543. X#define CONTINUE    4    /* start playing where you left off */
  544. X#define STOPPING    5    /* we were playing, and are about to stop */
  545. X#define PAUSING        6    /* we were playing, and are about to pause */
  546. X#define START_TRACK    9    /* start playing at the beginning of the current track */
  547. X
  548. X/* maximum number of tracks to store info for */
  549. X/* I *have* seen up to 28 tracks on a single CD, but none longer */
  550. X#define MAX_TRACK_INFO    64
  551. X
  552. X    /* audio stuff */
  553. XALport audio_port = NULL;
  554. XCDPLAYER *cd_device = NULL;
  555. XCDPARSER *cd_parser = NULL;
  556. XCDFRAME *cd_buffer = NULL;
  557. X
  558. X    /* cd stuff */
  559. Xstruct cdinformation {
  560. X    short length_min;            /* track length */
  561. X    short length_sec;
  562. X    } track_info[MAX_TRACK_INFO];
  563. Xint first_track = 0;                /* first track on the disk */
  564. Xint last_track = 0;                /* index into track_info for entry AFTER last one we have info for */
  565. Xint current_track = -1;                /* number of track currently playing */
  566. Xint total_min = 0;                /* minutes part of total running time on current disk */
  567. Xint total_sec = 0;                /* second part of total running time on current disk */
  568. Xint play_index = -1;                /* index into playlist for shuffle mode, -1 means that shuffle is not on */
  569. Xint play_list[MAX_TRACK_INFO];            /* order of tracks to play */
  570. Xint cd_readsize = 12;                /* the normal number of frames to read at one time (CDbestreadsize fills this in) */
  571. Xint cd_init_readsize = 200;            /* initial number of frames to read at the beginning of the disc */
  572. Xint status = STOPPING;                /* main process loop status */
  573. X
  574. X    /* X11 stuff */
  575. XXtAppContext    appcon;
  576. XWidget    main_window,
  577. X    label,
  578. X    play_button,
  579. X    prev_button,
  580. X    pause_button,
  581. X    next_button,
  582. X    shuffle_button,
  583. X    tracks_button,
  584. X    info_button,
  585. X    stop_button,
  586. X    eject_button;
  587. Xstatic XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
  588. X
  589. X
  590. XDisplay_Warning (message)
  591. Xchar *message;
  592. X{
  593. XWidget button;
  594. XWidget warning_box;
  595. XXmString title_string = NULL;
  596. XXmString message_string = NULL;
  597. XArg args[4];
  598. Xregister int n;
  599. X
  600. Xmessage_string = XmStringCreateLtoR (message, charset);
  601. Xtitle_string = XmStringCreateLtoR ("Cdreader Warning!", charset);
  602. X
  603. Xn = 0;
  604. XXtSetArg (args[n], XmNdialogTitle, title_string); n++;
  605. XXtSetArg (args[n], XmNmessageString, message_string); n++;
  606. Xwarning_box = XmCreateWarningDialog (main_window, "warning", args, n);
  607. Xbutton = XmMessageBoxGetChild (warning_box, XmDIALOG_CANCEL_BUTTON);
  608. XXtUnmanageChild (button);
  609. Xbutton = XmMessageBoxGetChild (warning_box, XmDIALOG_HELP_BUTTON);
  610. XXtUnmanageChild (button);
  611. Xif (title_string) XtFree (title_string);
  612. Xif (message_string) XtFree (message_string);
  613. XXtManageChild (warning_box);
  614. X}
  615. X
  616. X
  617. Xset_message (message)
  618. Xchar *message;
  619. X{
  620. XXmString label_string;
  621. XArg    args[30];
  622. Xint ctr;
  623. X
  624. Xctr = 0;
  625. Xlabel_string = XmStringCreate (message, charset);
  626. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  627. XXtSetValues (label, args, ctr);
  628. XXmStringFree (label_string);
  629. X}
  630. X
  631. X
  632. Xint
  633. Xget_track_info ()
  634. X{
  635. XCDSTATUS cd_status;
  636. XCDTRACKINFO cd_info;
  637. X
  638. Xif ((cd_device == NULL) && ((cd_device = CDopen(0, "r")) == NULL)) {
  639. X    Display_Warning (CDOPEN_FAILED);
  640. X    return (1);
  641. X    }
  642. X
  643. X/* display disk info */
  644. Xif (CDgetstatus(cd_device, &cd_status) == 0) {
  645. X    status = STOPPING;
  646. X    Display_Warning (CDGETSTATUS_FAILED);
  647. X    return (1);
  648. X    }
  649. X/* don't start unless it's ready */
  650. Xif (cd_status.state != CD_READY) {
  651. X    status = STOPPING;
  652. X    Display_Warning (DISC_NOT_READY);
  653. X    return (1);
  654. X    }
  655. Xif (! cd_status.scsi_audio) {
  656. X    status = STOPPING;
  657. X    Display_Warning (CANNOT_READ_SCSI);
  658. X    return (1);
  659. X    }
  660. Xtotal_min = cd_status.total_min;
  661. Xtotal_sec = cd_status.total_sec;
  662. X
  663. X/* get track information */
  664. Xfor (first_track = last_track = cd_status.first;
  665. X  (last_track <= cd_status.last) && (last_track < MAX_TRACK_INFO);
  666. X  last_track++) {
  667. X    if (CDgettrackinfo(cd_device, last_track, &cd_info) == 0) {
  668. X        status = STOPPING;
  669. X        Display_Warning (CDGETTRACKINFO_FAILED);
  670. X        return (1);
  671. X        }
  672. X    track_info[last_track].length_min = cd_info.total_min;
  673. X    track_info[last_track].length_sec = cd_info.total_sec;
  674. X    }
  675. Xif (last_track >= MAX_TRACK_INFO) {
  676. X    Display_Warning (TOO_MANY_TRACKS);
  677. X    return (1);
  678. X    }
  679. X
  680. X/* find the best number of frames to read at a time */
  681. Xcd_readsize = CDbestreadsize (cd_device);
  682. X
  683. Xreturn (0);
  684. X}
  685. X
  686. X
  687. X/* called as signal handler, and when the quit button is pressed */
  688. Xvoid
  689. Xquit_pgm ()
  690. X{
  691. XCDdeleteparser(cd_parser);    /* free parser memory */
  692. Xif (cd_device != NULL) {
  693. X    CDclose(cd_device);        /* close CD player port */
  694. X    }
  695. Xif (audio_port != NULL) {
  696. X    ALcloseport(audio_port);    /* close audio port */
  697. X    }
  698. Xexit (0);
  699. X}
  700. X
  701. X
  702. X/* called by pressing the EJECT button */
  703. Xvoid
  704. Xeject_callback (w, client_data, call_data)
  705. XWidget w;
  706. Xcaddr_t client_data;    /* unused */
  707. Xcaddr_t call_data;    /* unused */
  708. X{
  709. Xif (status == STOPPED) {
  710. X    if ((cd_device == NULL) && ((cd_device = CDopen(0, "r")) == NULL)) {
  711. X        Display_Warning (CDOPEN_FAILED);
  712. X        }
  713. X    else    {
  714. X        CDeject(cd_device);
  715. X        CDclose(cd_device);
  716. X        cd_device = NULL;
  717. X        }
  718. X    }
  719. Xelse    {
  720. X    Display_Warning (CDEJECT_FAILED);
  721. X    }
  722. X}
  723. X
  724. X
  725. X/* called by pressing the STOP button */
  726. Xvoid
  727. Xstop_callback (w, client_data, call_data)
  728. XWidget w;
  729. Xcaddr_t client_data;    /* unused */
  730. Xcaddr_t call_data;    /* unused */
  731. X{
  732. Xplay_index = -1;
  733. Xstatus = STOPPING;
  734. X}
  735. X
  736. X
  737. X/* called by pressing the PAUSE button */
  738. Xvoid
  739. Xpause_callback (w, client_data, call_data)
  740. XWidget w;
  741. Xcaddr_t client_data;    /* unused */
  742. Xcaddr_t call_data;    /* unused */
  743. X{
  744. Xif (status == PLAYING) {
  745. X    status = PAUSING;
  746. X    }
  747. X}
  748. X
  749. X
  750. X/* called by pressing the PLAY button */
  751. Xvoid
  752. Xplay_callback (w, client_data, call_data)
  753. XWidget w;
  754. Xcaddr_t client_data;    /* unused */
  755. Xcaddr_t call_data;    /* unused */
  756. X{
  757. Xif (status == STOPPED) {
  758. X    status = STARTING;
  759. X    }
  760. Xelse if (status == PAUSED) {
  761. X    status = CONTINUE;
  762. X    }
  763. X}
  764. X
  765. X
  766. X/* called by pressing the PREV button */
  767. Xvoid
  768. Xprev_callback (w, client_data, call_data)
  769. XWidget w;
  770. Xcaddr_t client_data;    /* unused */
  771. Xcaddr_t call_data;    /* unused */
  772. X{
  773. Xchar message[64];
  774. X
  775. Xif ((cd_device == NULL) && get_track_info()) {        /* opens cd_device and gets track_info[] */
  776. X    status = STOPPING;
  777. X    return;
  778. X    }
  779. X
  780. Xif ((status == PLAYING) || (status == PAUSED) || (status == STOPPED)) {
  781. X    if (play_index == -1) {
  782. X        current_track--;
  783. X        if (current_track < first_track) {
  784. X            current_track = first_track;
  785. X            }
  786. X        }
  787. X    else    { /* shuffling */
  788. X        play_index--;
  789. X        if (play_index < first_track) {
  790. X            play_index = first_track;
  791. X            }
  792. X        current_track = play_list[play_index];
  793. X        }
  794. X
  795. X    if (CDseektrack(cd_device, current_track) == -1) {
  796. X        (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
  797. X        Display_Warning (message);
  798. X        status = STOPPING;
  799. X        }
  800. X    else if (status == PLAYING) {
  801. X        status = CONTINUE;
  802. X        }
  803. X    else    {
  804. X        status = PAUSING;
  805. X        }
  806. X    }
  807. X}
  808. X
  809. X
  810. X/* called by pressing the NEXT button */
  811. Xvoid
  812. Xnext_callback (w, client_data, call_data)
  813. XWidget w;
  814. Xcaddr_t client_data;    /* unused */
  815. Xcaddr_t call_data;    /* unused */
  816. X{
  817. Xchar message[64];
  818. X
  819. Xif ((cd_device == NULL) && get_track_info()) {        /* opens cd_device and gets track_info[] */
  820. X    status = STOPPING;
  821. X    return;
  822. X    }
  823. X
  824. Xif ((status == PLAYING) || (status == PAUSED) || (status == STOPPED)) {
  825. X    if (play_index < 0) {
  826. X        current_track++;
  827. X        if (current_track >= last_track) {
  828. X            current_track = first_track;
  829. X            status = STOPPING;
  830. X            return;
  831. X            }
  832. X        }
  833. X    else    {    /* shuffling */
  834. X        play_index++;
  835. X        if (play_index >= last_track) {
  836. X            current_track = first_track;
  837. X            status = STOPPING;
  838. X            return;
  839. X            }
  840. X        current_track = play_list[play_index];
  841. X        }
  842. X
  843. X    if (CDseektrack(cd_device, current_track) == -1) {
  844. X        (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
  845. X        Display_Warning (message);
  846. X        status = STOPPING;
  847. X        }
  848. X    else if (status == PLAYING) {
  849. X        status = CONTINUE;
  850. X        }
  851. X    else    {
  852. X        status = PAUSING;
  853. X        }
  854. X    }
  855. X}
  856. X
  857. X
  858. X/* called by pressing the SHUFFLE button
  859. X * plays all tracks on the disk in a random order
  860. X */
  861. Xvoid
  862. Xshuffle_callback (w, client_data, call_data)
  863. XWidget w;
  864. Xcaddr_t client_data;    /* unused */
  865. Xcaddr_t call_data;    /* unused */
  866. X{
  867. Xdouble jdb;
  868. Xint i, j, m, d = 1;
  869. Xint played[MAX_TRACK_INFO];
  870. X
  871. Xif (get_track_info()) {        /* opens cd_device and gets track_info[] */
  872. X    status = STOPPING;
  873. X    return;
  874. X    }
  875. X
  876. Xm = last_track - 1;
  877. X
  878. X/* initialize played array to -1's, indicating track hasn't been selected to play yet */
  879. Xfor (i = first_track; i < last_track; i++) {
  880. X    played[i] = 0;
  881. X    }
  882. X
  883. X/* seed is our process id */
  884. Xsrand ((u_int) getpid());
  885. X
  886. Xfor (i = first_track; i < last_track; i++) {
  887. X    j = rand( );
  888. X    jdb = (double)j / (double)(RAND_MAX + 1);
  889. X    j = (int)(jdb * m) + 1;
  890. X    for (; played[j]; j += d) {
  891. X        if (j < first_track) {
  892. X            j = last_track;
  893. X            }
  894. X        else if (j >= last_track) {
  895. X            j = first_track;
  896. X            }
  897. X        }
  898. X    d = d * -1;    /* switch direction */
  899. X    play_list[i] = j;
  900. X    played[j] = 1;
  901. X    }
  902. X
  903. Xplay_index = first_track;
  904. Xcurrent_track = play_list[play_index];
  905. Xstatus = START_TRACK;
  906. X}
  907. X
  908. X
  909. X/* called by pressing the TRACKS button */
  910. X/* show info about the entire disk */
  911. Xvoid
  912. Xtracks_callback (w, client_data, call_data)
  913. XWidget w;
  914. Xcaddr_t client_data;    /* unused */
  915. Xcaddr_t call_data;    /* unused */
  916. X{
  917. XWidget button;
  918. XWidget message_box;
  919. XXmString title_string = NULL;
  920. XXmString message_string = NULL;
  921. XXmString button_string = NULL;
  922. XArg args[4];
  923. Xregister int n;
  924. Xint track;
  925. Xchar message[4096];
  926. Xchar line[256];
  927. X
  928. Xif ((status == STOPPED) && get_track_info() ) {
  929. X    return;    /* if stopped, try to re-read the track info - might be a new disc */
  930. X    }
  931. Xif ((status != PLAYING) && (status != PAUSED) && (status != STOPPED)) {
  932. X    return;        /* ignore this button during odd status changes */
  933. X    }
  934. X(void) sprintf (message, "%s = %02d:%02d\n\n", Total_Msg, total_min, total_sec);
  935. X
  936. X/* show info about each track */
  937. Xfor (track = first_track; track < last_track; track++) {
  938. X    (void) sprintf (line, "\t%s %2d:  %s %02d:%02d\n", Track_Word, track, Length_Word,
  939. X        track_info[track].length_min, track_info[track].length_sec);
  940. X    (void) strcat (message, line);
  941. X    }
  942. X
  943. Xtitle_string = XmStringCreateLtoR ("Cdreader Track List", charset);
  944. Xbutton_string = XmStringCreateLtoR ("Close", charset);
  945. Xmessage_string = XmStringCreateLtoR (message, charset);
  946. X
  947. Xn = 0;
  948. XXtSetArg (args[n], XmNdialogTitle, title_string); n++;
  949. XXtSetArg (args[n], XmNokLabelString, button_string); n++;
  950. XXtSetArg (args[n], XmNmessageString, message_string); n++;
  951. Xmessage_box = XmCreateMessageDialog (main_window, "tracks", args, n);
  952. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
  953. XXtUnmanageChild (button);
  954. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
  955. XXtUnmanageChild (button);
  956. Xif (title_string) XtFree (title_string);
  957. Xif (button_string) XtFree (button_string);
  958. Xif (message_string) XtFree (message_string);
  959. XXtManageChild (message_box);
  960. X}
  961. X
  962. X
  963. X/* called by pressing the INFO button */
  964. Xvoid
  965. Xinfo_callback (w, client_data, call_data)
  966. XWidget w;
  967. Xcaddr_t client_data;    /* unused */
  968. Xcaddr_t call_data;    /* unused */
  969. X{
  970. XWidget button;
  971. XWidget message_box;
  972. Xchar message[2048];
  973. XXmString title_string = NULL;
  974. XXmString message_string = NULL;
  975. XXmString button_string = NULL;
  976. XArg args[4];
  977. Xregister int n;
  978. X
  979. X(void) sprintf (message, "\
  980. XCdreader V%s plays an audio compact disc loaded in an SGI cdrom drive through\n\
  981. Xthe Audio Processor.\n\
  982. X\n\
  983. XCdreader uses the libcdaudio routines to read the digital data directly from\n\
  984. Xthe cdrom drive, and plays it through the Audio Processor.  You can listen on\n\
  985. Xthe Indigo's speaker, or even better, buy a cable with a stereo mini-plug on\n\
  986. Xone end, and two phono plugs on the other, and connect from your Indigo's\n\
  987. Xline out jack to your stereo amplifier's cd in or tape in jacks.\n\
  988. X\n\
  989. XCdreader will probably only work with an SGI's cdrom drive and under release\n\
  990. X4.0.1 (or later) of the Irix operating system.  The program will tell you if\n\
  991. Xyour cdrom drive doesn't support reading audio over the SCSI bus.  It uses\n\
  992. Xabout 5-6%% of the cpu, and 4%% of the SCSI bus bandwidth.  Use of other\n\
  993. Xprograms which change the audio processor's parameters is discouraged (but\n\
  994. Xsure can make you chuckle).\n\
  995. X\n\
  996. XOriginal Author:\n\
  997. X\tPatrick Wolfe\n\
  998. X\tSystem Programmer/Operations Manager\n\
  999. X\tKuck & Associates\n\
  1000. X\t1906 Fox Drive\n\
  1001. X\tChampaign, IL 61820\n\
  1002. X\tInternet:  pwolfe@kai.com\n\
  1003. X\tUUCP:      uunet!kailand!pwolfe\n\
  1004. X\tvoice:     (217) 356-2288\n\
  1005. X\tFAX:       (217) 356-5199\n\
  1006. Xcopyright (c) 1992 Patrick J. Wolfe\n", VERSION);
  1007. X
  1008. Xmessage_string = XmStringCreateLtoR (message, charset);
  1009. Xbutton_string = XmStringCreateLtoR ("Close", charset);
  1010. Xtitle_string = XmStringCreateLtoR ("Cdreader Information", charset);
  1011. X
  1012. Xn = 0;
  1013. XXtSetArg (args[n], XmNdialogTitle, title_string); n++;
  1014. XXtSetArg (args[n], XmNokLabelString, button_string); n++;
  1015. XXtSetArg (args[n], XmNmessageString, message_string); n++;
  1016. Xmessage_box = XmCreateMessageDialog (w, "credit", args, n);
  1017. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
  1018. XXtUnmanageChild (button);
  1019. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
  1020. XXtUnmanageChild (button);
  1021. Xif (title_string) XtFree (title_string);
  1022. Xif (button_string) XtFree (button_string);
  1023. Xif (message_string) XtFree (message_string);
  1024. XXtManageChild (message_box);
  1025. X}
  1026. X
  1027. X
  1028. X/* called by pressing the HELP button */
  1029. Xvoid
  1030. Xhelp_callback (w, client_data, call_data)
  1031. XWidget w;
  1032. Xcaddr_t client_data;    /* unused */
  1033. Xcaddr_t call_data;    /* unused */
  1034. X{
  1035. XWidget button;
  1036. XWidget message_box;
  1037. Xchar message[2048];
  1038. XXmString title_string = NULL;
  1039. XXmString message_string = NULL;
  1040. XXmString button_string = NULL;
  1041. XArg args[4];
  1042. Xregister int n;
  1043. X
  1044. X(void) sprintf (message, "\
  1045. XCdreader V%s plays an audio compact disc loaded in an SGI cdrom drive through\n\
  1046. Xthe Audio Processor.\n\n\
  1047. XTo get started, load an audio CD in the caddy, and insert it into your cd drive\n\
  1048. Xwith the clear side of the caddy facing up.\n\n\
  1049. XThe buttons function as follows:\n\
  1050. X\tPlay    - plays an audio disk\n\
  1051. X\tShuffle - plays the whole disk in a random order\n\
  1052. X\tStop    - stops playback\n\
  1053. X\tPause   - suspends playback - press Play to continue\n\
  1054. X\tNext    - selects the next track\n\
  1055. X\tPrev    - selects the previous track\n\
  1056. X\tTracks  - displays a table of tracks and their lengths\n\n\
  1057. X\tEject   - ejects the disk from the cdrom drive\n\
  1058. XThe buttons are context sensitive, for example, the eject button won't function\n\
  1059. Xunless the program is in the \"Stopped\" state.  Buttons are are not active will\n\
  1060. Xappear dimly shaded.\n\n\
  1061. XNear the top of the window is a menu bar.  On the bar are three buttons:\n\
  1062. X\tQuit    - terminates the program\n\
  1063. X\tInfo    - give the author some credit!\n\
  1064. X\tHelp    - uh, you're looking at it\n\
  1065. X", VERSION);
  1066. X
  1067. Xmessage_string = XmStringCreateLtoR (message, charset);
  1068. Xbutton_string = XmStringCreateLtoR ("Close", charset);
  1069. Xtitle_string = XmStringCreateLtoR ("Cdreader Help", charset);
  1070. X
  1071. Xn = 0;
  1072. XXtSetArg (args[n], XmNdialogTitle, title_string); n++;
  1073. XXtSetArg (args[n], XmNokLabelString, button_string); n++;
  1074. XXtSetArg (args[n], XmNmessageString, message_string); n++;
  1075. Xmessage_box = XmCreateMessageDialog (w, "helpbox", args, n);
  1076. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
  1077. XXtUnmanageChild (button);
  1078. Xbutton = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
  1079. XXtUnmanageChild (button);
  1080. Xif (title_string) XtFree (title_string);
  1081. Xif (button_string) XtFree (button_string);
  1082. Xif (message_string) XtFree (message_string);
  1083. XXtManageChild (message_box);
  1084. X}
  1085. X
  1086. X
  1087. X/* called only when the program (track) number changes */
  1088. Xvoid
  1089. Xcd_pnum_callback (arg, type, data)
  1090. Xint arg;
  1091. XCDDATATYPES type;
  1092. Xstruct cdprognum *data;
  1093. X{
  1094. Xchar message[32];
  1095. X
  1096. Xif (play_index == -1) {
  1097. X    current_track = data->value;
  1098. X    (void) sprintf (message, "%s %d - %s %2d:%02d", Playing_Msg, current_track, Length_Word,
  1099. X        track_info[current_track].length_min,
  1100. X        track_info[current_track].length_sec);
  1101. X    set_message (message);
  1102. X    }
  1103. Xelse if (data->value != current_track) {    /* shuffling and the track changed */
  1104. X    play_index++;
  1105. X    if (play_index >= last_track) {
  1106. X        status = STOPPING;
  1107. X        }
  1108. X    else    {
  1109. X        current_track = play_list[play_index];
  1110. X        status = START_TRACK;
  1111. X        }
  1112. X    }
  1113. X}
  1114. X
  1115. X
  1116. X/* called for every frame - data is already byte swapped and de-emphasized */
  1117. Xvoid
  1118. Xcd_audio_callback (arg, type, data)
  1119. Xint arg;
  1120. XCDDATATYPES type;
  1121. Xvoid *data;
  1122. X{
  1123. XALwritesamps (audio_port, data, SAMPLES_PER_FRAME);
  1124. X}
  1125. X
  1126. X
  1127. Xint
  1128. Xinit_audio ()
  1129. X{
  1130. XALconfig aconfig;
  1131. Xlong pvbuf[6];
  1132. X
  1133. Xif (audio_port == NULL) {
  1134. X    /* initialize the audio port */
  1135. X    aconfig = ALnewconfig ();
  1136. X
  1137. X    /*
  1138. X     * create the maximum size audio buffer we can,
  1139. X     * in another attempt to avoid pauses in the music.
  1140. X     */
  1141. X    ALsetqueuesize (aconfig, SAMPLES_PER_FRAME * cd_init_readsize);
  1142. X
  1143. X#ifdef WATCH_ABUF
  1144. X    total_samps = SAMPLES_PER_FRAME * cd_init_readsize;
  1145. X    printf ("allocating an audio buffer that can hold %d samples\n", total_samps);
  1146. X#endif /* WATCH_ABUF */
  1147. X
  1148. X    /*
  1149. X     * set the sample to 16 bit width and stereo.  Yes, I know it these are the
  1150. X     * defaults ... TODAY, but I've gotten into trouble before by assuming the
  1151. X     * defaults would never change change.  Besides, it doesn't hurt.
  1152. X     */
  1153. X    ALsetwidth (aconfig, AL_SAMPLE_16);
  1154. X    ALsetchannels (aconfig, AL_STEREO);
  1155. X
  1156. X    audio_port = ALopenport ("cdreader", "w", aconfig);
  1157. X
  1158. X    /* free audio port config buffer immediately */
  1159. X    ALfreeconfig(aconfig);
  1160. X
  1161. X    if (audio_port == NULL) {
  1162. X        Display_Warning ("Could not open a port to the Audio Processor!");
  1163. X        return (1);
  1164. X        }
  1165. X
  1166. X    /* set audio port output sampling rate to 44.1 kHz */
  1167. X    pvbuf[0] = AL_OUTPUT_RATE;
  1168. X    pvbuf[1] = AL_RATE_44100;
  1169. X    ALsetparams (AL_DEFAULT_DEVICE, pvbuf, 2);
  1170. X    }
  1171. Xreturn (0);
  1172. X}
  1173. X
  1174. X
  1175. Xint
  1176. Xinit_cd ()
  1177. X{
  1178. X/* allocate a buffer to read CD data into */
  1179. Xif (cd_buffer == (CDFRAME *) NULL) {
  1180. X    cd_buffer = (CDFRAME *) malloc (cd_init_readsize * CDDA_BLOCKSIZE);
  1181. X    if (cd_buffer == (CDFRAME *) NULL) {
  1182. X        Display_Warning ("cannot allocate enough memory for a cd digital data buffer");
  1183. X        return (1);
  1184. X        }
  1185. X    }
  1186. X
  1187. X/* create parser structure */
  1188. Xif (cd_parser == NULL) {
  1189. X    cd_parser = CDcreateparser ();
  1190. X    if (cd_parser == NULL) {
  1191. X        Display_Warning ("SERIOUS ERROR!\nCDcreateparser failed");
  1192. X        return (1);
  1193. X        }
  1194. X
  1195. X    /* initialize parser structure */
  1196. X    CDresetparser(cd_parser);
  1197. X
  1198. X    /* define callback routines for CDparseframe() */
  1199. X    CDsetcallback (cd_parser, cd_audio, cd_audio_callback, 0);
  1200. X    CDsetcallback (cd_parser, cd_pnum, cd_pnum_callback, 0);
  1201. X    }
  1202. Xreturn (0);
  1203. X}
  1204. X
  1205. X
  1206. Xvoid
  1207. Xinit_motif (argc, argv)
  1208. Xint argc;
  1209. Xchar **argv;
  1210. X{
  1211. XDisplay *display;
  1212. XWidget    app_shell, menu_bar, cascade, frame, form, row_column;
  1213. XXmString label_string;
  1214. XArg args[30];
  1215. Xint ctr;
  1216. X
  1217. XXtToolkitInitialize ();
  1218. Xappcon = XtCreateApplicationContext ();
  1219. Xdisplay = XtOpenDisplay (appcon, NULL, "cdreader", "Cdreader", NULL, 0, &argc, argv);
  1220. Xif (!display) {
  1221. X    XtWarning ("cdreader: Can't open your X display, exiting...");
  1222. X    exit (0);
  1223. X    }
  1224. X
  1225. Xapp_shell = XtAppCreateShell ("cdreader", "Cdreader", applicationShellWidgetClass, display, NULL, 0);
  1226. X
  1227. X/* XtGetApplicationResources (app_shell, &AppData, resources, XtNumber(resources), NULL, 0); */
  1228. X
  1229. Xctr = 0;
  1230. Xmain_window = XmCreateMainWindow (app_shell, "main1", args, ctr);
  1231. XXtManageChild (main_window);
  1232. X
  1233. Xctr = 0;
  1234. Xmenu_bar = XmCreateMenuBar (main_window, "menu_bar", args, ctr);
  1235. XXtManageChild (menu_bar);
  1236. X
  1237. Xctr = 0;
  1238. Xcascade = XmCreateCascadeButton (menu_bar, "Quit", args, ctr);
  1239. XXtManageChild (cascade);
  1240. XXtAddCallback (cascade, XmNactivateCallback, quit_pgm, NULL);
  1241. X
  1242. Xctr = 0;
  1243. Xcascade = XmCreateCascadeButton (menu_bar, "Info", args, ctr);
  1244. XXtManageChild (cascade);
  1245. XXtAddCallback (cascade, XmNactivateCallback, info_callback, NULL);
  1246. X
  1247. Xctr = 0;
  1248. Xcascade = XmCreateCascadeButton (menu_bar, "Help", args, ctr);
  1249. XXtManageChild (cascade);
  1250. XXtAddCallback (cascade, XmNactivateCallback, help_callback, NULL);
  1251. X
  1252. X/* let the menu bar know who's the help button around here */
  1253. Xctr = 0;
  1254. XXtSetArg (args[ctr], XmNmenuHelpWidget, cascade); ctr++;
  1255. XXtSetValues (menu_bar, args, ctr);
  1256. X
  1257. X/* create form to hold everything */
  1258. Xctr = 0;
  1259. Xform = XmCreateForm (main_window, "form", args, ctr);
  1260. XXtManageChild (form);
  1261. X
  1262. X/* create label gadget inside frame */
  1263. Xctr = 0;
  1264. Xlabel_string = XmStringCreate ("Stopped", charset);
  1265. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1266. XXtSetArg (args[ctr], XmNwidth, 230); ctr++;
  1267. XXtSetArg (args[ctr], XmNheight, 35); ctr++;
  1268. XXtSetArg (args[ctr], XmNrecomputeSize, False); ctr++;
  1269. XXtSetArg (args[ctr], XmNleftAttachment, XmATTACH_FORM); ctr++;
  1270. XXtSetArg (args[ctr], XmNrightAttachment, XmATTACH_FORM); ctr++;
  1271. XXtSetArg (args[ctr], XmNtopAttachment, XmATTACH_FORM); ctr++;
  1272. Xlabel = XmCreateLabelGadget (form, "label", args, ctr);
  1273. XXtManageChild (label);
  1274. X
  1275. X/* create frame mainwindow */
  1276. Xctr = 0;
  1277. XXtSetArg (args[ctr], XmNmarginWidth, 2); ctr++;
  1278. XXtSetArg (args[ctr], XmNmarginHeight, 2); ctr++;
  1279. XXtSetArg (args[ctr], XmNshadowThickness, 1); ctr++;
  1280. XXtSetArg (args[ctr], XmNshadowType, XmSHADOW_OUT); ctr++;
  1281. XXtSetArg (args[ctr], XmNleftAttachment, XmATTACH_FORM); ctr++;
  1282. XXtSetArg (args[ctr], XmNrightAttachment, XmATTACH_FORM); ctr++;
  1283. XXtSetArg (args[ctr], XmNtopAttachment, XmATTACH_WIDGET); ctr++;
  1284. XXtSetArg (args[ctr], XmNtopWidget, label); ctr++;
  1285. XXtSetArg (args[ctr], XmNbottomAttachment, XmATTACH_FORM); ctr++;
  1286. Xframe = XmCreateFrame (form, "frame", args, ctr);
  1287. XXtManageChild (frame);
  1288. X
  1289. X/* create rowcolumn in frame to manage buttons */
  1290. Xctr = 0;
  1291. XXtSetArg (args[ctr], XmNpacking, XmPACK_COLUMN); ctr++;
  1292. XXtSetArg (args[ctr], XmNnumColumns, 4); ctr++;
  1293. Xrow_column = XmCreateRowColumn (frame, "row_column", args, ctr);
  1294. XXtManageChild (row_column);
  1295. X
  1296. X/* create buttons by column */
  1297. Xctr = 0;
  1298. Xlabel_string = XmStringCreateLtoR (PLAY_NAME, charset);
  1299. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1300. Xplay_button = XmCreatePushButtonGadget (row_column, PLAY_NAME, args, ctr);
  1301. XXtManageChild (play_button);
  1302. XXtAddCallback (play_button, XmNarmCallback, play_callback, NULL);
  1303. XXmStringFree (label_string);
  1304. X
  1305. Xctr = 0;
  1306. Xlabel_string = XmStringCreateLtoR (PREV_NAME, charset);
  1307. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1308. Xprev_button = XmCreatePushButtonGadget (row_column, PREV_NAME, args, ctr);
  1309. XXtManageChild (prev_button);
  1310. XXtAddCallback (prev_button, XmNarmCallback, prev_callback, NULL);
  1311. XXmStringFree (label_string);
  1312. X
  1313. Xctr = 0;
  1314. Xlabel_string = XmStringCreateLtoR (PAUSE_NAME, charset);
  1315. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1316. Xpause_button = XmCreatePushButtonGadget (row_column, PAUSE_NAME, args, ctr);
  1317. XXtManageChild (pause_button);
  1318. XXtAddCallback (pause_button, XmNarmCallback, pause_callback, NULL);
  1319. XXmStringFree (label_string);
  1320. X
  1321. Xctr = 0;
  1322. Xlabel_string = XmStringCreateLtoR (NEXT_NAME, charset);
  1323. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1324. Xnext_button = XmCreatePushButtonGadget (row_column, NEXT_NAME, args, ctr);
  1325. XXtManageChild (next_button);
  1326. XXtAddCallback (next_button, XmNarmCallback, next_callback, NULL);
  1327. XXmStringFree (label_string);
  1328. X
  1329. Xctr = 0;
  1330. Xlabel_string = XmStringCreateLtoR (SHUFFLE_NAME, charset);
  1331. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1332. Xshuffle_button = XmCreatePushButtonGadget (row_column, SHUFFLE_NAME, args, ctr);
  1333. XXtManageChild (shuffle_button);
  1334. XXtAddCallback (shuffle_button, XmNarmCallback, shuffle_callback, NULL);
  1335. XXmStringFree (label_string);
  1336. X
  1337. Xctr = 0;
  1338. Xlabel_string = XmStringCreateLtoR (TRACKS_NAME, charset);
  1339. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1340. Xtracks_button = XmCreatePushButtonGadget (row_column, TRACKS_NAME, args, ctr);
  1341. XXtManageChild (tracks_button);
  1342. XXtAddCallback (tracks_button, XmNarmCallback, tracks_callback, NULL);
  1343. XXmStringFree (label_string);
  1344. X
  1345. Xctr = 0;
  1346. Xlabel_string = XmStringCreateLtoR (STOP_NAME, charset);
  1347. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1348. Xstop_button = XmCreatePushButtonGadget (row_column, STOP_NAME, args, ctr);
  1349. XXtManageChild (stop_button);
  1350. XXtAddCallback (stop_button, XmNarmCallback, stop_callback, NULL);
  1351. XXmStringFree (label_string);
  1352. X
  1353. Xctr = 0;
  1354. Xlabel_string = XmStringCreateLtoR (EJECT_NAME, charset);
  1355. XXtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
  1356. Xeject_button = XmCreatePushButtonGadget (row_column, EJECT_NAME, args, ctr);
  1357. XXtManageChild (eject_button);
  1358. XXtAddCallback (eject_button, XmNarmCallback, eject_callback, NULL);
  1359. XXmStringFree (label_string);
  1360. X
  1361. X/* set MainWindow areas */
  1362. XXmMainWindowSetAreas (main_window, menu_bar, NULL, NULL, NULL, form);
  1363. X
  1364. X/* put them all on the screen */
  1365. XXtRealizeWidget (app_shell);
  1366. X}
  1367. X
  1368. X
  1369. X#ifdef WATCH_ABUF
  1370. Xvoid
  1371. Xheartbeat ()
  1372. X{
  1373. Xshow_bufsleft = 1;
  1374. Xsignal (SIGALRM, heartbeat);
  1375. X}
  1376. X#endif /* WATCH_ABUF */
  1377. X
  1378. X
  1379. Xmain (argc, argv)
  1380. Xint argc;
  1381. Xchar *argv[];
  1382. X{
  1383. X#ifdef WATCH_ABUF
  1384. Xstruct itimerval itbuf;
  1385. X#endif /* WATCH_ABUF */
  1386. XXEvent an_event;
  1387. Xint frame_ctr, frames_to_play;
  1388. Xchar message[64];
  1389. X
  1390. X/*
  1391. X * Try to increase the scheduling priority of this process.  This should help
  1392. X * reduce pauses in the music, due to cpu scheduling conflicts by making
  1393. X * cdreader one of the highest priority processes in the system.
  1394. X *
  1395. X * The schedctl() system call will fail (silently) unless the program is installed
  1396. X * setuid to root, or the kernel is reconfigured to allow mere mortals to use
  1397. X * non-degrading priorities.  See the SCHEDCTL(2) and AUTOCONFIG(1M) manpages,
  1398. X * and the Irix Programming Guide Vol 2, section 14.2.3 for complete details.
  1399. X *
  1400. X * That's what I did, and it's pretty easy!  Basically, * become superuser,
  1401. X * edit /usr/sysgen/master.d/disp, find the variable "ndpri_hilim", change it's
  1402. X * value to "NDPHIMAX", run "autoconfig" and reboot.
  1403. X *
  1404. X * We don't care if it fails, probably the user doesn't have permission.
  1405. X *
  1406. X *    WARNING!  when testing new code, DON'T do this!  (this is
  1407. X *    the voice of experience talking, so listen up!)  If you get
  1408. X *    into an infinite loop, your system will LOCK UP tight!
  1409. X *    (because cdreader will be the highest priority process,
  1410. X *    and you won't be able to kill it)
  1411. X *    
  1412. X */
  1413. X#ifndef TESTING
  1414. X(void) schedctl (NDPRI, 0, NDPHIMAX+1);
  1415. X#endif
  1416. X
  1417. X/* lose any setuid priviledges assigned to allow schedctl to succeed */
  1418. X(void) seteuid (getuid());
  1419. X
  1420. X(void) signal (SIGHUP, quit_pgm);    /* should really trap everything, right? */
  1421. X(void) signal (SIGINT, quit_pgm);
  1422. X(void) signal (SIGQUIT, quit_pgm);
  1423. X(void) signal (SIGTERM, quit_pgm);
  1424. X
  1425. Xinit_motif (argc, argv);    /* initialize the X11/Motif user interface */
  1426. X
  1427. X/* main process loop */
  1428. Xfor (;;) {
  1429. X    switch (status) {
  1430. X
  1431. X    case PAUSED:
  1432. X    case STOPPED:
  1433. X        XtAppNextEvent (appcon, &an_event);
  1434. X        XtDispatchEvent (&an_event);
  1435. X        break;
  1436. X
  1437. X    case PAUSING:
  1438. X        (void) sprintf (message, "%s %d", Paused_Msg, current_track);
  1439. X        set_message (message);
  1440. X
  1441. X        XtSetSensitive (play_button, True);
  1442. X        XtSetSensitive (stop_button, True);
  1443. X        XtSetSensitive (pause_button, False);
  1444. X        XtSetSensitive (shuffle_button, False);
  1445. X        XtSetSensitive (eject_button, False);
  1446. X
  1447. X#ifdef WATCH_ABUF
  1448. X        /* turn off monitor timer */
  1449. X        signal (SIGALRM, SIG_IGN);
  1450. X        itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = 0;
  1451. X        itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
  1452. X        if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
  1453. X            perror ("setitimer");
  1454. X            return;
  1455. X            }
  1456. X#endif /* WATCH_ABUF */
  1457. X
  1458. X        status = PAUSED;
  1459. X        break;
  1460. X
  1461. X    case STOPPING:
  1462. X        set_message (Stopped_Msg);
  1463. X        current_track = 1;
  1464. X        if (cd_device != NULL) {
  1465. X            CDclose (cd_device);
  1466. X            cd_device = NULL;
  1467. X            }
  1468. X
  1469. X        XtSetSensitive (play_button, True);
  1470. X        XtSetSensitive (shuffle_button, True);
  1471. X        XtSetSensitive (eject_button, True);
  1472. X        XtSetSensitive (pause_button, False);
  1473. X        XtSetSensitive (stop_button, False);
  1474. X
  1475. X#ifdef WATCH_ABUF
  1476. X        /* turn off monitor timer */
  1477. X        signal (SIGALRM, SIG_IGN);
  1478. X        itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = 0;
  1479. X        itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
  1480. X        if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
  1481. X            perror ("setitimer");
  1482. X            return;
  1483. X            }
  1484. X#endif /* WATCH_ABUF */
  1485. X
  1486. X        status = STOPPED;
  1487. X        break;
  1488. X
  1489. X    case STARTING:
  1490. X        if (get_track_info()) {        /* opens cd_device and gets track_info[] */
  1491. X            status = STOPPING;
  1492. X            break;
  1493. X            }
  1494. X        current_track = first_track;    /* play whole disk from the start */
  1495. X        play_index = -1;
  1496. X
  1497. X    case START_TRACK:
  1498. X        if (CDseektrack(cd_device, current_track) == -1) {
  1499. X            (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
  1500. X            Display_Warning (message);
  1501. X            status = STOPPING;
  1502. X            break;
  1503. X            }
  1504. X        /* FALLTHROUGH */
  1505. X
  1506. X    case CONTINUE:
  1507. X        if (init_audio() || init_cd()) {    /* initialize audio port and cd structures */
  1508. X            status = STOPPING;
  1509. X            break;
  1510. X            }
  1511. X
  1512. X        (void) sprintf (message, "%s %d - %s %2d:%02d", Playing_Msg, current_track, Length_Word,
  1513. X            track_info[current_track].length_min,
  1514. X            track_info[current_track].length_sec);
  1515. X        set_message (message);
  1516. X
  1517. X        while (XtAppPending (appcon)) {        /* process any pending X events */
  1518. X            XtAppNextEvent (appcon, &an_event);
  1519. X            XtDispatchEvent (&an_event);
  1520. X            }
  1521. X
  1522. X        XtSetSensitive (pause_button, True);
  1523. X        XtSetSensitive (stop_button, True);
  1524. X        XtSetSensitive (play_button, False);
  1525. X        XtSetSensitive (shuffle_button, False);
  1526. X        XtSetSensitive (eject_button, False);
  1527. X
  1528. X#ifdef WATCH_ABUF
  1529. X        show_bufsleft = 0;
  1530. X        signal (SIGALRM, heartbeat);
  1531. X        itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = monitor_interval;
  1532. X        itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
  1533. X        if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
  1534. X            perror ("setitimer");
  1535. X            return;
  1536. X            }
  1537. X#endif /* WATCH_ABUF */
  1538. X
  1539. X        /*
  1540. X         * read enough cd data to fill the audio buffer, to help
  1541. X         * cover any later pauses due to cpu scheduling.
  1542. X         * Be aware that we might still have some audio data left over
  1543. X         * from a previous pause.
  1544. X         */
  1545. X        frames_to_play = CDreadda (cd_device, &cd_buffer[0], cd_init_readsize);
  1546. X
  1547. X        /* process any pending X events */
  1548. X        while (XtAppPending (appcon)) {
  1549. X            XtAppNextEvent (appcon, &an_event);
  1550. X            XtDispatchEvent (&an_event);
  1551. X            }
  1552. X
  1553. X        if (frames_to_play < 1) {
  1554. X            status = STOPPING;
  1555. X            }
  1556. X        else    {
  1557. X            status = PLAYING;
  1558. X            }
  1559. X        break;
  1560. X
  1561. X    case PLAYING:
  1562. X
  1563. X#ifdef IRIX401_CDREADDA_BUG
  1564. X        /*
  1565. X         *    BUG!  The manpage for CDreadda() says it returns the number
  1566. X         *    of frames read.  In reality, it returns the number of bytes read
  1567. X         *    into the buffer.  Divide by CDDA_BLOCKSIZE to get the number of frames.
  1568. X         *
  1569. X         *    I'd prefer it to work like the manpage says, return the number of frames.
  1570. X         *    This is supposed to be fixed in the next release of Irix (after 4.0.1).
  1571. X         */
  1572. X        frames_to_play = frames_to_play / CDDA_BLOCKSIZE;
  1573. X#endif /* IRIX401_CDREADDA_BUG */
  1574. X
  1575. X        /* process CD data */
  1576. X        for (frame_ctr = 0; frame_ctr < frames_to_play; frame_ctr++) {
  1577. X            CDparseframe (cd_parser, &cd_buffer[frame_ctr]);
  1578. X            }
  1579. X
  1580. X        /* process any pending X events */
  1581. X        while (XtAppPending (appcon)) {
  1582. X            XtAppNextEvent (appcon, &an_event);
  1583. X            XtDispatchEvent (&an_event);
  1584. X            }
  1585. X
  1586. X        /* still playing?  read more CD data */
  1587. X        if (status == PLAYING) {
  1588. X            frames_to_play = CDreadda (cd_device, &cd_buffer[0], cd_readsize);
  1589. X            if (frames_to_play < 1) {    /* end of disc */
  1590. X                status = STOPPING;
  1591. X                }
  1592. X            }
  1593. X
  1594. X#ifdef WATCH_ABUF
  1595. X        if (show_bufsleft) {
  1596. X            show_bufsleft = 0;
  1597. X            printf ("abufs left = %d\n", total_samps - ALgetfilled(audio_port));
  1598. X            }
  1599. X#endif /* WATCH_ABUF */
  1600. X
  1601. X        /* process any pending X events */
  1602. X        while (XtAppPending (appcon)) {
  1603. X            XtAppNextEvent (appcon, &an_event);
  1604. X            XtDispatchEvent (&an_event);
  1605. X            }
  1606. X        break;
  1607. X
  1608. X    default:
  1609. X        Display_Warning ("Cdreader has become horribly confused.\nYou should quit and start the program over");
  1610. X        status = STOPPING;
  1611. X        }
  1612. X    }
  1613. X
  1614. X/* NOTREACHED */
  1615. X}
  1616. X
  1617. X/*
  1618. X * Original Author:  Patrick Wolfe  (pwolfe@kai.com, uunet!kailand!pwolfe)
  1619. X *
  1620. X * This software is Copyright (c) 1992 by Patrick J. Wolfe.
  1621. X *
  1622. X * Permission is hereby granted to copy, distribute or otherwise 
  1623. X * use any part of this package as long as you do not try to make 
  1624. X * money from it or pretend that you wrote it.  This copyright 
  1625. X * notice must be maintained in any copy made.
  1626. X *
  1627. X * Use of this software constitutes acceptance for use in an AS IS 
  1628. X * condition. There are NO warranties with regard to this software.  
  1629. X * In no event shall the author be liable for any damages whatsoever 
  1630. X * arising out of or in connection with the use or performance of this 
  1631. X * software.  Any use of this software is at the user's own risk.
  1632. X *
  1633. X * If you make modifications to this software that you feel 
  1634. X * increases it usefulness for the rest of the community, please 
  1635. X * email the changes, enhancements, bug fixes as well as any and 
  1636. X * all ideas to me. This software is going to be maintained and 
  1637. X * enhanced as deemed necessary by the community.
  1638. X *              
  1639. X *              Patrick J. Wolfe
  1640. X *              uunet!kailand!pwolfe
  1641. X *              pwolfe@kai.com
  1642. X */
  1643. END_OF_FILE
  1644.   if test 34681 -ne `wc -c <'cdreader.c'`; then
  1645.     echo shar: \"'cdreader.c'\" unpacked with wrong size!
  1646.   fi
  1647.   # end of 'cdreader.c'
  1648. fi
  1649. if test -f 'cdreader.icon' -a "${1}" != "-c" ; then 
  1650.   echo shar: Will not clobber existing file \"'cdreader.icon'\"
  1651. else
  1652.   echo shar: Extracting \"'cdreader.icon'\" \(3086 characters\)
  1653.   sed "s/^X//" >'cdreader.icon' <<'END_OF_FILE'
  1654. X#define cdreader_width 60
  1655. X#define cdreader_height 60
  1656. Xstatic char cdreader_bits[] = {
  1657. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1658. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00,
  1659. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
  1660. X   0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00,
  1661. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
  1662. X   0x1e, 0xc0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf8, 0x7f, 0x00,
  1663. X   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
  1664. X   0xfe, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00,
  1665. X   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
  1666. X   0xfe, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00,
  1667. X   0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
  1668. X   0xfe, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0x00,
  1669. X   0x00, 0x00, 0x00, 0x00, 0xee, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1670. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
  1671. X   0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1672. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
  1673. X   0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1674. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
  1675. X   0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1676. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00,
  1677. X   0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1678. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x0e, 0x00, 0x00, 0x00,
  1679. X   0x00, 0x00, 0xf8, 0x0f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f,
  1680. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x0e, 0x00, 0x00, 0x00,
  1681. X   0x00, 0x00, 0xff, 0x7f, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff,
  1682. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
  1683. X   0x00, 0xc0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff,
  1684. X   0x0f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
  1685. X   0x00, 0xe0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff,
  1686. X   0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00,
  1687. X   0x00, 0x80, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f,
  1688. X   0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x0e, 0x00, 0x00, 0x00,
  1689. X   0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
  1690. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00,
  1691. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1692. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1693. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1694. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1695. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1696. X   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  1697. END_OF_FILE
  1698.   if test 3086 -ne `wc -c <'cdreader.icon'`; then
  1699.     echo shar: \"'cdreader.icon'\" unpacked with wrong size!
  1700.   fi
  1701.   # end of 'cdreader.icon'
  1702. fi
  1703. echo shar: End of archive 1 \(of 1\).
  1704. cp /dev/null ark1isdone
  1705. MISSING=""
  1706. for I in 1 ; do
  1707.     if test ! -f ark${I}isdone ; then
  1708.     MISSING="${MISSING} ${I}"
  1709.     fi
  1710. done
  1711. if test "${MISSING}" = "" ; then
  1712.     echo You have the archive.
  1713.     rm -f ark[1-9]isdone
  1714. else
  1715.     echo You still must unpack the following archives:
  1716.     echo "        " ${MISSING}
  1717. fi
  1718. exit 0
  1719. exit 0 # Just in case...
  1720.