[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference rdvax::grateful

Title:Take my advice, you'd be better off DEAD
Notice:It's just a Box of Rain
Moderator:RDVAX::LEVY::DEBESS
Created:Wed Jan 02 1991
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:580
Total number of notes:60238

72.0. "Software for Tape Lists and Labels" by GR8FUL::WHITE (She sang a little while...) Thu Jan 10 1991 01:56

	Those doggone tape lists are getting out of hand!  Keeping
	track, keeping them up to date - very time consuming.  And
	labeling tapes, jeepers, I'm *months* behind!

	Seems like the perfect job for a computer!  What a brilliant
	idea! :-)

	So who's got the code?  What software do you use to keep up
	with your tape list?  What about automated tape label programs?
	What do you use?

T.RTitleUserPersonal
Name
DateLines
72.111SRUS::MARKWaltzing with BearsTue Jan 15 1991 17:4732
	Here's the LaTeX code I used to label my second NYE tape.  If you don't
have LaTeX on your system, you can find pointers to kits in VAXUUM::TEX.  It
looks a bit arcane, but the output is nice.

Mark
---------------------------------------------------------------------------
\documentstyle{article}
\begin{document}
 
\begin{tabular}{p{1.625in}p{1.625in}}
\multicolumn{2}{c}{\Large New Year's Eve 1990-1991} \\
\multicolumn{2}{c}{Tape 2 - Set II} \\
\multicolumn{2}{c}{\hbox to 3.75in{}} \\
 & \\
{\small\raggedright Side A\\
Not Fade Away$\hookleftarrow$\\
Eyes of the World$\hookleftarrow$\\
Dark Star$\hookleftarrow$\\
Jam$\hookleftarrow$\\
Drumz (abbreviated)
} & {\small\raggedright Side B\\
Olin Agareed${}^1 \hookleftarrow$\\
Jam$\hookleftarrow$\\
The Other One$\hookleftarrow$\\
Wharf Rat$\hookleftarrow$\\
Not Fade Away
} \\
 & \\
\multicolumn{2}{l}{All with Branford Marsallis} \\
\multicolumn{2}{l}{${}^1$ with Hamza al Din} \\
\end{tabular}
\end{document}
72.2Let's Trade tape list programLESPE::WHITEWithout love in a dream...Sun Jan 26 1992 19:4747
        The advertisement reproduced below (within the limits of an ASCII
        character cell display :-) came with my last order of tapes from
        Terrapin Tapes.  It is posted here strictly as an FYI - no
        endorsement, explicit or implicit, is made in this posting.

        That said...

        The author had been discussing this on The WELL.  It seems
        interesting.  I may even scare up the $40 to check it out,
        although I have some doubts about the implied "one tape-one show"
        format.  But I may be mistaken.
        
        Bob

        -----------------------------------------------------------------

                     TIRED OF FILLING OUT ALL OF THOSE
                             CASSETTE LABELS?
                             
                                    GET
                                    
                               LET'S TRADE!
                               
        Let's Trade is a computer program that keeps track of your GD
        tape list for you.  It has every show's set list from 1972-1991.
        It keeps track of useful information about each tape, such as
        generation, quality, source, time and who you got it from.  When
        you get a new tape all you have to do is add the date to your
        tape list and Let's Trade will do the rest.  It prints cassette
        or DAT labels, and a complete listing of all your tapes.  You can
        even serach for songs in your tape list and display or print just
        the tapes with that song.  Let's Trade has a built in address
        book and can print mailing labels.  It also has a built in memo
        pad to help keep track of all your trades.  Let's Trade runs on
        an IBM PC or compatible computer with at least 640K RAM and a
        hard disk.
        
        Send a check or money order for $40 (tax, handling and shipping
        included) to:

                              Terrapin Tapes
                              P.O. Box 1408
                            Greenwich, CT 06836
   For telephone orders call 1-800-677-8650, Visa and Master Card only
            Let's Trade Copyright (c) 1991 by Adam Robucci
                       Distributed by Terrapin Tapes
72.5generic postscript label file ...CUPTAY::BAILEYA pirate looks at 40.Tue Jun 23 1992 16:38281
    For those of you who don't have access to label programs, but do have
    access to a postscript printer, the template below is for generic tape
    labels.
    
    Just extract the reply, and delete everything above the line of
    asterisks.  All the fields you have to fill in are identified with a
    double-asterisk (**).  So all ya have to do is make a copy of the file
    for each set of labels you wanna make, do a search for **, and fill in
    the info it tells ya to.  The file is set up to produce three labels,
    but you can customize it to one or two, as you need to.
    
    If ya have any blank fields, delete the "**label" tag in the field (in
    other words, don't leave anything identified with a ** in the file or
    it will print that way).
    
    I'm sure if ya diddle with it a bit you'll get the idea.
    
    ... Bobbb
    
    ************************************************************************
%!PS
%
% Label for   **band_name
%             **venue
%             **date
%
/inch {72 mul} def
/box
 { 0.1 inch  0.0 inch rlineto
   0.0 inch  0.1 inch rlineto
  -0.1 inch  0.0 inch rlineto
   closepath } def
/outline {
100 100 translate
newpath
0 inch 0 inch moveto
3.94 inch 0 inch lineto
3.94 inch 3.63 inch lineto
0 inch 3.63 inch lineto
closepath
.9 setgray
fill
newpath
0 inch 0 inch moveto
3.94 inch 0 inch lineto
3.94 inch 3.63 inch lineto
0 inch 3.63 inch lineto
closepath
0 setgray
3 setlinewidth
stroke
newpath
0 inch 2.97 inch moveto
3.94 inch 2.97 inch lineto
stroke
newpath
0 inch 2.47 inch moveto
3.94 inch 2.47 inch lineto
stroke
newpath
1.97 inch 2.47 inch moveto
1.97 inch 0 inch lineto
stroke
1 setlinewidth
/Times-Bold findfont 10 scalefont setfont
newpath
0.13 inch 3.20 inch moveto box
stroke
0.26 inch 3.20 inch moveto
(Audience) show
newpath
1.00 inch 3.20 inch moveto box
stroke
1.13 inch 3.20 inch moveto
(Board) show
newpath
1.75 inch 3.20 inch moveto box
stroke
1.88 inch 3.20 inch moveto
(FM) show
2.40 inch 3.20 inch moveto (gen) show
newpath
0.13 inch 3.05 inch moveto box
stroke
0.26 inch 3.05 inch moveto
(Dolby B) show
newpath
1.00 inch 3.05 inch moveto box
stroke
1.13 inch 3.05 inch moveto
(Dolby C) show } def
outline
/Times-Bold findfont 12 scalefont setfont
0.13 inch 3.40 inch moveto
(**band_name        **date      I    ) show
newpath 1.00 inch 3.20 inch moveto box
/Times-Bold findfont 10 scalefont setfont
2.25 inch 3.20 inch moveto
(**gen#) show
newpath 1.00 inch 3.05 inch moveto box
/Times-Bold findfont 10 scalefont setfont
1.75 inch 3.05 inch moveto
(**donor&date           ) show
/Times-Bold findfont 14 scalefont setfont
0.13 inch 2.76 inch moveto
(**band_name                     ) show
3.15 inch 2.76 inch moveto
(**date) show
0.13 inch 2.55 inch moveto
(**venue                         ) show
3.775 inch 2.55 inch moveto (I) show
/Times-Bold findfont 10 scalefont setfont
0.13 inch 2.24 inch moveto
(**song_title) show
0.13 inch 2.04 inch moveto
(**song_title) show
0.13 inch 1.84 inch moveto
(**song_title) show
0.13 inch 1.64 inch moveto
(**song_title) show
0.13 inch 1.44 inch moveto
(**song_title) show
0.13 inch 1.24 inch moveto
(**song_title) show
0.13 inch 1.04 inch moveto
(**song_title) show
0.13 inch 0.84 inch moveto
(**song_title) show
0.13 inch 0.64 inch moveto
(**song_title) show
0.13 inch 0.44 inch moveto
(**song_title) show
/Times-Bold findfont 10 scalefont setfont
2.10 inch 2.24 inch moveto
(**song_title) show
2.10 inch 2.04 inch moveto
(**song_title) show
2.10 inch 1.84 inch moveto
(**song_title) show
2.10 inch 1.64 inch moveto
(**song_title) show
2.10 inch 1.44 inch moveto
(**song_title) show
2.10 inch 1.24 inch moveto
(**song_title) show
2.10 inch 1.04 inch moveto
(**song_title) show
2.10 inch 0.84 inch moveto
(**song_title) show
2.10 inch 0.64 inch moveto
(**song_title) show
2.10 inch 0.44 inch moveto
(**song_title) show
showpage
outline
/Times-Bold findfont 12 scalefont setfont
0.13 inch 3.40 inch moveto
(**band_name        **date     II      ) show
newpath 1.00 inch 3.20 inch moveto box
/Times-Bold findfont 10 scalefont setfont
2.25 inch 3.20 inch moveto
(**gen#) show
newpath 1.00 inch 3.05 inch moveto box
/Times-Bold findfont 10 scalefont setfont
1.75 inch 3.05 inch moveto
(**donor&date           ) show
/Times-Bold findfont 14 scalefont setfont
0.13 inch 2.76 inch moveto
(**band_name                     ) show
3.15 inch 2.76 inch moveto
(**date) show
0.13 inch 2.55 inch moveto
(**venue                         ) show
3.725 inch 2.55 inch moveto (II) show
/Times-Bold findfont 10 scalefont setfont
0.13 inch 2.24 inch moveto
(**song_title) show
0.13 inch 2.04 inch moveto
(**song_title) show
0.13 inch 1.84 inch moveto
(**song_title) show
0.13 inch 1.64 inch moveto
(**song_title) show
0.13 inch 1.44 inch moveto
(**song_title) show
0.13 inch 1.24 inch moveto
(**song_title) show
0.13 inch 1.04 inch moveto
(**song_title) show
0.13 inch 0.84 inch moveto
(**song_title) show
0.13 inch 0.64 inch moveto
(**song_title) show
0.13 inch 0.44 inch moveto
(**song_title) show
/Times-Bold findfont 10 scalefont setfont
2.10 inch 2.24 inch moveto
(**song_title) show
2.10 inch 2.04 inch moveto
(**song_title) show
2.10 inch 1.84 inch moveto
(**song_title) show
2.10 inch 1.64 inch moveto
(**song_title) show
2.10 inch 1.44 inch moveto
(**song_title) show
2.10 inch 1.24 inch moveto
(**song_title) show
2.10 inch 1.04 inch moveto
(**song_title) show
2.10 inch 0.84 inch moveto
(**song_title) show
2.10 inch 0.64 inch moveto
(**song_title) show
2.10 inch 0.44 inch moveto
(**song_title) show
showpage
outline
/Times-Bold findfont 12 scalefont setfont
0.13 inch 3.40 inch moveto
(**band_name        **date     III      ) show
newpath 1.00 inch 3.20 inch moveto box
/Times-Bold findfont 10 scalefont setfont
2.25 inch 3.20 inch moveto
(**gen#) show
newpath 1.00 inch 3.05 inch moveto box
/Times-Bold findfont 10 scalefont setfont
1.75 inch 3.05 inch moveto
(**donor&date           ) show
/Times-Bold findfont 14 scalefont setfont
0.13 inch 2.76 inch moveto
(**band_name                     ) show
3.15 inch 2.76 inch moveto
(**date) show
0.13 inch 2.55 inch moveto
(**venue                         ) show
3.625 inch 2.55 inch moveto (III) show
/Times-Bold findfont 10 scalefont setfont
0.13 inch 2.24 inch moveto
(**song_title) show
0.13 inch 2.04 inch moveto
(**song_title) show
0.13 inch 1.84 inch moveto
(**song_title) show
0.13 inch 1.64 inch moveto
(**song_title) show
0.13 inch 1.44 inch moveto
(**song_title) show
0.13 inch 1.24 inch moveto
(**song_title) show
0.13 inch 1.04 inch moveto
(**song_title) show
0.13 inch 0.84 inch moveto
(**song_title) show
0.13 inch 0.64 inch moveto
(**song_title) show
0.13 inch 0.44 inch moveto
(**song_title) show
/Times-Bold findfont 10 scalefont setfont
2.10 inch 2.24 inch moveto
(**song_title) show
2.10 inch 2.04 inch moveto
(**song_title) show
2.10 inch 1.84 inch moveto
(**song_title) show
2.10 inch 1.64 inch moveto
(**song_title) show
2.10 inch 1.44 inch moveto
(**song_title) show
2.10 inch 1.24 inch moveto
(**song_title) show
2.10 inch 1.04 inch moveto
(**song_title) show
2.10 inch 0.84 inch moveto
(**song_title) show
2.10 inch 0.64 inch moveto
(**song_title) show
2.10 inch 0.44 inch moveto
(**song_title) show
showpage

72.6hey...i've seen that code before! ;-)DEDHED::SpineTom SpineTue Jun 23 1992 18:009
Ha!  That PostScript code sure looks an aweful lot like the code that
my tape label program produces.  Glad ya like the design, Bobbb!

Credit where credit is due department -- the PostScript code and the
tape label design posted by Bobbb was written by me back in '86 or '87
or so.  My inspriation for doing so can be traced to Mystery Hill's code
and design.

tms
72.7DOS label programSSGV02::STROBELIn this style 10/6Tue Jun 23 1992 18:034
I seem to recall in Grateful_Old someone have a DOS based program for labels.
Is that available somewhere?

Jeff_who_should_read_notes_more_often_so_that_he_doesn't_miss_northern_lunches
72.8what goes around, keeps going around ... ;^)CUPTAY::BAILEYA pirate looks at 40.Wed Jun 24 1992 09:266
    Hey now tms ... thanks for the code!  I got it from Probz as a label
    for some Radiators tapes about a year ago.  Been meaning to put it in
    here for a while now.  Hope somebody finds it useful ...
    
    								... Bobbb
    
72.9NRSTA2::CLARKHour of SlackFri Feb 19 1993 11:0485
re            <<< Note 72.7 by SSGV02::STROBEL "In this style 10/6" >>>
>                             -< DOS label program >-
>
>I seem to recall in Grateful_Old someone have a DOS based program for labels.
>Is that available somewhere?

Here's one I just got from a guy in rec.music.gdead ... check out
NRSTA2::USER03:[CLARK.PUBLIC]CASLINR3.ZIP

Here's the readme file that came with it:

                         CaseLinr Version 3.0

                            Ed Adasiewicz
                         764 Old Westbury Rd.
                       Crystal Lake, IL  60012

                      CompuServe ID  71101,2744


CaseLinr is a Windows program which prints case liners (a.k.a. J-Cards) for
audio cassettes.  The image displayed on the CRT screen approximates what
will actually be printed.  The printed result is extremely accurate and can
be cut, folded, and then inserted into an empty (preferably clear plastic)
audio cassette box.

To install CaseLinr, copy the files CASELINR.EXE and CASELINR.HLP to any
directory and then use the New Program Item in the Files menu of the Program
Manager to install CaseLinr within any group.

For help about CaseLinr, read the online help available under the help menu.


CaseLinr Version 3.0 is Shareware. It is NOT FREE SOFTWARE, but it is also
NOT Crippleware.  It is fully functional and does not contain any randomly
appearing oversized dialog boxes with insulting messages, charge card
graphics, and floating buttons.  If you like CaseLinr and find it useful,
you are requested to support it by sending me at least $10.00.  Your donation
will result in you receiving a warm feeling inside knowing that you are not
abusing the shareware concept.  Besides money, I also get a warm feeling
knowing that someone appreciates my work.  All suggestions, comments,
criticisms, and modification requests are welcome -- those accompanied with
donations will be acknowledged.


This program is being made available on an "as is" basis, and carries no
warranties, express or implied.  The author shall in no way be held liable
for any damages resulting from the use of this program or the media on which
it is distributed, including, without limitation, loss of business profits,
interruption of business, loss of information, damage to equipment, or any
other incidental or consequential damages.


Revision History:
----------------

1.0 - Initial release (fixed various bugs in CLFREE).

1.1 - Added the Invert menu option.

1.2 - Added Bisect Side checkbox to global layouts. Changed the Invert menu
      option to Invert Image checkbox in global layouts so that it could be
      saved/reset and written to a cassette file.

2.0 - Insured that the program functioned correctly under Windows 3.0.  The
      Ctrl-Enter key combination must now be used, instead of the Enter key,
      for entering multiple lines in Titles and Songs.  Added an alternate
      icon.  Added system menus to all of the dialog boxes.  Default
      extensions (*.CAS) are now properly displayed in the Open... dialog
      box.  OK in the global layout box only causes scrolling up or down if
      inversion was actually selected or deselected.

2.1 - Centered the liner, both horizintally and vertically, within the page
      specified in Control Panel prior to printing.  Shrunk size of about
      box.  J-card icon now blends in with background color.

3.0 - Started using private profile file (caselinr.ini) rather than win.ini.
      Provided automatic conversion from win.ini to caselinr.ini.  Added
      online help.  Modified file format slightly.  Added Print Setup and
      Reset All Fonts.  Added directory list boxes to Open and Save.  Added
      top and left margins for printing.  Split font handling into two
      dialog boxes and added more options.  Added margins and indents for
      songs.  Added title alignment, margins, and splitting.  Modified
      features so that both the name and value are user settable.  Changed
      a lotta radio buttons to combo boxes.
72.10ZENDIA::FERGUSONI had one of those flashesFri Feb 19 1993 12:212
Jeff, I wrote a program that does tape labels too.  Runs on VMS.  If anyone
wants the executable + direx, send me mail.
72.11SSGV02::GPEACE::Strobelexpecting something witty?Fri Feb 19 1993 13:257
Thanks for the pointers and offers JC & DC. Actually, I've started playing 
around with Microsoft Access to see what type of label maker/db I can come up 
with. It's 90% there but until the developer's kit comes out to make runtime 
applications or unless you have an Access license (still under $100) it won't 
be much use to you.

jeff
72.12DAT label program, VMS weeney can't deal with UNIXCORA::65447::BELKINthe slow one now will later be fastFri Apr 16 1993 15:1292
I've just read the replies in this note.  Does anyone have a tape label program
for DAT tapes?  I do not have a PC at home or in the office, so VMS (is VMS
is VMS is forever) please only!

I've extracted the generic cassette tape label.ps from a few replies back, 
but I don't know enough Postscript-ese to diddle with it.

Also, I've tried looking with the decwrl::ftpmail thing in berkeley.dead.edu 
(?) for tape label programs, but I don't know anything about UNIX to know even 
how to interpret the mail I got back.  I tried to 1) get a directory of
tape label programs, I don't think it went to the right place 2) get a
directory of the readme file ?? 3) copy the readme file, which didn't work 
(no such file or directory?).  Maybe this string should be continued in the
usenet note.

thanks, Josh


From:   US1RMC::"[email protected]"
To:     wedoit::belkin
Subj:   part 001 of ls  (@nemesis.berkeley.edu) [tape-labels] (ascii, last)

total 5
d---------  5 0        daemon        512 Mar 12 07:01 ...old
-rwxr-xr-x  1 0        daemon         36 Feb 16 13:41 .cache
d--x--x--x  2 0        wheel         512 Feb 17 09:43 bin
d--x--x--x  2 0        wheel         512 Jun 12  1989 etc
dr-xr-xr-x  4 ftp      wheel         512 Feb 16 13:41 pub

% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
[headers deleted]
% Reply-To: <[email protected]>



From:   US1RMC::"[email protected]"
To:     wedoit::belkin
Subj:   part 001 of ls  (@gdead.berkeley.edu) [readme] (ascii, last)

total 5
d---------  5 0        daemon        512 Mar 12 07:01 ...old
-rwxr-xr-x  1 0        daemon         36 Feb 16 13:41 .cache
d--x--x--x  2 0        wheel         512 Feb 17 09:43 bin
d--x--x--x  2 0        wheel         512 Jun 12  1989 etc
dr-xr-xr-x  4 ftp      wheel         512 Feb 16 13:41 pub

% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
[headers deleted]
% Reply-To: <[email protected]>



From:   US1RMC::"[email protected]"
to:     wedoit::belkin
Subj:   results of ftpmail request 734724649.14200 [readme]

Orig message-id: <[email protected]>
Orig subject: readme
Orig from: Josh Belkin 13-Apr-1993 1409 <"wedoit::belkin"@cora.ENET.dec.com>
Orig date: Tue, 13 Apr 93 11:10:39 PDT

--- connecting to gdead.berkeley.edu...
Connecting to gdead.berkeley.edu
220 gdead FTP server ready. Complaints and questions should be sent to
             <[email protected]>.
--- logging in as user=anonymous password=-ftpmail/wedoit::belkin account=...
---> USER anonymous
331 Guest login ok, send e-mail address as password.
Begin your password entry with a - (dash) to suppress the helpful messages.
---> PASS <somestring>
230 Guest login ok, access restrictions apply.
---> TYPE A
200 Type set to A.
---> PORT 16,1,240,16,11,144
200 PORT command successful.
---> LIST
150 Opening ASCII mode data connection for /bin/ls.
ls  (@gdead.berkeley.edu) (1 part(s), 304 bytes) sent to wedoit::belkin
226 Transfer complete.
=== getting 'readme'...
---> PORT 16,1,240,16,11,146
200 PORT command successful.
---> RETR readme
550 readme: No such file or directory.
Failure on RETR command
!!! cannot initiate RETR
---> (end of ftpmail session)

% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
[headers deleted]
% Reply-To: <[email protected]>

72.13CSCMA::M_PECKARBe kind: unwindFri Apr 16 1993 15:224
Josh, I've been meaning to poke around that site for a while now. I'll try 
to find something for ya next time I ftp over there. MAy be a while, 
though...
72.14CORA::65447::BELKINthe slow one now will later be fastFri Apr 16 1993 17:173
Thanks, when I sent off the ftpmail it was 3 days before I got mail back.

Josh
72.15SUBPAC::MAGGARDHave YOU changed your logo lately???Wed Apr 21 1993 17:172583
I got this from DAT-Heads ... but then you and the rest of the world
probably did too... ;-)  FWIW, it apparently puts a stealie in the
background...

directions are included.

- jeff

--------------
From:	CRL::"[email protected]" "Digestifier"
        17-APR-1993 01:04:18.90
To:	[email protected]
CC:	
Subj:	DAT-Heads Digest #493

DAT-Heads Digest #493, Volume #1                 Fri, 16 Apr 93 20:30:03 EDT

Contents:
  PostScript label program (Bob Ramstad)

----------------------------------------------------------------------------

From: Bob Ramstad <[email protected]>
Subject: PostScript label program
Reply-To: boccibob%[email protected]
Date: Fri, 16 Apr 93 16:46:31 PDT


Here is a great little PostScript label program.  Anyone want to put
this at an FTP site?  With a pointer in the FAQ?

It's got two modifications I think are important from the source that
Jamie puts out.  1) text on inside flap  2) nice SYF, corrected by
Duane Day from the original inverted and wrong left/right for all
those Dead labels.

Enjoy!

Bob

%!PSAdobe-1
%%Creator: Jamie Zawinski <[email protected]>
%%Title: audio-tape.ps
%%CreationDate: 1-jun-91
%%
%%  PostScript code to generate tape labels, version 1.19.
%%  For audio-cassette, DAT, or 8mm video-cassette labels.
%%  Copyright (c) 1991 Jamie Zawinski <[email protected]>.
%%
%%  Permission granted for non-commercial use and distribution
%%  so long as this notice of copyright remains intact.
%%
%%  This version specially modified by [email protected] to allow
%%  printing of additional information on the inside flap.
%%
%%      All five label formats, as well as all three tape sizes, support
%%  an optional last array.  If you specify this array, you have to preceed
%%  the array with:
%%
%%              /additional-information
%%
%%  The text always appears across the song listings and is oriented 
%%  horizontally.  To orient the additional information the same as the 
%%  songs, set /additional-information-follows-songs to true.
%%
%%      The font name and size are:
%%
%%              /additional-information-font
%%              /additional-information-font-height
%%
%%  and their default values are:
%%
%%              Helvetica
%%              8 points
%%
%%  The additional information font is scaled to fit the flap if the 
%%  information is too large.  
%%
%%EndComments

%%BeginDocumentation
%%
%% There are a few examples at the end of this file; print this for a
%% representative selection of what this code can do.  Search for the
%% string "example" to see how to do it.
%%
%% If you are using this code, send me mail, and I will send you updates
%% as I improve it.

%% And remember: PostScript programs don't senslessly destroy trees.
%% People senslessly destroy trees.  Print your labels on the backs of
%% used sheets of paper, and preview your labels with an on-screen PS
%% previewer such as GhostScript.

%% =========================================================================
%%                             HOW TO USE THIS
%% =========================================================================
%%
%% To print a tape label, you construct a call to one of several PostScript
%% procedures defined in this file.  The calling syntax is fairly simple,
%% and you don't need to know PostScript to do it.  Just fill in the blanks.
%%
%% For a tape label with one album on each side, both albums by the same band,
%% do this:
%%
%%       (Band Name) (Album 1 Name) (Album 1 Date)
%%                   (Album 2 Name) (Album 2 Date)
%%        [ <...album 1 songs....> ] [ <...album 2 songs....> ]
%%        two-albums
%%
%% For a tape label with one album on each side, both albums by different
%% bands, do this:
%%
%%       (Band 1 Name) (Album 1 Name) (Album 1 Date)
%%          [ <...album 1 songs....> ]
%%        (Band 2 Name) (Album 2 Name) (Album 2 Date)
%%          [ <...album 2 songs....> ]
%%        two-bands
%%
%% For a tape label with one double album consuming both sides, do this:
%%
%%       (Band Name) (Album Name) (Album Date)
%%          [ <...songs, side 1....> ]
%%          [ <...songs, side 2....> ]
%%        double-album
%%
%% For a tape label with three or four albums/EPs by the same band, do this:
%%
%%       (Band Name) (Album 1.1 Name) (Album 1.2 Name) (Album 1.* Date)
%%                   (Album 2.1 Name) (Album 2.2 Name) (Album 2.* Date)
%%          [ <...songs, side 1....> ]
%%          [ <...songs, side 2....> ]
%%        N-albums
%%
%% (Either of the strings (Album 1.2 Name) or (Album 1.2 Name) may be
%% an empty string; things will be positioned appropriately.)
%%
%% For a tape label with three or four albums/EPs by two different bands,
%% do this:
%%
%%       (Band 1 Name) (Album 1.1 Name) (Album 1.2 Name) (Album 1.* Date)
%%          [ <...songs, side 1...> ]
%%       (Band 2 Name) (Album 2.1 Name) (Album 2.2 Name) (Album 2.* Date)
%%          [ <...songs, side 2...> ]
%%        two-bands-N-albums
%%
%%
%% In the above examples, [ <songs> ] should really be of the form
%%
%%   [ (song 1) ... (song N) ]          that is, an array of strings; or it
%%                                      may also be of the form
%%
%%   [[ (song 1)  (song 1 time) ]       that is, an array of arrays, where
%%    [ (song 2)  (song 2 time) ]       each sub-array holds exactly two
%%     ...                              strings.  The first string is the name
%%    [ (song N)  (song N time) ]]      of a song, and the second string is
%%                                      the start-time, length, counter, or
%% whatever of the song.  The song name is printed flushleft, and the song
%% time is printed flushright.
%%
%% An entry in the song array may also be of the form
%%    [ (song N)  (song N time) ...font... ]
%% where ...font... is one of /B, /I, /BI, or /Title.  This is explained a
%% little later.

%% =========================================================================
%%                            WHAT YOU WILL GET
%% =========================================================================
%%
%% The labels are printed two-per-page.  You do not need to insert "showpage"s
%% in this file; that happens automagically.
%%
%% The band-names and album-names are printed on the spine of the label.
%% For the one-band-on-both-sides cases, the band-name is printed tall enough
%% to fill the label.  For the two-band cases, the band names are printed one
%% atop the other.  Album names are scaled so that all album names fit on
%% one atop the other on the spine.
%%
%% In all cases (spine, song lists, etc) it is not possible for a string to
%% be "too long" - font-widths are scaled so that the strings fit in the
%% available space (taking into account adjascent strings of the same height;
%% strings stacked above/next to each other are scaled as a unit.  You'll
%% see what I mean.)
%%
%% Songs are printed in one or two columns on the back of the tape label, or
%% on the inside of the tape label (user-configurable).  The name of the album
%% is printed above the song lists.  When there are more than two albums on a
%% tape, the names of all three or four albums are printed on the spine, and
%% the names of albums 1.1 and 2.1 are printed above the song listings on the
%% inside.
%%
%% Labels for DATs and 8mm tapes look the same, except that they are smaller
%% (of course...)
%%
%% It is possible to specify the font of individual lines in the song listings
%% by placing a font-keyword in the third position of an element of the 
%% song-list array.  Valid face-specifiers are /B (bold), /I (italic), /BI
%% (bold italic), and /Title.  If the font is unspecified, /B, /I, or /BI,
%% then the font used for the song name is determined by one of the variables
%% /song-font, /song-font-bold, /song-font-italic, or /song-font-bold-italic.
%% The font will always be scaled to be /song-font-height points tall.
%%
%% If, however, the font is specified as /Title, then the font used will be
%% the value of /title-font, and it will be /title-font-height tall; it will
%% also be underlined.  The intent here is that specifying the font as /Title
%% makes an entry in the song listings look just like the album titles above
%% the listings.  That way, if you have more than one album on the same side
%% of a tape, you can display a title for both of them, which was not possible
%% in versions prior to 1.5.  (Extra hack: [(song) /Title] is considered to
%% be the same as [(song) () /Title], since the time is ignored for titles.)
%%
%% It is possible to include arbitrary graphics in place of the band-name
%% on the spine, to duplicate the way a band normally renders its name, or
%% whatever.  It is also (as of v1.4) possible to include an arbitrary
%% graphic on the inside flap, or printed (lightly) under the song listings.
%% See below.
%%
%% If you want a Dolby logo printed, simply include a line containing only the
%% word "DolbyB" or "DolbyC" (no quotes) before the band name(s).  You must do
%% this before each tape to get this logo; it is reset after printing each
%% label.  "dbx", "AAD", "ADD", and "DDD" print the appropriate logo as well.
%% These logos go in the corner of the short back flap (where the signature
%% string goes) because I couldn't think of a better place.  Feel free to
%% suggest one.
%%
%% =========================================================================
%%                        HOW TO USE THIS UNDER UNIX
%% =========================================================================
%%
%% Of course, it's possible to just edit this file and print it each time you
%% want to print a label, but that's kind of a pain.  And you don't want a
%% copy of this file sitting around for every tape label you print, it's too
%% big.  This is the solution that I use:
%%
%%   When you edit a new tape label, put it in its own file.  Include in that
%%   file only what the "How to Use This" section had you type in.
%%
%%   Add the following to your .cshrc file:
%%
%%       alias tape_prolog awk '/^%.PS/,/^%%BeginDoc//^%%EndDoc/,/^%%EndPro/'
%%       alias tape_trailer awk '/^%%Trailer/,/^--eof--\$/'
%%       setenv TAPEPS ~/ps/audio-tape.ps
%%       alias catapes '(tape_prolog $TAPEPS;cat \!*; tape_trailer $TAPEPS)'
%%       alias printapes '(catapes \!*) | lpr'
%%
%%   'tape_prolog' and 'tape_trailer' are 'awk' programs that will extract
%%   the important part of this file.  TAPEPS is a variable that points at 
%%   the place your copy of the file is.  'catapes' takes one or more files 
%%   as arguments, and splices their contents in with the PostScript code at
%%   the appropriate place.  
%%
%%   With the above aliases, the command "printapes tape1 tape2 tape3" will
%%   concatentate the PostScript code defined in this file, the definitions
%%   of your labels (which presumably are the contents of the files "tape1,"
%%   "tape2," and "tape3"), and the necessary trailer together, and hand that
%%   as input to "lpr" (or whatever command it is that you use for printing).
%%
%% I also have some Common Lisp code which maintains a database of tapes, and
%% can generate this PostScript code directly.  It uses a simple textual file
%% format for storing the song listings; if you want it, send me mail.  If
%% you use TI Explorer Lisp Machines, I have a totally whizzy menu-driven 
%% interface to editing, searching, and printing these labels. Again, just ask.

%% =========================================================================
%%                           SIMPLE CUSTOMIZATION
%% =========================================================================
%%
%% To print labels for Digital Audio Tapes instead of normal cassette tapes,
%% insert a line consisting of
%%        DAT-sizes
%% in the file before the labels.  To switch back to cassette sizes, include
%% a line that says "cassette-sizes" instead of "DAT-sizes" (the default is
%% to produce labels for normal cassettes.)
%%
%% To print labels for 8mm video cassettes, include a line that says
%% (predictably enough) "8mm-sizes".
%%
%% To change the fonts of various things, change the values of the variables
%% /song-font, /band-font, /album-font, /inner-album-font, or /date-font.
%% It is not possible to change the height or aspect ratio of the fonts, as
%% those are computed at runtime.
%%
%% If you prefer the labels to be printed in such a way that the song listings
%% will appear on the inside of the tape box instead of the outside, set the
%% variable /songs-go-inside to true.  It defaults to false.
%%
%% If you prefer the labels to be printed so that a band's graphic goes on the
%% inside of the tape box instead of the outside, set /icons-go-inside to
%% true.  It defaults to false.
%%
%% If you prefer to have the spine of the label wrong-side-up, set /flip-spine
%% to true.  It defaults to false.  If you prefer to have the song listings
%% wrong-side-up, set /flip-songs to true.  It defaults to false.
%%
%% If you want the columns to follow the long edge of the tape rather than
%% the short edge, set /columns-horizontally to true.  You can change the
%% orientation with /flip-songs.
%%
%% If you want the song-listings to be printed in one column instead of two,
%% then set /one-column to true.  The side1 songs and side2 songs will be
%% appended together and printed in one column down the middle.  This is
%% most useful in conjunction with /columns-horizontally.
%%
%% If /songs-go-inside and /icons-go-inside have the same value (both inside
%% or both outside) then the songs will be printed overlaying the icon.  The
%% icon will be printed at 20% intensity so that you can still read the songs
%% on top of dark areas.  This is customizable by changing the variable 
%% /icon-fade-factor.
%%
%% One problem I encountered with this code was that my co-worker's tapes all
%% looked just like mine...  I got around this by adding the parameter
%% /signature - set this to a string of your name or something, and it will
%% be printed on the back-spine of all of your labels.  It can be multiple
%% lines by specifying it as [ (line 1) (line 2) ... ] instead of as a string.
%% (Embedding newlines in a string will not do what you want.)

%% =========================================================================
%%                       SOPHISTICATED CUSTOMIZATION
%% =========================================================================
%%
%% Defining a new magic-name-printer is pretty simple.  Just define a
%% procedure for drawing the name, and index it in "magic-name-dict" under
%% the string which is the band's name.  There are some fairly sophisticated
%% examples of this in this file.  If you define any more, send them to me
%% and I'll include them in the next distribution (whether I like the band
%% or not :-)).
%%
%% Adding an icon-printer is similar - you use "magic-icon-dict" instead of
%% "magic-name-dict".  For magic-names, define the procedures to draw in
%% a device-scale (1 unit = 1 point) space with origin at the upper left.
%% For icons, define the procedure to be in a one-unit tall space - 1 unit
%% will correspond to the entire height of the flap on which the icon is
%% drawn.  For icons, the origin is at the XY center instead of the upper
%% left.  This is all kind of arbitrary, but it doesn't matter too much,
%% because the beauty of PostScript is that you can scale/translate within
%% your procedure to work in the space that is most convenient to you.
%%
%% When you add something to magic-name-dict or magic-icon-dict, be sure to
%% use "CIput" instead of "put" to insure case-insensitivity.
%%
%% If you associate an icon printer with the name (default-icon-printer), then
%% this will be used for bands which do not have their own icons defined.  
%%
%% When /songs-go-inside and /icons-go-inside have the same value, meaning 
%% that the songs will be printed overlaying the icon, we cause the icon to
%% be printed at quarter-intensity by changing the transfer function.  If
%% your icon is written in such a way that this is not desirable, it's
%% possible to defeat it within a given icon printer by doing something 
%% like "{} settransfer" within the scope of a "gsave".
%%
%% Note that magic-name and magic-icon printers are not used unless the label
%% being printed is a double album, or the albums on both sides are by the
%% same band.

%% =========================================================================
%%                                 WISHLIST
%% =========================================================================
%%
%%  o  Maybe the magic-name printers should be invoked even if both sides of
%%     the tape are not by the same band.
%% 
%%  o  The magic-icon-printers should be used even if there are two different
%%     bands on one tape - print two of them side by side if necessary.
%%
%%  o  Maybe there should be a way to print arbitrary text on the inside flap,
%%     aside from defining a magic-icon printer.
%%
%%  o  A general font-change mechanism would be nice, for font changes in the
%%     signature as well as in the song listings.
%%
%%  o  Should have /3-bands-N-albums and /4-bands-N-albums commands.

%% =========================================================================
%%             WHAT THE CURRENTLY DEFINED MAGIC-NAME-PRINTERS DO
%% =========================================================================
%% 
%% o  Siouxsie and the Banshees is printed in an alternating sized, alternating
%%    cased font, with the "and" over the "the" like on many early albums.
%% o  Cabaret Voltaire is printed in a font that looks like the one on the
%%    cover of "Micro-Phonies."
%% o  New Order is printed with a black "New" overlapping a hollow "Order" as
%%    on "Low Life" etc.
%% o  OMD is printed on two lines, one font thicker than the other.  The OE is
%%    printed with an OE character.
%% o  Front 242 is printed similarly.
%% o  Love and Rockets has an icon - a heart on a rocket in a circle.
%% o  Bauhaus has an icon - the Beggars' Banquet "face-in-circle" logo.
%% o  Nitzer Ebb has three icons:
%%    o  If the album name is "That Total Age", the gear/star/hammer logo is
%%       printed.
%%    o  If the album name is "Belief", a low-resolution bitmap of the angry
%%       looking eye from the cover of that album is printed.  This is a fair
%%       example of how to incorperate such bitmaps, and it doesn't take up
%%       that much space, either.
%%    o  Otherwise, the star-over-gear icon from the Warsaw Ghetto EP is used.
%% o  Nine Inch Nails has an icon - "NIN" in a box with the first N backwards.
%% o  Kate Bush has an icon.
%% o  Depeche Mode has a "some great reward"-like icon.
%%
%% Please send me more!

%% =========================================================================
%%                                CHANGELOG
%% =========================================================================
%% some time in 1988... created by Jamie Zawinski.
%% some time in 1990... posted v1.1 to comp.lang.postscript
%% 30 may 90    Jamie Zawinski
%%      fixed a bug which made it impossible to have the band-name and
%%      album-name in different fonts for double-albums.
%% 27 jul 90    Jamie Zawinski
%%      fixed the above fix.
%% 28 jul 90    Jamie Zawinski
%%      Modified the magic-name printers to work around a bug in version 1.1
%%      of Adrian Aylward's Amiga postscript interpreter (post).  In that
%%      implementation, 'get' doesn't work on dictionaries whose keys are
%%      string instead of names; so I added some calls to 'cvn' before 
%%      storing into 'magic-name-dict'.
%%  6 aug 90    Jamie Zawinski
%%      Implemented magic-icons for arbitrary graphics on the back.
%%      Improved auto-scaling a great deal.
%%  9 aug 90    Jamie Zawinski
%%      Made songs able to be strings as well as [()()], and made the signature
%%      able to be multiple lines.  Made sig able to be in a different font
%%      than the song listings.  Made magic-name and magic-icon lookups happen
%%      case-insensitively.
%%  17 oct 90   Jamie Zawinski
%%      Made it possible to change the fonts of individual song listings, and
%%      have album-titles embedded in the middle of the song listings.  Fixed
%%      the auto-scaling of v1.5 to produce the exact same output as v1.4
%%      except where v1.5 does better.
%%  22 oct 90  Jamie Zawinski
%%     Made the fonts for /Title-type song listings be autscaled along with
%%     the titles at the top of the listing instead of with the songs 
%%     themselves.  (That is, long inline titles don't squash the song names,
%%     but they do squash the album names.)  Also, /song-time-font was not
%%     being used.
%%  15 dec 90  Jamie Zawinski
%%     Added support for Digital Audio Tapes.
%%  20 dec 90  Jamie Zawinski
%%     Made dates auto-scale (for when they are used as footnotes).  Fixed a
%%     bug that made auto-scaling not work for inner-album-titles.  Tweaked
%%     sizes of DATs; made DATs fit 3-per-page.  Added default-icon-printer.
%%     Added /flip-songs.  Added /one-column and /columns-horizontally.  Made
%%     the song-lists autoscale heightwise, for when there are too many songs.
%%     This doesn't completely work, and made the code much uglier...
%%  16 jan 90  Jamie Zawinski
%%     Fixed a translation bug with songs inside and sideways columns.  Took
%%     out the code that scales the height of the song font since it didn't
%%     really work.  Adjusted the vertical placement of strings on the spine
%%     when there is only one string (as in double-albums).
%%  22 feb 91  Jamie Zawinski
%%     Tested and fixed all permutations of the orientation variables.
%%     Made the song-lists autoscale heightwise, for when there are too many
%%     songs.  And it works this time.
%%  25 feb 91  Jamie Zawinski
%%     Spliced in Michael Brown's dolby-logo code -- thanks Michael.
%%     Fixed spurious comma when one-column and no dates.
%%  27 feb 91  Jamie Zawinski
%%     Made icon orientations track song list orientations.  Added logos for
%%     DDD, AAD, dbx, etc.
%%   6 mar 91  Jamie Zawinski
%%     posted to comp.lang.postscript
%%  14 mar 91  Jamie Zawinski
%%     Added code to print 8mm video cassette labels, from Allen Wade.
%%   3 apr 91  Jamie Zawinski
%%     Put it in its own dictionary instead of userdict.
%%  11 jun 91  Jamie Zawinski (who else?)
%%     Fixed a bug which caused inner-title width computations to have state
%%     beyond the current label (very bad...)
%% =========================================================================

%% Questions?  Comments?  Suggestions?  Improvements?  Send them to me,
%% [email protected].  "Please, no applause, just throw money."
%%
%%EndDocumentation

/TapeDict 500 dict def TapeDict begin

/bdef { bind readonly def } bind readonly def

/box {
  4 2 roll
  newpath moveto
    exch dup 0 rlineto
    exch 0 exch neg rlineto
    neg 0 rlineto
  closepath
} bdef

/rightshow
 {dup stringwidth pop
  neg 0 rmoveto
  show } bdef

/centershow
 {dup stringwidth pop
  2 div neg 0 rmoveto
  show } bdef

/max {
  dup 3 -1 roll dup
  3 -1 roll gt
  { exch pop } { pop } ifelse
  } bdef

/max-stringwidth {
  stringwidth pop
  exch stringwidth pop
  max
  } bdef

%% Default font-names and sizes.  The widths (and sometimes heights) are 
%% stomped at runtime, but the names are the responsibility of the user.
%%
/song-font /Helvetica def
/song-font-bold /Helvetica-Bold def
/song-font-italic /Helvetica-Oblique def
/song-font-bold-italic /Helvetica-BoldOblique def
/song-time-font song-font def
/song-font-height 8 def

/signature-font /Helvetica def
/signature-font-height 8 def

/band-font /Helvetica def
/band-font-height 13 def

/album-font /Helvetica def
/album-font-height 13 def

/inner-album-font /Helvetica-Bold def
/inner-album-font-height 13 def

/date-font /Helvetica-Bold def
/date-font-height 8 def

/additional-information-font /Helvetica def
/additional-information-font-height 8 def

% if true, songs go inside the tape label, else outside.
/songs-go-inside false def

% if true, icons go inside the tape label, else outside.
/icons-go-inside false def

% If true, the spine will be printed with a nasty orientation.
/flip-spine false def

% If true, the song-listings will be printed other-side-up.
/flip-songs false def

% If true, the song-listings will be in one column instead of two.
/one-column false def

% If true, the song-listings will be horizontal instead of vertical.
/columns-horizontally false def

% if an icon and the song listings are being printed on the same flap, the
% icon will be faded by this amount (so that the songs will be readable).
%
/icon-fade-factor 0.20 def

/cassette-sizes {
  /margins 4 def
  /back-spine-height 40 def
  /spine-height 32 def
  /list-height 185 def
  /total-height margins back-spine-height add
                margins spine-height add add
                margins list-height add  2 mul add
                margins add
                def
  /inner-width 280 def
  /total-width inner-width margins dup add add def
  % if there are DATs or 8mms on the page already, force a page-break.
  DATp 8mmp or tick 0 ne and { showpage /tick 0 def } if
  /DATp false def
  /8mmp false def
} bdef

/DAT-sizes {
  % Length: 3 1/6 inches     - 228.95
  % Width: 2 7/8 in          - 209.86
  % Folds:
  % 7/16 in from bottom      - 31.63
  % 15/16 in from the bottom - 67.78
  /margins 3 def
  /back-spine-height 27 def
  /spine-height 33 def
  /list-height 156 2 sub def
  /total-height margins back-spine-height add
                margins spine-height add add
                margins list-height add  2 mul add
                margins add
                def
  /inner-width 202 4 sub def
  /total-width inner-width margins dup add add def
  % if there are normal cassette tapes on the page already, force a page-break.
  DATp not tick 0 ne and { showpage /tick 0 def } if
  /DATp true def
  /8mmp false def
} bdef

/8mm-sizes {   % by Allen Wade, 13 mar 91
  % Length: 3 5/8 inches     - 250
  % Width:  3 11/16 inches   - 279.86
  % Folds:
  % 1/2 in from bottom       - 32.63
  % 1 1/8 in from the bottom - 77.78
  /margins 4 def
  /back-spine-height 34 def
  /spine-height 40 def
  /list-height 175 def
  /total-height margins back-spine-height add
                margins spine-height add add
                margins list-height add  2 mul add
                margins add
                def
  /inner-width 260 def
  /total-width inner-width margins dup add add def
  % if there are normal cassette tapes on the page already, force a page-break.
  8mmp not tick 0 ne and { showpage /tick 0 def } if
  /8mmp true def
  /DATp false def
} bdef


/tick 0 def             % How many tapes have been dumped on this page.
/DATp false def         % don't change this.
/8mmp false def         % don't change this.
/really-big false def   % don't change this.
cassette-sizes

/extract-song-and-time-and-font-1 {
  dup type /stringtype eq
  { () /R }
  { dup length
    dup 0 eq
    { pop pop () () /R }
    { dup 1 eq
      { 0 get () /R }
      { 2 eq
        { dup 0 get exch 1 get /R }
        { dup 0 get exch dup 1 get exch 2 get }
        ifelse
      } ifelse
    } ifelse
  } ifelse
  % if the time is /Title or /title, set the font to
  % be the same.
  exch dup dup
  /Title eq
  exch
  /title eq
  or
    { pop pop /Title dup } if
  exch
} bdef

/extract-song-and-time-and-font {  % takes a song spec and leaves three things
                                   % on the stack - (song) (time) <font>.
  extract-song-and-time-and-font-1
  decode-song-font-name
} bdef

/song-fonts-w-scale 1 def
/song-fonts-h-scale 1 def
/song-fonts-title-w-scale 1 def

/decode-song-font-name {   % takes a name, one of /R, /B, /I, /BI, or /Title
                           % and converts that to a font scaled appropriately.
                           % Leaves the font on the stack.
    
  song-font-height exch % put the height on the stack under the name.

  /titlep false def % set the Hack flag...

  % convert the name to a font-name.
  dup /B eq
  { pop song-font-bold }
  { dup /I eq
    { pop song-font-italic }
    { dup /BI eq
      { pop song-font-bold-italic }
       { dup /Title eq
         exch /title eq or
         % if the code was /Title or /title, take the default height off the
         % stack and put the title-font-height there instead.
         { pop inner-album-font-height
           inner-album-font 
           /titlep true def  % hack hack...
         }
         { song-font }
         ifelse
       } ifelse
    } ifelse
  } ifelse

  % set FH to the font height, leaving the font-name.
  exch /FH exch def
  % then find and scale the font, leaving it on the stack.
  findfont
  [ FH titlep {song-fonts-title-w-scale} {song-fonts-w-scale} ifelse mul
    0 0
    titlep { FH } { FH song-fonts-h-scale mul } ifelse
    0 0 ] makefont
} bdef

/compute-max-colheight {
  songs1 compute-max-colheight-1
  songs1 compute-max-colheight-1
  max
} bdef

/compute-max-colheight-1 {
  /total 0 def
  { extract-song-and-time-and-font-1
    exch pop exch pop
    /Title eq
    { /total total inner-album-font-height add 5 add def }
    { /total total song-font-height add 2 add def }
    ifelse
  } forall
  total
} bdef

% songs1 length songs2 length max
%        song-font-height song-fonts-h-scale mul 2 add mul

/print-one-column {                    % write one column of the song listings
  /songs exch def
  /h exch def /w exch def
  /y exch def /x exch def
  gsave
    /w w 10 sub def
    /x x 5 add def
    one-column double-album-p not and not
      { /y y inner-album-font-height sub def } if
    x y translate
%    -5 0 w h box clip newpath
%    -5 0 w h box stroke %debug
    /x 0 def
    /x2 x w add 5 sub def
    /y song-font-height neg def

    /maxh compute-max-colheight def
    maxh h y sub gt
    { 1 h y sub maxh div scale } if

    songs { extract-song-and-time-and-font
            setfont
            dup /Title eq
            { /y y inner-album-font-height song-font-height sub sub def
              pop x 5 sub y moveto
              show
              0 -2 rmoveto
              x 5 sub y 2 sub lineto stroke   % underline it
              /y y
                inner-album-font-height song-font-height sub
                2 sub sub def           % frob y.
            }
            { exch
              x y moveto
              show
              dup () ne {
                  song-time-font findfont
                  [ song-fonts-w-scale song-font-height mul 0 0
                    song-fonts-h-scale song-font-height mul 0 0 ]
                  makefont setfont
                  x2 y moveto
                  rightshow }
              { pop }
              ifelse
            }
            ifelse
            /y y song-font-height song-fonts-h-scale mul sub 1 sub def
          } forall
  grestore
 } bdef


/print-songs {                 % write a column of the song listings; 0=right.
  /left exch def
  gsave
    /x one-column { inner-width 20 sub max-songwidth sub 2 div 5 add }
                  { 10 } ifelse def
    /y  back-spine-height spine-height add
        margins 3 mul  add
        neg  def
    /w  one-column { max-songwidth 20 add } { inner-width 2 div } ifelse def
    /h  list-height
        one-column double-album-p not and not
          { inner-album-font-height sub } if
        () date1 eq () date2 eq and not { date-font-height sub } if
        margins 2 mul sub def

    songs-go-inside
    { flip-songs
      { /y y list-height margins add add def }
      { /y y list-height margins add sub def }
      ifelse }
    if

    1 left eq
      { /songs songs1 def }
      { /x x w add def 
        /songs songs2 def }
    ifelse

    x y w h songs print-one-column
  grestore
 } bdef

/draw-icon {
  gsave
    total-width 2 div
    icons-go-inside
     { total-height list-height 2 div margins add sub neg }
     { total-height list-height 1.5 mul margins dup add add sub neg }
    ifelse
    translate
    list-height dup scale
    columns-horizontally { -90 rotate } if
    flip-songs { 180 rotate } if

    icons-go-inside songs-go-inside and
    icons-go-inside not songs-go-inside not and or
      { { 1 exch sub icon-fade-factor mul 1 exch sub } settransfer
          0 setgray } % ..to work around bug in GhostScript 2.0's settransfer.
    if
    magic-icon
  grestore
  } bdef

/set-songfont {     % compute width-scale of fonts for song listings.
  /tfont song-time-font findfont song-font-height scalefont def
  /maxw 0 def
  /song-fonts-w-scale 1 def   % set to 1 for width computation.
  songs1 { extract-song-and-time-and-font
           setfont
           dup /Title eq
            { pop pop () 0 }
            { stringwidth pop }  %% oops, this isn't taking into account
           ifelse                %% the /song-time-font.
           exch stringwidth pop
           add
           maxw max
           /maxw exch def
         } forall
  songs2 { extract-song-and-time-and-font
           setfont
           dup /Title eq
            { pop pop () 0 }
            { stringwidth pop }
           ifelse
           exch stringwidth pop
           add
           maxw max
           /maxw exch def
         } forall
  /w  one-column
      { inner-width 20 sub }
      { inner-width 2 div 5 sub } ifelse
      def 
  /max-songwidth maxw 20 add def
  max-songwidth w gt
    { /song-fonts-w-scale w max-songwidth div def
      /max-songwidth w def }
  if

  one-column double-album-p not and
  { /Imaxw inline-album-titles-max-stringwidth def
    /song-fonts-title-w-scale
      Imaxw max-songwidth gt { max-songwidth Imaxw div } { 1 } ifelse
      def
  } if
  } bdef


/inline-album-titles-max-stringwidth {
  /Imaxw 0 def
  /Imaxh 0 def
  /ofsws song-fonts-w-scale def
  /ofshs song-fonts-h-scale def
  /song-fonts-w-scale 1 def   % set to 1 for width computation.
  songs1 { extract-song-and-time-and-font
           setfont
           /Title eq
            { stringwidth pop Imaxw max /Imaxw exch def
              /Imaxh Imaxh inner-album-font-height add 4 add def }
            { pop }
           ifelse } forall
  songs2 { extract-song-and-time-and-font
           setfont
           /Title eq
            { stringwidth pop Imaxw max /Imaxw exch def
              /Imaxh Imaxh inner-album-font-height add 4 add def }
            { pop }
           ifelse } forall
  /song-fonts-w-scale ofsws def
  /song-fonts-h-scale ofshs def
  Imaxw
} bdef


/print-two-inner-album-titles {   % write album titles above the song listings
  gsave
    /x 10 def
    /y  back-spine-height spine-height add
        margins 3 mul  add
        neg  def
    /w  inner-width 2 div 10 sub def
    /x2 w 20 add def

    one-column { /w2 w def } if

    songs-go-inside
    { flip-songs
      { /y y list-height margins add add def }
      { /y y list-height margins add sub def }
      ifelse }
    if

    /font  inner-album-font findfont inner-album-font-height scalefont  def
    font setfont
    /maxw albumname1 albumname2 max-stringwidth def
    /maxw maxw inline-album-titles-max-stringwidth max def

    /song-fonts-title-w-scale
      maxw w gt { w maxw div } { 1 } ifelse
    def
    font [ song-fonts-title-w-scale 0 0 1 0 0 ] makefont setfont

    gsave
      x y w inner-album-font-height 1.5 add box clip newpath
      x  y inner-album-font-height sub 2 add  moveto
      albumname1 show
      0 -2 rmoveto
      x  y inner-album-font-height sub  lineto stroke        % underline it.
    grestore
    gsave
      x2 y w inner-album-font-height 1.5 add box clip newpath
      x2 y inner-album-font-height sub 2 add  moveto
      albumname2 show
      0 -2 rmoveto
      x  y inner-album-font-height sub  lineto stroke        % underline it.
    grestore
  grestore
 } bdef


/print-one-inner-album-title {  % write album title centered above songs.
  gsave
    /x 10 def
    /y  back-spine-height spine-height add
        margins 3 mul  add
        neg  def
    /w  inner-width x sub def
    /w2 inner-width 2 div x sub def

    one-column { /w2 w def } if

    songs-go-inside
    { flip-songs
      { /y y list-height margins add add def }
      { /y y list-height margins add sub def }
      ifelse }
    if

    /font inner-album-font findfont inner-album-font-height scalefont def
    font setfont
    /maxw albumname1 stringwidth pop def
    /innerw inline-album-titles-max-stringwidth def
    /maxw maxw innerw max def

    /w3 innerw 0 eq { w } { w2 } ifelse def
    /song-fonts-title-w-scale
      maxw w3 gt
      { w3 maxw div } { 1 } ifelse
    def
    font [ song-fonts-title-w-scale 0 0 1 0 0 ] makefont setfont

    gsave
      x y w inner-album-font-height 1.5 add box clip newpath
      x w 2 div add  y inner-album-font-height sub 2 add  moveto
      albumname1 centershow
      newpath 
      x  y inner-album-font-height sub  moveto
%      w 10 sub 0 rlineto stroke
      w 0 rlineto stroke
    grestore
  grestore
 } bdef


/print-inner-album-titles {
  double-album-p
  { print-one-inner-album-title }
  { print-two-inner-album-titles }
  ifelse
} bdef


/print-one-date {       % write a date centered below the song listings
  gsave
    /x 10 def
    /y  back-spine-height spine-height add
        list-height  add
        margins 2 mul  add
        inner-album-font-height sub
        neg  def
    /w  inner-width x sub def

    songs-go-inside
    { flip-songs
      { /y y list-height margins add add def }
      { /y y list-height margins add sub def }
      ifelse }
    if

    date-font findfont date-font-height scalefont setfont
    x y w inner-album-font-height 1.5 add box clip newpath
    x w 2 div add  y inner-album-font-height sub 2 add  moveto
    /datew date1 stringwidth pop def
    datew w gt { currentfont [ w datew div 0 0 1 0 0 ] makefont setfont } if
    date1 centershow
  grestore
 } bdef


/print-two-dates {              % write the dates below the song listings
  gsave
    /x 25 def
    /y  back-spine-height spine-height add
        list-height add
        margins 2 mul  add
        inner-album-font-height sub
        neg  def
    /w  inner-width 2 div def
    /x2 w x add def

    songs-go-inside
    { flip-songs
      { /y y list-height margins add add def }
      { /y y list-height margins add sub def }
      ifelse }
    if

    date-font findfont date-font-height scalefont setfont
    /datew date1 date2 max-stringwidth def
    gsave
      x y w inner-album-font-height box clip newpath
      x  y inner-album-font-height sub 2 add  moveto
      datew w x sub gt
        { currentfont [ w x sub datew div 0 0 1 0 0 ] makefont setfont } if
      date1 show
    grestore
    gsave
      x2 y w inner-album-font-height box clip newpath
      x2  y inner-album-font-height sub 2 add  moveto
      datew w x sub gt
        { currentfont [ w x sub datew div 0 0 1 0 0 ] makefont setfont } if
      date2 show
    grestore
  grestore
 } bdef

/print-dates {
  one-column double-album-p not and
  { () date1 eq
    { /date1 date2 def
      /date2 () def }
    { () date2 eq not
      {
        /l1 date1 length def
        /l2 date2 length def
        /s l1 l2 add 2 add string def
        0 1 l1 1 sub { s exch dup date1 exch get put } for
        s l1 (,) 0 get put
        s l1 1 add ( ) 0 get put
        0 1 l2 1 sub { s exch dup date2 exch get exch l1 2 add add exch put }
          for
        /date1 s def
        /date2 () def
      } if
    } ifelse
  } if
  double-album-p one-column or
  { print-one-date }
  { print-two-dates }
  ifelse
} bdef

/print-additional-information {       % write the additional information
  gsave
    /x 10 def
    /y back-spine-height spine-height add
       margins 3 mul add
       neg additional-information-font-height sub def

    columns-horizontally
    { /x x list-height
      songs-go-inside
      flip-songs xor
      { sub } { add } ifelse
      def

      songs-go-inside
      flip-songs not and
      { /y y inner-width margins add sub def } if

      songs-go-inside
      flip-songs and
      { /y y inner-width margins add add def } if
    }
    { songs-go-inside not
      flip-songs not and
      { /y y list-height margins add sub def } if

      songs-go-inside not
      flip-songs and
      { /y y list-height margins add add def } if
    }
    ifelse

    additional-information-font findfont
    additional-information-font-height scalefont setfont

    0 1 additional-information length 1 sub
    {  x y moveto
       additional-information exch get show
      /y y additional-information-font-height sub def
    } for
  grestore
 } bdef

/compute-spine-font-xscale {
  % compute horizontal size of largest band name string...
  magic-name-p
   { magic-name-width }
   { band-font findfont band-font-height scalefont setfont
     bandname1 bandname2 max-stringwidth }
  ifelse
  % compute horizontal size of largest album name string...
  album-font findfont album-font-height scalefont setfont
  albumname1 albumname2 max-stringwidth
  albumname3 albumname4 max-stringwidth max
  add                     % add them and divide inner-width by them to get
  spine-height mul        % the ratio to scale the fonts by.  If this is
  inner-width             % less than 1, don't do any scaling.
  10 sub     % subtract 10 from inner-width to account for the 5 point margin
             % between the text and the right and left edges.
  % if the two fonts are the same height, insert an additional 10 point gap.
%  band-font-height album-font-height eq { 10 sub } if
  % no, always insert it.
  10 sub

  exch div
  dup 1 ge { pop 1 } if
} bdef


/box-name-printers-p false def   % For debugging.  You don't want this.


/draw-spine {                       % draw the spine of the tape
  gsave
    margins  margins margins add  back-spine-height add neg  translate

    flip-spine not { 180 rotate inner-width neg spine-height translate } if
    
    0 0  inner-width  spine-height  box stroke     % the box around the spine
    0 0  inner-width  spine-height  box clip newpath
    margins spine-height neg translate
    /xscale compute-spine-font-xscale def
    gsave
      0 0 moveto
      spine-height xscale mul spine-height scale
      magic-name-p
      { box-name-printers-p  % debugging magic-name-printer sizing.
        { 0 setgray 0 0 magic-name-width -1 box fill
          { 1 exch sub } settransfer 0.01 setlinewidth 0 setgray
          0 1 9 { 0 moveto 0 1 rlineto stroke } for }
        if
%       bandname2 () eq not
%       {
%         0 0.6 translate
%         0.45 0.45 scale
%         gsave magic-name grestore
%         0 -1 translate
%         magic-name2
%       }
%       {
          0 0.2222 translate
          0.9 0.9 scale
          magic-name
%       } ifelse
      }
      { band-font findfont band-font-height scalefont setfont
        0 1 band-font-height sub moveto
        same-band-p { 0 -0.1 rmoveto } if
        bandname1 show
        0 1 band-font-height dup add sub moveto
        bandname2 show
      }
      ifelse
    grestore
    inner-width margins sub margins sub 0 translate
    gsave
      spine-height xscale mul spine-height scale
      /afh album-font-height def
      album-font findfont afh scalefont setfont
      1 afh sub
      dup 0 exch moveto
      double-album-p { 0 -0.1 rmoveto } if
      % albumname1 and albumname2 are the first album on each side.
      % albumname3 and albumname4 are the second album on each side.
      albumname1 () eq not {                  albumname1 rightshow afh sub }if
      albumname3 () eq not {dup 0 exch moveto albumname3 rightshow afh sub }if
      albumname2 () eq not {dup 0 exch moveto albumname2 rightshow afh sub }if
      albumname4 () eq not {dup 0 exch moveto albumname4 rightshow }if
      pop
    grestore
  grestore
} bdef

/coerce-to-array-of-strings {  % if given a string, puts it in an array.
  dup
  type /stringtype eq
  { 1 array astore }
  if
  } bdef


/draw-back-spine {                 % draw the short flap on the back.
  /x margins def
  /y margins neg def
  /w inner-width def
  /h back-spine-height def
  gsave
  x y w h box stroke
    x y w h box clip newpath
    x w add  y h add neg  translate
    180 rotate
    signature-font findfont signature-font-height scalefont setfont
    /s signature coerce-to-array-of-strings def
    /sx margins def
    /sy h margins 3 mul sub neg
        s length 1 sub signature-font-height mul add
       def
    s { sx sy moveto
        show
        /sy sy signature-font-height sub def
      } forall
  grestore
 } bdef


/reset {                % resets all the tape-specific parameters.
  /bandname1 () def
  /bandname2 () def
  /albumname1 () def
  /albumname2 () def
  /albumname3 () def
  /albumname4 () def
  /date1 () def
  /date2 () def
  /magic-name-p false def
  /magic-icon-p false def
  /double-album-p false def
  /same-band-p false def
  /dolby false def
  /additional-information false def

  %% This shouldn't be necessary, but it seems to be.
  %% This program is way outta control...
  %/song-fonts-w-scale 1 def
  %/song-fonts-h-scale 1 def
  /song-fonts-title-w-scale 1 def
  } bdef

reset                   % do it now to give them their initial values.
/signature () def       % probably redefined later.


/draw-tape-label {     % draw one.  Assumes all variables have been filled in.
                       % Takes X and Y on the stack.
  /tty exch def
  /ttx exch def

% save          % ** Comment this out if your PS interpreter doesn't like it.

  really-big { /ttx 0 def /tty 0 def } if

  gsave
    90 rotate
    ttx tty translate

    really-big { % This is a hack for debugging on screen...
      90 rotate 2 2 scale
      total-width neg 0 translate
     } if

    0 0 total-width total-height box stroke

    margins total-height neg
            list-height 2 mul add
            margins 2 mul add
    inner-width list-height box stroke    % draw a box around the back.
    magic-icon-p { draw-icon } if

    margins total-height neg
            list-height add
            margins add
    inner-width list-height box stroke    % draw a box around the listings.

    draw-back-spine
    draw-spine
    0 0 total-width total-height box      % draw the outermost box.

    % You are not expected to understand this.
    %
    flip-songs
    { 180 rotate total-width neg
      list-height
       spine-height back-spine-height add margins 3 mul add 2 mul
      add
      translate } if

    /frobbed-columns false def
    columns-horizontally
    { /frobbed-columns true def
      -90 rotate 0 inner-width translate
      back-spine-height spine-height add 3 margins mul add
      dup margins sub exch translate
      flip-songs
        {
          columns-horizontally not
          { 0 total-width neg margins add translate }
          if
          songs-go-inside
          { list-height margins add neg total-width neg margins add translate }
          if
        }
        { songs-go-inside
          { list-height margins add total-width translate }
          if }
      ifelse
      one-column { margins 0 translate } if    % hack
      /iw inner-width def
      /inner-width list-height def
      /list-height iw def
      /total-width inner-width margins dup add add def
    } if

    one-column
    { double-album-p not { [ albumname1 /Title ] } if
      songs1 aload pop
      double-album-p not
         { () albumname2 () eq not { [ albumname2 /Title ] } if } if
      songs2 aload pop
      songs1 length songs2 length add
      double-album-p not 
         { albumname2 () eq not {3} {2} ifelse add } if
      array astore
      /songs1 exch def
      /songs2 [] def
      double-album-p { print-inner-album-titles } if
      set-songfont
      1 print-songs
    }
    { print-inner-album-titles
      set-songfont
      0 print-songs
      1 print-songs }
    ifelse

    print-dates
    frobbed-columns  % fix up the sizes we've screwed with
      { DATp
        {DAT-sizes}
        { 8mmp
          {8mm-sizes}
          {cassette-sizes}
          ifelse }
        ifelse
      } if
    additional-information false eq not { print-additional-information } if
  grestore
  gsave
    90 rotate ttx tty translate

    really-big { % This is a hack for debugging on screen...
      90 rotate 2 2 scale
      total-width neg 0 translate
     } if

    -90 rotate margins 2 add dup translate
    dolby false eq not { draw-dolby } if
  grestore
  reset

% restore       % ** Comment this out if your PS interpreter doesn't like it.

 } bdef


%% Dolby symbols.  This code is derived from code written by Michael L. Brown.
%%
/draw-dolby-internal {
  gsave
    dup () eq
    { pop }
    {
      % text
      /Helvetica-Bold findfont 36 scalefont setfont
      92 12 moveto
      dup stringwidth pop /dolbytextw exch def
      show % from stack
      4 setlinewidth
      82 2 moveto
      0 46 rlineto
      dolbytextw 20 add 0 rlineto
      0 -46 rlineto
      closepath stroke
      % Trademark
% aaah, who needs this.
%      /Helvetica-Bold findfont 28 scalefont setfont
%      dolbytextw 110 add 29.5 moveto
%      (TM) show
    }
    ifelse
    % left D box
    0 0 moveto 0 50 rlineto 32 0 rlineto 0 -50 rlineto closepath fill
    % right D box
    38 0 moveto 0 50 rlineto 32 0 rlineto 0 -50 rlineto closepath fill
    1.0 setgray
    4 setlinewidth
    % left D
    10 8 moveto 0 34 rlineto stroke
    gsave
      newpath
      1.0 1.2142857 scale
      12 20.588236 14 270 90 arc fill
    grestore
    % right D
    60 8 moveto 0 34 rlineto stroke
    gsave
      newpath
      1.0 1.2142857 scale
      58 20.588236 14 90 270 arc fill
    grestore
    0.0 setgray
  grestore
} bdef

/draw-dolby {  % stack: x y
               % draw a dolby symbol at x,y, with a boxed string next to it.
               % if string=(), don't draw box.  DD symbol is 1 point square.
  gsave
    0.0143 9 mul dup scale
    dolby type /stringtype eq
    { dolby draw-dolby-internal }
    { /Helvetica-Bold findfont 36 scalefont setfont
      gsave
        5 setlinewidth
        /d dolby 3 string cvs def
        0 0 d stringwidth pop 12 add -36 box stroke
        7 7 translate 0 0 moveto d show
      grestore
    }
    ifelse
  grestore
} bdef

/Dolby  { /dolby () def } def
/DolbyB { /dolby (DOLBY  B) def } def
/DolbyC { /dolby (DOLBY  C) def } def
/AAD    { /dolby /AAD def } def
/DAD    { /dolby /DAD def } def
/ADD    { /dolby /ADD def } def
/DDD    { /dolby /DDD def } def
/dbx    { /dolby /dbx def } def

%%% Case-insensitive dictionary lookup.  Yowza.

/nsdc-buf 255 string def
/nstring-downcase { % target-string source-string
                    % convert a string to lowercase; copies source-string
                    % into target-string, doing the conversion.  The two 
                    % strings may be the same, and the source-string may
                    % be a 'name'.
  dup type /nametype eq { nsdc-buf cvs } if
  0 exch
  { dup dup 65 ge
    exch 90 le and
     { 32 add } if
    exch dup
    4 1 roll exch
    2 index 5 1 roll
    put 1 add
  } forall
  pop
} bdef

/CIget { % like get, but uses a lowercase version of the string.
    dup length string exch nstring-downcase get
} bdef

/CIput { % like put, but uses a lowercase version of the string.
    exch dup length string exch nstring-downcase exch put
} bdef

/CIknown { % like known, but uses a lowercase version of the string.
    dup length string exch nstring-downcase known
} bdef


% Dictionaries for storing magic band-name-and-icon-rendering functions.
%
/magic-name-dict 200 dict def
/magic-icon-dict 200 dict def

% Invoke the magic band-name-rendering function for the current band.
%
/magic-icon
{ magic-icon-dict bandname1 CIknown
  { magic-icon-dict bandname1 CIget exec }
  { magic-icon-dict /default-icon-printer known
    { magic-icon-dict /default-icon-printer get exec }
    if }
  ifelse
} bdef

/magic-name  { magic-name-dict bandname1 CIget 0 get exec } bdef
/magic-name2 { magic-name-dict bandname2 CIget 0 get exec } bdef

/magic-name-width { magic-name-dict bandname1 CIget 1 get } bdef


% Decide whether this band has a magic rendering function.
%
/check-magic {
  /magic-name-p magic-name-dict bandname1 CIknown def
  /magic-icon-p magic-icon-dict bandname1 CIknown 
                magic-icon-dict /default-icon-printer known or
  def
} bdef


% Define a new magic-name printer.
/define-magic-name-printer {   % arguments: bandname procedure width
   2 array astore
   magic-name-dict  % stack: band [proc w] dict
   3 1 roll         % stack: dict band [proc w]
   CIput
} bdef


/dump-internal {
  DATp { tick 2 eq {550} { tick 1 eq {300} {50} ifelse } ifelse }
       { tick 1 eq {360} {50} ifelse }
  ifelse
  -100 draw-tape-label
  tick DATp { 2 } { 1 } ifelse eq
  really-big or
  { showpage } if
  /tick tick 1 add DATp { 3 } { 2 } ifelse mod def
  really-big { /tick 0 def } if
  reset
} bdef

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%                 The user-level functions.               %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

/two-albums {   % arguments:  bandname album1 date1 album2 date2 songs1 songs2
                %             /additional-information info (both optional)
  1 index
  /additional-information eq
  {
    def
  } if
  /songs2 exch def
  /songs1 exch def
  /date2 exch def
  /albumname2 exch def
  /date1 exch def
  /albumname1 exch def
  /bandname1 exch def
  /same-band-p true def
  /band-font-height  0.6 def
  /album-font-height 0.4 def
  check-magic
  dump-internal
} bdef


/two-bands { %args: bandname1 album1 date1 songs1 bandname2 album2 date2 songs2
             %      /additional-information info (both optional)
  1 index
  /additional-information eq
  {
    def
  } if
  /songs2 exch def
  /date2 exch def
  /albumname2 exch def
  /bandname2 exch def
  /songs1 exch def
  /date1 exch def
  /albumname1 exch def
  /bandname1 exch def
  /band-font-height  0.4 def
  /album-font-height 0.4 def
  /magic-name-p false def
  /magic-icon-p false def
%  check-magic
  dump-internal
} bdef


/double-album { % arguments:  bandname album date songs1 songs2
                %             /additional-information info (both optional)
  1 index
  /additional-information eq
  {
    def
  } if
  /songs2 exch def
  /songs1 exch def
  /date1 exch def
  /albumname1 exch def
  /bandname1 exch def
  /band-font-height  0.6 def
  /album-font-height 0.6 def
  /double-album-p true def
  /same-band-p true def
  check-magic
  dump-internal
} bdef


/N-albums { %args:  bandname album1.1 album1.2 date1 album2.1 album2.2 date2 songs1 songs2
            %       /additional-information info (both optional)
  1 index
  /additional-information eq
  {
    def
  } if
  /songs2 exch def
  /songs1 exch def
  /date2 exch def
  /albumname4 exch def
  /albumname2 exch def
  /date1 exch def
  /albumname3 exch def
  /albumname1 exch def
  /bandname1 exch def

  /band-font-height 0.6 def
  () albumname3 eq () albumname4 eq and
  { /album-font-height 0.4 def }
  { () albumname3 eq () albumname4 eq or
    { /album-font-height 0.3125 def }
    { /album-font-height 0.21875 def }
    ifelse }
  /same-band-p band-font-height 0.6 eq def
  ifelse

  check-magic
  dump-internal
} bdef


/two-bands-N-albums { % arguments:  band1 album1.1 album1.2 date1 songs1 band2 album2.1 album2.2 date2 songs2
                      %             /additional-information info (both optional)
  1 index
  /additional-information eq
  {
    def
  } if
  /songs2 exch def
  /date2 exch def
  /albumname4 exch def
  /albumname2 exch def
  /bandname2 exch def
  /songs1 exch def
  /date1 exch def
  /albumname3 exch def
  /albumname1 exch def
  /bandname1 exch def

  /band-font-height 0.4 def
  () albumname3 eq () albumname4 eq and
  { /album-font-height 0.4 def }
  { () albumname3 eq () albumname4 eq or
    { /album-font-height 0.3125 def }
    { /album-font-height 0.21875 def }
    ifelse }
  ifelse
  /magic-name-p false def
  /magic-icon-p false def
  dump-internal
} bdef


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%                 The Magic-Name Printers.                %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%    These routines will be automatically invoked to      %%%%%%%%
%%%%%%%    draw certain band-names, so that you can have        %%%%%%%%
%%%%%%%    really hi-tech tape-labels.  Add more!               %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%% Draw "Front 242" as a long, thin "front" over a long, tall "242".
%%%
(Front 242)
  {
    gsave
      0 -0.1 translate
      0.95 1 scale
      /Helvetica-Bold findfont [ 1.35 0 0 0.4 0 0 ] makefont  setfont
      0 0.58 moveto
      (FRONT) show
      /Helvetica-Bold findfont [ 2.85 0 0 0.7 0 0 ] makefont  setfont
      0 0 moveto (242) show
    grestore
  } bind
  4
define-magic-name-printer

%%% Draw "Orchestral Manoeuveres in the Dark" on two lines; use the
%%% "oe" character.
%%%
(Orchestral Manoeuveres in the Dark)
  {
    gsave
      0 -0.1 translate
      0.7 1 scale
      /Helvetica-Bold findfont [0.45 0 0 0.65 0 0] makefont setfont
      0.1 0.35 moveto
      (ORCHESTRAL MAN\352UVRES) show
      /Helvetica findfont [1 0 0 0.3 0 0] makefont setfont
      0.1 0.05 moveto
      (IN THE DARK) show
    grestore
  } bind
  4.2
define-magic-name-printer


%%% Draw "OMD" in the same way as "Orchestral Manoeuveres in the Dark".
%%%
magic-name-dict (OMD) cvn
  magic-name-dict (Orchestral Manoeuveres in the Dark) cvn CIget
CIput


%%% Draw "New Order" as a dark "New" over an outlined "Order", staggered.
%%%

(New Order)
  {
    gsave
      0 -0.1 translate
      0.02 setlinewidth
      1.5 setmiterlimit
      /Helvetica-Bold findfont setfont
      0 0.1 moveto
      (Order) true charpath stroke
      1.57 0.1 moveto
      (new) show
    grestore
  } bind
  3.2
define-magic-name-printer


%%% Draw "Siouxsie and the Banshees" with varying-height letters,
%%% like on the early albums.
%%%

(Siouxsie and the Banshees)
  {
    gsave
      0 -0.1 translate
      0.7 0.4 scale
      0.1 0.25 translate
      /big-font   /Helvetica findfont [ 0.5 0 0 2.2 0 0 ] makefont  def
      /med-font   /Helvetica findfont [ 0.5 0 0 1.1 0 0 ] makefont  def
      /small-font /Helvetica findfont [ 0.5 0 0 1.5 0 0 ] makefont  def
      0 -0.1 5.9 -1.8 box clip newpath
      0 0 moveto
      big-font setfont (SI) show
      0 0.8 rmoveto
      small-font setfont (o) show
      0 -0.8 rmoveto
      big-font setfont (UXSIE) show
      med-font setfont
      currentpoint /y exch def /x exch def
      .07 0.85 rmoveto
      (and) show x y moveto (THE) show
      big-font setfont (BANSHE) show
      0 0.8 rmoveto
      small-font setfont (e) show
      0 -0.8 rmoveto
      big-font setfont (S) show
    grestore
  } bind
  4
define-magic-name-printer


%%% Draw "Cabaret Voltaire" in their font.  I should probably have
%%% implemented this as a font, instead of as a set of procedures,
%%% but life's too short.
%%%

(Cabaret Voltaire)
  {
    gsave
      0 -0.1 translate
      0.5 0.5 scale
      1.8 setmiterlimit 0.1 setlinewidth
      0.2 0.3 moveto cabaret-c 0.5 0 rmoveto cabaret-a
      0.7 0 rmoveto cabaret-b  0.6 0 rmoveto cabaret-a
      0.7 0 rmoveto cabaret-R  0.6 0 rmoveto cabaret-e
      0.4 0 rmoveto cabaret-T  1.0 0 rmoveto cabaret-v
      0.6 0 rmoveto cabaret-o  0.7 0 rmoveto cabaret-L
      0.6 0 rmoveto cabaret-t  0.4 0 rmoveto cabaret-A
      0.45 0 rmoveto cabaret-I 0.45 0 rmoveto cabaret-r
      0.5 0 rmoveto cabaret-e
    grestore
  } bind
  4.1
define-magic-name-printer

%% Internal procedures to the "Cabaret Voltaire" printer.
%%
/cabaret-c { gsave currentpoint translate newpath 0.5 0.25 moveto 0.25 0 lineto
  0 0.5 lineto 0.25 1 lineto 0.5 0.75 lineto stroke grestore } bdef

/cabaret-a { gsave currentpoint translate newpath 0.25 0.75 moveto 0.5 1 lineto
   0.5 0 lineto 0 0.5 lineto 0.5 0.5 lineto stroke grestore } bdef

/cabaret-b { gsave currentpoint translate newpath 0 1 moveto 0 0 lineto 
  0.5 0.5 lineto 0 0.5 lineto stroke grestore } bdef

/cabaret-R { gsave currentpoint translate newpath 0 0 moveto 0 1 lineto 0.5 0.5
  lineto 0 0.5 lineto 0.25 0.5 moveto 0.5 0 lineto stroke grestore } bdef

/cabaret-e { gsave currentpoint translate newpath 0.375 0.25 moveto 
  0.25 0 lineto 0 0.5 lineto 0.25 1 lineto 0.5 0.5 lineto 0 0.5 lineto stroke
  grestore } bdef

/cabaret-T { gsave currentpoint translate newpath 0 1 moveto 0.5 1 lineto 
  0.25 1 moveto 0.25 0 lineto stroke grestore } bdef

/cabaret-v { gsave currentpoint translate newpath
  0 1 moveto 0.25 0 lineto 0.5 1 lineto stroke grestore } bdef

/cabaret-o { gsave currentpoint translate newpath 0.25 1 moveto 0.5 0.5 lineto
  0.25 0 lineto 0 0.5 lineto closepath stroke grestore } bdef

/cabaret-L { gsave currentpoint translate newpath 0 1 moveto
    0 0.10 lineto 0.5 0.10 lineto stroke grestore } bdef

/cabaret-t { gsave currentpoint translate newpath 0 1 moveto
  0 0 lineto 0.275 0.25 lineto stroke 0 0.75 moveto 0.25 0.75 lineto stroke
  grestore } bdef

/cabaret-A { gsave currentpoint translate newpath 0 0 moveto 0.25 1 lineto
  0.5 0 lineto stroke 0.125 0.5 moveto 0.375 0.5 lineto stroke grestore } bdef

/cabaret-I { gsave currentpoint translate newpath 0.25 0 moveto 0.25 1 lineto
  stroke grestore } bdef

/cabaret-r { gsave currentpoint translate newpath 0 0 moveto 0 1 lineto stroke
  0 0.75 moveto 0.25 1 lineto 0.5 0.75 lineto stroke grestore } bdef


(Nine Inch Nails)
  { gsave
      0 0 moveto
      /Helvetica findfont [ 1 0 0 1 0 0] makefont
      /Helvetica findfont [-1 0 0 1 0 0] makefont
      dup setfont
      gsave
        90 rotate 0.3 -0.2 translate 0.7 0.7 scale NiNbox
      grestore
      /nw (n)stringwidth pop neg def
      0.6 0 moveto
      nw 0 rmoveto (n)show
      nw 0 rmoveto exch dup setfont (i)show
      nw 0 rmoveto exch dup setfont (n)show
      nw 0 rmoveto exch dup setfont (e i)show
      nw 0 rmoveto exch dup setfont (n)show
      nw 0 rmoveto exch dup setfont (ch )show
      nw 0 rmoveto exch dup setfont (n)show
      nw 0 rmoveto exch dup setfont (ails)show
      pop pop
    grestore } bind
  6.3
define-magic-name-printer

%% Draw "Depeche Mode" as on their "Some Great Reward"
%% "depeche" (in lower case) over a larger "MODE"
%% By Roderick Lee <[email protected]>.
%%
(Depeche Mode)
  {
    gsave
    0 -0.1 translate
    0.95 1 scale
        /Helvetica-Bold findfont [ 0.60 0 0 0.50 0 0 ] makefont setfont
        0.05 0.51 moveto
        (depeche) show
        /Helvetica-Bold findfont [ 0.84 0 0 0.70 0 0 ] makefont setfont
        0 -0.05 moveto
        (MODE) show
    grestore
  } bind
  2
define-magic-name-printer

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%                 The Magic-Icon Printers.                %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%    These routines will be automatically invoked to      %%%%%%%%
%%%%%%%    draw icons for tapes of certain band, again for      %%%%%%%%
%%%%%%%    added whizziness.  Add more!                         %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

magic-icon-dict (Love and Rockets) cvn { L&R } CIput

/L&R {    % Love and Rockets logo.
  gsave
   0.005 setlinewidth
   gsave
     newpath 0.5 0 moveto 0 0 0.5 0 360 arc clip newpath
     -0.5 -0.5 1 -1 box fill
     1 setgray
     -0.1875 -0.5 0.375 -1 box fill
   grestore
   newpath 0.5 0 moveto 0 0 0.5 0 360 arc stroke
   L&R-rocket
   L&R-heart
  grestore
  } bdef

/L&R-rocket {
  -0.0625 0.3125 0.125 0.625 box fill   % shaft
  -0.0625 0.3125 moveto 0.125 0 rlineto % head
   0 0.5 lineto closepath fill
  -0.0625 -0.2 moveto -0.03 -0.03 rlineto % lfin
   0 -0.25 rlineto 0 -0.3125 lineto fill
   0.0625 -0.2 moveto 0.03 -0.03 rlineto  % rfin
   0 -0.25 rlineto 0 -0.3125 lineto fill
  } bdef

/L&R-heart-path {
  newpath
  0 0.125 moveto
  -0.0625 0.125 0.0625 0 180 arc
  0 -0.125 lineto
  0.125 0.125 lineto
   0.0625 0.125 0.0625 0 180 arc
  closepath
  } bdef

/L&R-heart {
  0.5 setgray L&R-heart-path fill
  0 setgray L&R-heart-path stroke
  } bdef


magic-icon-dict (Bauhaus) cvn { BEGA } CIput

/BEGA {  % Beggars Banquet logo.
  gsave
   0.005 setlinewidth
   newpath 0.5 0 moveto 0 0 0.5 0 360 arc stroke
   newpath 0.5 0 moveto 0 0 0.5 0 360 arc clip newpath
   0     0.3333 moveto 0.25 0 rlineto 0 -0.25 rlineto stroke  % eye
   0.083 0.3333 0.1666 0.1666 box fill
   0.3125 0.5 0.02 0.5 box fill                         % nose v
   0.2125 0 moveto 0.3125 0 lineto stroke               % nose h
   0.2725 0 0.04 0.3 box fill                           % mouth v
   0.2125 -0.125 0.1 0.03 box fill                      % mouth h
   0.125 -0.3 0.155 0.25 box fill                       % chin v
   0.0625 -0.3 moveto 0.28 -0.3 lineto stroke           % chin h
  grestore
  } bdef

magic-icon-dict (Nitzer Ebb) cvn { NE-dispatch } CIput

/NE-dispatch {  % draw one of three nitzer ebb logos, depending on albumname.
  albumname1 (That Total Age) eq
  { NE3 }
  { albumname1 (Belief) eq
    { NE-belief }
    { NE-star-and-gear }
    ifelse
  }
  ifelse
} bdef

/NE3 {  % Nitzer Ebb "That Total Age" logo.
  gsave
    -0.175 0.5 0.35 1 box fill
    0.5 setgray
    /s 0.3 def
    gsave 0 -0.3333 translate s s scale
     NE-hammer grestore
    gsave s s scale
     starpath fill grestore
    gsave 0 0.3333 translate s s scale
     NE-gear grestore
  grestore
  } bdef

/NE-gear {
  gsave
    0.1 setlinewidth
    0 0 0.375 0 360 arc stroke
    0 1 8
     { -0.075 0.5 0.15 0.1 box fill
       45 rotate
     } for
  grestore
  } bdef

/NE-hammer {
  gsave
    0.05 0 translate
    45 rotate
    -0.1 0.4 0.2 0.85 box fill
    -0.3 0.4 0.45 0.2 box fill
     0.15 0.4 moveto
     0.35 0.2 lineto
     0.15 0.2 lineto
     closepath fill
  grestore
  } bdef

/starpath {
  newpath 0 0.5 moveto
  0 1 4 { 144 rotate 0 0.5 lineto } for
  closepath
  } bdef


/NE-star-and-gear {  % Nitzer Ebb "Warsaw Ghetto" logo.
  gsave
   0.8 0.8 scale
   NE-split-gear
  grestore
  NE-split-star
  } bdef

/NE-split-star {
  gsave
    0.02 setlinewidth
    0 setgray starpath stroke
    starpath clip newpath
    0 setgray 0 0.5 0.5 1 box fill
    1 setgray -0.5 0.5 0.5 1 box fill
  grestore
  } bdef

/NE-gear-path {
    0 0.5 moveto
    0 1 11
      { -0.075 0.5 lineto
        -0.075 0.45 lineto
        30 rotate
         0.075 0.45 lineto % ## make this a curveto!!
         0.075 0.45 lineto
         0.075 0.5 lineto
      } for
    closepath
  } bdef


/NE-split-gear {
  gsave
    % I tried doing this with eopath, but it doesn't work in Amiga Post 1.1.
    0.005 setlinewidth
    0 setgray
    NE-gear-path stroke
    NE-gear-path clip newpath
    -0.5 0.5 0.5 1 box fill
    1 setgray 0.4 0 moveto 0 0 0.4 0 360 arc fill
    0 setgray 0.4 0 moveto 0 0 0.4 0 360 arc stroke
  grestore
  } bdef

%% What follows is a bitmap of the "grainy eye" image from "Belief".
%% Digitized on an Amiga, converted to PS with Jef Poskanzer's PBM toolkit.
%% I would have stored the bitmap run-length encoded, but that would have
%% taken some work, as the only rle-decoders I have expect to draw the image
%% as they decode, and not store it away for future use as we do here.
%%
/NE-belief {
  gsave
  0.8 0.8 scale
  -0.5 -0.5 translate
  82 71 1
  [ 82 0 0 -71 0 71 ]
  %% 28 lines of bitmap data... pinhead representation (tm).
  {<000000000000000000003f000000000000000000003f000000000000000000003f00000000
   0000000000003f000000000000000000003f03ffffffffffeffff0003f03ffffffdf3fffffb
   0003f03fffff800002ff661003f03ffffe00000060ffb003f03ffff8000000001fc003f007f
   fc00000000067c003f007fe000000000001d803f001f00000000000008203f0000000000000
   00006003f000000000000000004003f0000000000001e0000003f0000000000003f8000003f
   0000000000007d0000003f000000000000390000003f000000000000000000003f000000000
   000000000003f000000000000000000003f000000000000000000003f000000002000000000
   003f0000000ff000000000003f0000001fe006000000003f0000003f8046000000003f02000
   07fc1c6000000003f0200007fb780000000403f0300007fc70800000f803f0300003ff03040
   0008883f030001ffffff800018003f0380004ffffe0001f8003f03800007fffc0003fc003f0
   380001780000053f4003f03800001c8000197f7003f03800001f80001fffe003f03800046c0
   0037ffbf003f03800007f801ffffff803f0380000ffffffffff0003f03800003fffffffffe0
   03f03800002fffffffffe003f03c00000fffffffff8003f03c00000fffffffff8003f03c000
   01fffffffff0003f03c000007ffffffff0003f03c000001ffffffff0003f03c000007ffffff
   fe0003f03c00000ffffffffe0003f03e000007fffffffe0003f03e000003fffffff40003f03
   e000001fffffff80003f03e000001ffffffd80003f03f0000003fffffe00003f03f0000001f
   ffffc00003f03f0000001fffffc00003f03f0000000fffffc00003f03f00000017ffff80000
   3f03f0000001fffffc00003f03f0000000fffff800003f03e0000000fffff800003f03e0000
   0003ffff000003f03e000000017fff000003f0300000000179fe000003f02000000001f0ae0
   00003f000000000001000000003f0000000000007f0000003f000000000000000000003f000
   000000000000000003f000000000000000000003f000000000000000000003f000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000000000000000000000000000000000000000000000000000000
   000000000000000000000000>}
  image
  grestore
  } bdef

magic-icon-dict (Nine Inch Nails) cvn { NiNbox } CIput

/NiNbox {
   gsave
    0.7 0.7 scale
    /Helvetica-Bold findfont [ 1 0 0 1 0 0] makefont
    /Helvetica-Bold findfont [-1 0 0 1 0 0] makefont
    dup setfont
    (NIN)stringwidth pop 2 div -0.3 translate
    0 0 moveto
    /Nw (N)stringwidth pop neg def
    Nw 0 rmoveto (N)show Nw 0 rmoveto
    exch dup setfont (IN)show exch
    0.1 setlinewidth
    -0.1 -0.15 Nw (IN)stringwidth pop add 0.2 add -1.05 box stroke
    pop pop
    grestore
} bdef

%% Kate Bush logo by Christer Lindh <[email protected]>.  
%% This draws the old-style KB logo. If it goes on the outside 
%% but songs go inside, it is rotates 90 degrees.
%%
/KB {   gsave
        .87 .87 scale
%       songs-go-inside icons-go-inside not and
%               { -0.5 0.54 translate -90 rotate }
%               { -0.5 -0.5 translate }
%               ifelse
        -0.5 -0.5 translate
        0.5 0.5 0.5 0 360 arc fill stroke
    1 setgray
        0.3 setlinewidth
        0.14 0.68 moveto
    0.14 0 lineto stroke

    0.08 setlinewidth
    0 0.80 moveto
    1 0.80 lineto
    0.45 0.80 moveto
    0.45 0 lineto stroke

    0.06 setlinewidth
    0.45 0.45 moveto
    1 0.875 lineto
    0.60 0.55 moveto
    0.9 0.1 lineto stroke
   grestore
} bdef
magic-icon-dict (Kate Bush) cvn { KB } CIput

systemdict /statusdict known
{ systemdict /statusdict get /product known
  { systemdict /statusdict get /product get (Ghostscript) eq
    { /really-big true def } if
  } if
} if

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%      Dead bitmap from [email protected] (Fish)
%%      courtesy of boccibob%[email protected] (Bob Ramstad).
%%      Doubly inverted version (black<->white) and (left<->right)
%%      by Duane Day ([email protected]).
%%      The bitmap of the skull is from rec.music.gdead, it is
%%      presumed to be in the public domain.

magic-icon-dict (Dead) cvn { SYF } CIput

magic-icon-dict (Grateful Dead) cvn { SYF } CIput

/SYF { % Steal Your Face Logo.
  gsave
  0.8 0.8 scale
  -0.5 -0.5 translate
  96 100 1
  [96 0 0 -100 0 100]
  % data:

  {<ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffff8001ffffffffff
fffffffff03ffc07ffffffff
ffffffff81ffffc0ffffffff
fffffffc0fc007f83fffffff
fffffff03e0001fe0fffffff
ffffffe0f800000f81ffffff
ffffff83c0000001c0ffffff
fffffe0700000000f07fffff
fffff81e00000004381fffff
ffffe0380000003c1c07ffff
ffffe070000001f80e03ffff
ffff80e0000000300701ffff
ffff01c00000007003807fff
fffe0380000001e001c07fff
fffc0700000007c200e03fff
fff8070000001fde00601fff
fff80c000000fffc00700fff
fff01c000001fff0003007ff
ffe0180000000fe0001803ff
ffc03800000007c0001803ff
ffc0300000001f00001801ff
ff80600000003c00000c00ff
ff0060000000ff80000c00ff
ff0060000003fffe0006007f
fe00c000000ffffc0006007f
fe00c000003ffff80006003f
fe00c00000fc7fc00006003f
fc01c0000000ff800003001f
f80180000003fe000003001f
f8018000000ffc000003000f
f0018000001ff0000003000f
f0018000003fc0080003000f
f0018000007ffff80003000f
e001800001ffffc000030007
e001800007ffff8000030007
e00180000ffffe0000030007
e00180003e1ff80000030007
c0018000003ff00000060007
c0018000007fc00000060007
c001800001ff000000060003
c001400003feff8000060003
c000c00007fffe00000c0003
c000a0000ffff000000c0007
c000a0003fffe000001c0007
c000a00060ff800000180007
c000500001fe000000180007
c000500003f0000000300007
c000280003e0000000700007
c000280007fe000000700007
c00014000ff8000000e0000f
c0001a000fe0000001e0000f
c0000a001f8000000340000f
c0000d001e0000000740000f
e0000d003f8000000ec0000f
e00005403e0000001e80001f
e0000960700000003e80001f
e00000f800000000fc80001f
f00002fc00000001fc80003f
f00002ff00000017fc80003f
f00002ffc000003ffd00003f
f8000a7ff800007ffe80007f
f800093fff001ff3f28000ff
f800090f07f8fc01c50000ff
fc00020001fdf0000f0000ff
fc000900007de000080001ff
fe000200001fc000180003ff
fe000060000f800ff00003ff
ff00000a7fefbffe200007ff
ff8000017fef7fff50000fff
ff800040ffef7fff50001fff
ffc00055fff6ffff50001fff
ffe00055fff4fffea0003fff
fff00029fff0fffc00007fff
fff80000ffe0fff00000ffff
fffc00001fe07ff00001ffff
fffe000021e47c400003ffff
ffff000029f6ff400007ffff
ffff80002dffff00000fffff
ffffe0000dffff00001fffff
fffff00008fff88000ffffff
fffff800099ff58001ffffff
fffffe001b42050003ffffff
ffffff800369b4000fffffff
ffffffe0035db4003fffffff
fffffff80159b000ffffffff
ffffffff0009a007ffffffff
ffffffffe000003fffffffff
ffffffffff000fffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff
ffffffffffffffffffffffff>}
  image
  grestore
  } def


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%      old version: non-inverted, and not flipped left / right either.
%%      Dead bitmap from [email protected] (Fish)
%%      courtesy of [email protected] (Bob Ramstad).
%%      The bitmap of the skull is from rec.music.gdead, it is
%%      presumed to be in the public domain.
%
% magic-icon-dict (Dead) cvn { SYF } CIput
%
% magic-icon-dict (Grateful Dead) cvn { SYF } CIput
%
% /SYF { % Steal Your Face Logo.
%  gsave
%  0.8 0.8 scale
%  -0.5 -0.5 translate
%  96 100 1
%  [96 0 0 -100 0 100]
%  % data:
%
%  {<000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%00000000007ffe0000000000
%000000001fc003f000000000
%00000000fc00007e00000000
%00000003e01ffc0fc0000000
%0000000f807fff83f0000000
%0000007e0fffffe0f8000000
%000000fc7ffffffc3e000000
%000001f0ffffffff1f800000
%000007e3dfffffff87e00000
%00001fc7c3ffffffe3f80000
%00003f8fe07ffffff1f80000
%00007f1ff3fffffff8fe0000
%0001fe3ff1fffffffc7f0000
%0001fc7ff87ffffffe3f8000
%0003f8ffbc1fffffff1fc000
%0007f9ff8407ffffff1fe000
%000ff1ffc000ffffffcfe000
%001ff3fff0007fffffc7f000
%003fe7fff80fffffffe7f800
%003fe7fffc1fffffffe3fc00
%007fe7ffff07fffffff3fc00
%00ffcfffffc3fffffff9fe00
%00ffcffffe00fffffff9ff00
%01ff9fff80003ffffff9ff00
%01ff9fffc0000ffffffcff80
%03ff9fffe00003fffffcff80
%03ff9ffffc01c0fffffcff80
%07ff3ffffe00fffffffc7fc0
%07ff3fffff803ffffffe7fe0
%0fff3fffffc00ffffffe7fe0
%0fff3ffffff007fffffe7ff0
%0fff3fffeffc03fffffe7ff0
%0fff3fffe00001fffffe7ff0
%1fff3ffffc00007ffffe7ff8
%1fff3ffffe00001ffffe7ff8
%1fff3fffff80000ffffe7ff8
%1fff3fffffe00783fffe7ff8
%1fff9ffffff003fffffe7ffc
%1fff9ffffffc01fffffe7ffc
%3fff9fffffff007ffffe7ffc
%3fff9ffffe00803ffffd7ffc
%3fffcfffff80001ffffcfffc
%1fffcffffff0000ffffafffc
%1fffc7fffff80003fffafffc
%1fffe7fffffe00f9fffafffc
%1fffe7ffffff807ffff5fffc
%1ffff3fffffff03ffff5fffc
%1ffff1fffffff83fffebfffc
%1ffff1ffffff801fffebfffc
%0ffff8ffffffe00fffd7fffc
%0ffff87ffffff80fffa7fffc
%0ffffd3ffffffe07ffaffffc
%0ffffd1fffffff87ff4ffffc
%0ffffc8ffffffe03ff4ffff8
%07fffe87ffffff83fd5ffff8
%07fffe83fffffff1f96ffff8
%07fffec0ffffffffe0fffff8
%03fffec07fffffffc0bffff0
%03fffec017ffffff00bffff0
%03ffff4003fffffc00bffff0
%01fffe8001ffffe001afffe0
%00fffeb03007ff00036fffe0
%00ffff5c7fc0e01f0f6fffe0
%00ffff0ffff0407fffbfffc0
%007fffeffff841ffff6fffc0
%003fffe7fffc07ffffbfff80
%003ffff00ffe0ffff9ffff80
%001ffffb80020801afffff00
%000ffff5000108017ffffe00
%0007fff500010800fdfffe00
%0007fff50000900055fffc00
%0003fffa8000d00055fff800
%0001ffffc000f0006bfff000
%0000fffff000f800ffffe000
%00007ffff001f807ffffc000
%00003ffffdc1d87bffff8000
%00001ffffd00906bffff0000
%00000fffff00004bfffe0000
%000007ffff00004ffff80000
%000000fffee000effff00000
%0000007ffe50066fffe00000
%0000003fff5fbd27ff800000
%0000000fffd2693ffe000000
%00000003ffd2453ff8000000
%00000000fff2657fe0000000
%000000001ffa6fff00000000
%0000000003fffff800000000
%00000000000fff0000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000
%000000000000000000000000>}
%  image
%  grestore
%  } def
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/signature 
[
(From the private collection of Robert Ramstad.)
(Recorded with Dolby B unless otherwise noted.)
]
def

/flip-spine true def
/band-font /Helvetica def
/album-font /Helvetica def
%%EndProlog


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%                 Begin Example-Land.                     %%%%%%%%
%%%%%%%         Modify what lies after this point.              %%%%%%%%
%%%%%%%                                                         %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%% Set this string to what you want printed on the back flap, or an array
%% of strings (one string per line).
%%
/band-font /Helvetica def               % The font for band-names.
/album-font /Helvetica def              % The font for album-names.

% Uncomment the next line to produce labels for Digital Audio Tapes.
%DAT-sizes
% Uncomment the next line to produce labels for 8mm video cassettes.
%8mm-sizes

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%  An example of the normal case: two albums by one band,  %%%%%%%%
%%%%%%  with one album on each side of the tape.                %%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

(Gang of 4)             (Entertainment)         (1979)
                        (Solid Gold)            (1981)
[(Ether)
 (Natural's not in it)
 (Not Great Men)
 (Damaged Goods)
 (Return the Gift)
 (Guns before Butter)
 ()
 (I Found that Essence Rare)
 (Glass)
 (Contract)
 (At Home He's a Tourist)
 (5:45)
 (Anthrax)
 ()
 (To Hell With Poverty)
 (Capital it Fails Us Now)
 ]
[(Paralysed)
 (What we All Want)
 (Why Theory)
 (If I could keep it for myself)
 (Outside the trains don't run on time)
 ()
 (Cheeseburger)
 (The Republic)
 (In the Ditch)
 (A Hole in the Wallet)
 (He'd send in the Army)
 ]
/additional-information
[(Arbitrary text line 1.  This may be excessively long.        Well maybe not!)
 (Arbitrary text line 2)
 ()
 (Arbitrary text line 4)
 ]
two-albums

%%Trailer
%%  This form should always be here at the end, to make sure that the
%%  final page is dumped even if there are an odd number of labels
%%  being printed.
%%
tick 0 ne { showpage } if
end % pop the TapeDict



------------------------------

** FOR YOUR REFERENCE **

Requests to be added to or deleted from the DAT-heads mailing list, 
questions about the list, and requests for the current version of the
Frequently Asked Questions file must be sent to one of the following
service addresses:

    Internet: [email protected]
              [email protected]
    BITNET:   DATH-Req@Virginia
    UUCP:     ...!uunet!virginia!dat-heads-request

You can send mail to the entire list via one of these addresses:

    Internet: [email protected]
              [email protected]
    BITNET:   DATHeads@Virginia
    UUCP:     ...!uunet!virginia!dat-heads

End of DAT-Heads Digest
******************************

% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
% Received: by easynet.crl.dec.com; id AA21142; Sat, 17 Apr 93 01:04:26 -0400
% Received: by crl.dec.com; id AA15518; Sat, 17 Apr 93 01:04:22 -0400
% Message-Id: <[email protected]>
% Received: from fuggles.acc.Virginia.EDU by fuggles.acc.Virginia.EDU id aa27883;          16 Apr 93 20:32 EDT
% From: Digestifier <[email protected]>
% To: [email protected]
% Date:     Fri, 16 Apr 93 20:30:03 EDT
% Subject:  DAT-Heads Digest #493
72.16Now, how to use it for Dead TAPES?CORA::65447::BELKINthe slow one now will later be fastThu Apr 22 1993 11:4830
So, I'm trying to use CDA to view the .PS files so I can screw around with
this and get things right for using it with typical Dead tapes.

For example, for a Dead tape, I think you wanna use "double-album" ?
and the 'album-name' would be the venue/date of show?

Also, the area of the the label that has the 'signature' is IMHO better used
for info like 

Date the tape was recorded:  	Owner:
Type:				SCMS:
Notes: (history)

as I've seen on a Mystery Hill Productions tape label.
Now, this can be easily done with this program, but, problem is, it comes out
upside-down.  Anyone have a clue how make the .signature 'flip' ?
(Guess I'll ask the DAT-heads.)

I'm having problems with CDA - it draws the .ps file rotated 90 degrees.
Its easy enough to change that with the print options 'rotate' button, 
BUT HOW TO I PUT THIS IN A FREAKIN' .CDA$OPTIONS FILE????
I read the help on creating the .cda$options file, but _nowhere_ in there
does it say precisely how to specify something like the option to rotate
the page!!!  ARRGGHH!!!!  I also looked at the CDA stuff in Bookreader and
couldn't find anything in there about the View that was more than a 2 
paragraph description.

thanks, Josh

72.17CSCMA::M_PECKARBe kind: unwindThu Apr 22 1993 11:572
Well, you might try playing with the vms command convert/document first???
72.18closer but still no cigarCORA::65447::BELKINthe slow one now will later be fastThu Apr 22 1993 12:5615
Well, I don't want to have zillions of extra files around, and its also an
extra step to have to do.  However the help in convert/document was a little
usefull in describing how to make a .cda$options file, it gave the keywords,
but its still not working.

I have in file dat.cda$options:

PS LANDSCAPE
PS WATCH


and I set up CDA to use this options file, but it still either ignores the
options or something still isn't right.

thanks, Josh
72.19EBBV03::SMITHSo many roads tease my soulThu May 27 1993 17:024
	Where might I be able to obtain the tape labeler that
	puts the big white GD in the background of the place where
	the song list is?
72.20NRSTA2::CLARKElectric Music for the Mind and BodyThu May 27 1993 17:161
Deane, I think that might be JC's labeller ... send him mail ....
72.21AKOCOA::DMITCHELLor just another pretty faceThu May 27 1993 17:206
    
    .19 
    
    Deane, yes, Check w/ JC.
    
    Don
72.22ZENDIA::FERGUSONYour recipe is so tastyFri May 28 1993 11:431
both these guys are correct, that one be mine... send me mail.
72.23Grateful T.E.D. v2.0 Taper's Electronic DatabaseNRSTA2::CLARKWed Jun 30 1993 14:2255
Hey folks;

I ftp'd the Grateful T.E.D. software that's been mentioned in rec.music.gdead,
and put it in NRSTA2::USER03:[CLARK.PUBLIC]G_TED20.ZIP ... description is
below.  Ignore the bit about the self-extracting archive, I put the files
into a .ZIP file instead.  I scanned the files for viruses and they're clean.

- DC

p.s.  Only problem I've found so far is that you'll have to edit the
.PIF file if you want to use it from Windows, to change the pathspec to
whatever directory you choose to contain the software.


Subj:  G_TED20.EXE Grateful T.E.D. v2.0 Taper's Electronic Database




AUTHOR:  Michael E. Carver
EQUIPMENT:  IBM compatible, Hard Drive recommended (or high-density floppy)
NEEDS: Deadicated tape collection    

Type:  Shareware




Grateful T.E.D. (Taper's Electronic Database) version 2.0 is a DOS 
based database programmed specifically for DEALing with HARD TO 
HANDLE Dead tape collections.

Features:
   - Space for 22 song titles per entry
   - Pull Down Menus
   - Fast Entry of song titles (maintains a separate database of 
     readily available Dead tunes)
   - Multiple supported indexes (Date, City, Venue, Source, Recording 
     Quality, Performance Quality, & Overall Quality) -- providing 
     quick retrieval of particular tape(s)
   - Quickly locate tape(s) with a particular song title
   - Ability to print out tape lists (all or selected tapes) -- 4 
     different formats
   - Ability to print out to file or printer
   - Quickly calculates statistics on average quality of collection +
     total time

G_TED20.EXE is a self extracting file.  To install from a floppy disk
(720k or greater), copy file to disk and log to drive, enter: G_TED20

To install, log to drive/directory that contains extracted files and 
enter: INSTALL

Documentation: README.TXT and G_TED.DOC

72.24VXTST6::BOURDESSWed Jun 30 1993 14:385
    does anyone have an unzipper I could copy?
    
    	thanx much,  
    
    		Mike
72.25gzip/gunzipLANDO::HAPGOODWed Jun 30 1993 14:408
                     <<< Note 72.24 by VXTST6::BOURDESS >>>
>    does anyone have an unzipper I could copy?
    
I have a tar file with gzip/gunzip (gnu zip and unzip).  It's unix.

let me know and i'll make it available...
bob

72.26VXTST6::BOURDESSWed Jun 30 1993 14:468
    I'm kinda confused on this matter.  If the software is meant for DOS,
    does it have to be unzipped in a DOS environment?  Right now I have the
    zip file in a vms area.  Can I unzip it and copy to a dos machine, or
    do I have to copy it to a DOS machine *then* unzip it.  If the first
    method will work, then I can copy it to unix and use the unzipper
    mentioned in -.1...right?
    
    	Mike
72.27you can unpack it anywhere if your unzippers workNRSTA2::CLARKWed Jun 30 1993 14:566
I have unzippers that work for both DOS and VMS, but I usually find the one on
DOS to be more reliable ... the DOS versions are updated more frequently.

Let me know if you want it and I can copy the DOS version to my public dir.

- DC
72.28CSCMA::M_PECKARTwo pints make one cavortWed Jun 30 1993 15:5721
>    I'm kinda confused on this matter.  If the software is meant for DOS,
>    does it have to be unzipped in a DOS environment?  Right now I have the
>    zip file in a vms area.  Can I unzip it and copy to a dos machine, or
>    do I have to copy it to a DOS machine *then* unzip it.  If the first
>    method will work, then I can copy it to unix and use the unzipper
>    mentioned in -.1...right?
    
You can do either, but the prefered method would be to unzip it on the 
local machine to decrease the chances of data corruption (the more data you 
xfer between different machines, the more chances for corruption).

This program would be great if it came with a data entry operator. I figure
it would take me, oh, one man-year to load YADB (yet another database) with
all my tapes. Also, if I understand it correcty, it has no cross reference
to a Deadbase-like database of all setlists, so you can't make any queries
like "how many of all known Cosmic Charlies do I have on tape", or "Is this
tape I just entered a complete show or not", or even "The playin' on this
tape is 23 minutes long, which show is it from".  :-) 

Fog_staying_tuned_for_the_DB_software_from_the_deadbase_folks...
72.29works on DOSNRSTA2::CLARKWed Jun 30 1993 16:143
I copied PKUNZIP.EXE to NRSTA2::USER03:[CLARK.PUBLIC]

- dc
72.30ZENDIA::FERGUSONYour recipe is so tastyThu Jul 01 1993 10:014
DC, you might wanna just use ZIP2EXE and make that sucker into a self-extracting
zip file.  this way, you don't even need PKUNZIP


72.31NRSTA2::CLARKThu Jul 01 1993 10:226
Ah, I was *wondering* what that ZIP2EXE.EXE program was in my applications
directory!  :^}

Done ... NRSTA2::USER03:[CLARK.PUBLIC]G_TED20.EXE

- dc
72.32MR4MI2::REHILLTree&#039;s Name Here - Call 226-6165Fri Jul 02 1993 09:154
    I've heard that there is a Dancing Bears Screen Saver out on the
    internet. Anyone got a copy of that?
    
    
72.33NRSTA2::CLARKTue Jul 06 1993 10:345
I have it in NRSTA2::USER03:[CLARK.PUBLIC]DBEAR.EXE (self-extracting archive).
Unfortunately it needs a VBRUN200.DLL ... I'm tracking that down now (unless
someone has it on his/her PC already hint hint) ....

- DC
72.34MR4MI2::REHILLTree&#039;s Name Here - Call 226-6165Tue Jul 06 1993 13:263
    Kevin Flannagan mailed me a copy, I have it running now!
    
    
72.35zipped vbrun availableSSGV01::STROBEL&amp; now for something completely different...Tue Jul 06 1993 18:038
    I've put a zipped copy of VBRUN200.DLL in a public account for those
    who want/need it. Copy from:
    
    ssgv02::disk$user09:[strobel.public]vbrun200.ZIP
    
    enjoy
    
    jeff
72.36warning: 200 block CD_PLAYER.C (that I can't link!)PONDA::64423::BELKINthe slow one now will later be fastTue Jan 18 1994 10:192718
I'm still dinking around with the RRD-42 CD player programs.
I found the following program CD_PLAYER.C in the CDROM notes file.
It has volume and balance, which the one in the DEC$examples area 
(DECW$CDPLAYER.C) does not.
However I'm having major problems linking it!   I make a link_CD.com
that looks like:

$!-------------------------------------------
$ define/nolog c$include decw$examples,decw$include,sys$library
$ define/nolog vaxc$include c$include
$
$! cc CD_PLAYER                   
$
$ link CD_PLAYER, sys$input/opt, sys$share:decw$dxmlibshr/share, -
sys$share:decw$xmlibshr/share, sys$share:decw$xlibshr/share, 
sys$share:vaxcrtl/share
$
$!-------------------------------------------

which is just from the CD_PLAYER.C (a few lines down in the comments).
However when I try to link, this bombs out because we don't have .OBJs in
the sys$share area, only .EXEs.  How does this work?

I have:

12X5> dir sys$share:decw$dxmlibshr*
Directory SYS$COMMON:[SYSLIB]
DECW$DXMLIBSHR.EXE;2   948  19-MAY-1992 23:04:32.57


So how can I link this?

Also, there was mention in the CDROM notes file that you really didn't need
privs (PHY_IO and DIAGNOSE are needed for DECW$CDPLAYER.C) for the 
CD_PLAYER.C, that you can just go ahead and run it.    Does anyone have such
a program? 

 thanks, Josh
---------------------------------------------------------------------------
/*
           <<< CDROM::DISK$LAYERED:[NOTES$LIBRARY]CD_READER.NOTE;1 >>>
                           -< CD Reader Technology >-
================================================================================
Note 237.14                how to play audio on RRD42                   14 of 16
DENVER::BOYLES                                     2671 lines  20-JUL-1992 17:38
                       -< CD-player (VMS) with volume. >-
--------------------------------------------------------------------------------
*/  
/*
    Below is a VMS audio CD_PLAYER I wrote, which provides volume and
    balance controls to the CD display.  It does require a minimum of
    VMS V5.4-2, though.
*/
    
#define	CONVENIENCE_ROUTINES	0	/* Compile routines = 1, else 0	     */
/*============================================================================= 
! Program:	CD_PLAYER.C	(Version 1.0 revision 20)
! Author:	Gary Boyles	(Englewood, CO  USA)
! Date:		15-JUN-1992	17:00
!
!
! Modification History:
!	Revision	Reason					  Date
!	--------	-------------------------------------	--------
!	V1.0 -17	Initially finished		(gpb)	11/21/91
!	     -18	Plugged some memory-leaks	(gpb)	01/03/92
!	     -19	Modularized things a bit more	(gpb)	06/05/92
!	     -20	Added the following:		(gpb)	06/15/92
!			a) Descending time-remaining scale.
!			b) track-max label to "Track Now Playing"
!			c) Total play-time printf statement.
!			d) MSF-related convenience routines
!			   (present for example -- not used).
!                                    
!             
! Description:
!	This program acts as a control panel for a SCSI audio CD player. It
!	creates a workstation window panel with buttons for:           
!		eject	= stop playing/enable-eject/eject-caddy from player
!		stop	= stop the player from playing & enable-eject
!	    	play	= start playing CD on current track & disable-eject
!	   	pause	= pause/resume the CD-player      
!		replay  = replay the current selection
!		shuffle = play random selections
!		exit	= stop playing/enable eject(but don't)/exit program
!		incr	= increment track playing 
!		decr	= decrement track playing
!
!	The program also creates the following scales/sliders/displays:
!		current-track playing
!		track-time display
!		track-time remaining display
!		volume control/display
!		channel-balance control/display
!                                 
!  	Note that the volume thumb-wheel should be on full-volume, because
!	the slider will only control volume upto what the thumb-wheel is
!	set to.
!                             
! 	The program uses MOTIF toolkit routines to create and manage the
!	display and its widgets.  This program was tested with an RRD42
!	on a VMS workstation running VMS DECW MOTIF V1.0 & VMS V5.4-2
!	and VMS V5.5
!
!	Currently the following improvements are necessary:
!	  1)  Better random # generator		(currently not so random)
!	  2)  Some error-trapping code		(currently quite minimal)
!
!	In the program listing (frontend) refers for the most part to MOTIF
!	routines, and (backend) refers to CD-control routines.  Routines
!	starting with "handle_" are the button/arrow/slider callback
!	routines.
!                                    
!	In regard to routines getting executed... it happens via two methods:
!	  1)  Pushing a button or moving the slider (activating a callback)
!	  2)  Via the timer routine "the_timer".
!
!	Commands to build this program are (VMS):
!	========================================
!	$ define/nolog c$include decw$examples,decw$include,sys$library
!	$ define/nolog vaxc$include c$include
!	$
!	$ cc CD_PLAYER                   
!	$
!	$ link CD_PLAYER, sys$input/opt
!	sys$share:decw$dxmlibshr/share
!	sys$share:decw$xmlibshr/share
!	sys$share:decw$xlibshr/share
!	sys$share:vaxcrtl/share
!	$
!                                                                 
!	The program interfaces to the CD player through the SCSI disk driver.
!	If you assume that the CD-player is device DKB400 then you would
!	have to do the following before running the program (with privs):
!                                                            
!	$ DEFINE DECW$CD_PLAYER DKB400:
!
!	Note:
!	To change the icon resources for the CD-player, edit your
!	"mwm" file (on VMS this is DECW$MWM.DAT).  For example:
!	
!		Mwm*CD*iconImageForeground:	Firebrick
!		Mwm*CD*iconImageBackground:	Yellow
!
!
!	Thanks goes to Stephen N. Davis for his help.
!===========================================================================*/
                                             
#include <stdio.h>                                  
                             
#include <Xm/MainW.h>	    	    	/* MainWindow Class	    	*/
#include <Xm/BulletinB.h>		/* BulletinBoard Class		*/
#include <Xm/Frame.h>			/* Frame widget class		*/
#include <Xm/Label.h>			/* Label class			*/
#include <Xm/PushB.h> 			/* Push-button Class		*/
#include <Xm/RowColumn.h>		/* RowColumn Class		*/
#include <Xm/Scale.h>	    	  	/* Scale class			*/   

/*===============================(Frontend)===================================
! Symbolic Constants                           
!====================*/ 
#define SHOW_CD_TIME		1	/* 1 = show ttl play time on CD	*/
                                            
#define ICON_LABEL		"Audio"	/* Cd-player Icon label		*/

#define TIMER_INTERVAL		1000	/* How often?  1000 = 1/second	*/
        
#define CD_TRACK_MIN		0	/* Lower limit for track select	*/
#define CD_TRACK_MAX   		99	/* Upper limit for track select	*/

#define BALANCE_SCALE_MAX	10	/* Balance max (min = -max)	*/

#define VOLUME_OFF		  0	/* Volume Completely Off	*/
#define VOLUME_DEFAULT		200	/* Initial volume-setting	*/
#define VOLUME_MINIMUM		155 	/* Lower limit for volume level	*/
#define VOLUME_MAXIMUM		255	/* Upper limit for volume level	*/
          
#define PUSH_BUTTON		0	/* Used in Create_Button	*/
#define ARROW_LEFT		1	/* Used in Create_Button	*/
#define ARROW_RIGHT		2	/* Used in Create_Button	*/
                                                          
#define SHADOW_THICKNESS	4
#define BOTTOM_SHADOW_COLOR		"DimGrey"
#define TOP_SHADOW_COLOR		"White"
                
#define DEFAULT_FOREGROUND		"Firebrick"
#define DEFAULT_BACKGROUND		"AntiqueWhite3"

#define DEF_PUSHBUTTON_BACKGROUND	"Black"		/* Defaults	*/
#define DEF_PUSHBUTTON_FOREGROUND	"White"

#define BUTTON_HEIGHT	  	40
#define BUTTON_WIDTH		100

#define ALT_PUSHBUTTON_BACKGROUND	"Firebrick"	/* Alternate	*/
#define ALT_PUSHBUTTON_FOREGROUND	"Yellow"

#define ARROW_FOREGROUND		"Chocolate"
#define ARROW_BACKGROUND		"IndianRed4"

#define SCALE_FOREGROUND		DEFAULT_FOREGROUND
#define SCALE_BACKGROUND		DEFAULT_BACKGROUND
#define SCALE_TOP_SHADOW		DEFAULT_FOREGROUND
#define SCALE_BOTTOM_SHADOW 		DEFAULT_FOREGROUND

#define TRACK_TIME_FOREGROUND		DEF_PUSHBUTTON_FOREGROUND
#define TRACK_TIME_BACKGROUND		"NavyBlue"                 

#define	FALSE			0
#define TRUE			1
#define NOT_USED		-1
#define	VERTICAL_SCALE		1
#define HORIZONTAL_SCALE	2

/*===========================================================================
! Define bitmap for the icon used for the cd-player.
!===========================================================================*/
             
#define SMALL_ICON_WIDTH	32
#define SMALL_ICON_HEIGHT	32
static	char small_icon_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xf8, 0x00,
   0x00, 0x01, 0x08, 0x01, 0x80, 0x00, 0x08, 0x02, 0x80, 0x00, 0x08, 0x04,
   0x80, 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04,
   0x80, 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04,
   0x80, 0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x02, 0x00, 0x01, 0x08, 0x01,
   0x00, 0x7e, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00, 0x00, 0x08, 0x80, 0x00,
   0x00, 0x08, 0x80, 0x00, 0x00, 0x08, 0x87, 0x00, 0x00, 0x88, 0x8f, 0x00,
   0x00, 0xc8, 0x9f, 0x00, 0x00, 0xc8, 0x9f, 0x00, 0x00, 0xc8, 0x9f, 0x00,
   0x00, 0x88, 0x8f, 0x00, 0x00, 0x08, 0x87, 0x00, 0x00, 0x08, 0x80, 0x00,
   0x00, 0xf8, 0xff, 0x00, 0x00, 0xf8, 0xff, 0x00};
             
#define MEDIUM_ICON_WIDTH	50
#define MEDIUM_ICON_HEIGHT	50
static	char medium_icon_bits[] = {
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0x0f, 0x7c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07,
   0x7c, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xe3, 0x7f, 0x8e, 0xff, 0xff, 0xff,
   0xff, 0xf3, 0x7f, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x7f, 0x9e, 0xff,
   0xff, 0xff, 0xff, 0xf3, 0x7f, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x7f,
   0x9e, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x7f, 0x9e, 0xff, 0xff, 0xff, 0xff,
   0xe3, 0x7f, 0x8e, 0xff, 0xff, 0xff, 0xff, 0x07, 0x7c, 0xc0, 0xff, 0xff,
   0xff, 0xff, 0x0f, 0x7c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0x07, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0xc0,
   0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xfc, 0xff, 0xff,
   0xff, 0xc9, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xcc, 0xff, 0x3f, 0xff,
   0xff, 0xff, 0x7f, 0xce, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x3f, 0xcf, 0xff,
   0xcf, 0xff, 0xff, 0xff, 0x9f, 0xcf, 0xff, 0x07, 0x00, 0x00, 0x00, 0xc0,
   0xcf, 0xff, 0x07, 0x00, 0x00, 0x00, 0xe0, 0xcf, 0xff, 0xe7, 0xff, 0xff,
   0xff, 0xe7, 0xcf, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe7, 0xcf, 0xff, 0xe7,
   0xff, 0xff, 0xff, 0xe7, 0xcf, 0xff, 0x67, 0x00, 0x00, 0x00, 0xe7, 0xcf,
   0xff, 0x67, 0xff, 0xff, 0x7f, 0xe7, 0xcf, 0xff, 0x67, 0xff, 0xff, 0x7f,
   0xe7, 0xcf, 0xff, 0x67, 0x00, 0x00, 0x00, 0xe7, 0xcf, 0xff, 0xe7, 0xff,
   0xff, 0xff, 0xe7, 0xe7, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xe7, 0xf3, 0xff,
   0xe7, 0xf9, 0xff, 0x1f, 0xe7, 0xf9, 0xff, 0xe7, 0xf9, 0xff, 0x1c, 0xe7,
   0xfc, 0xff, 0xe7, 0xff, 0xff, 0xff, 0x67, 0xfe, 0xff, 0xe7, 0xff, 0xff,
   0xff, 0x27, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0x07,
   0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff};
             
#define LARGE_ICON_WIDTH	75
#define LARGE_ICON_HEIGHT	75
static	char large_icon_bits[] = {
   0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xfd, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa, 0x55, 0x55, 0x55, 0x55,
   0x55, 0x55, 0x55, 0x55, 0x55, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xfa, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
   0x55, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa,
   0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xfd, 0xaa, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xfa, 0xd5, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x60, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xfa, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
   0x65, 0xfd, 0xaa, 0xea, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xfa,
   0xd5, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x64, 0xfd, 0xaa, 0x2a,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xaa, 0xfa, 0xd5, 0x25, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x80, 0x64, 0xfd, 0xaa, 0xea, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xaa, 0xfa, 0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
   0x65, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa,
   0xd5, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x65, 0xfd, 0xaa, 0x0a,
   0xaa, 0xaa, 0xaa, 0xaa, 0x02, 0x80, 0xaa, 0xfa, 0xd5, 0x65, 0x05, 0x40,
   0x55, 0x55, 0x05, 0x00, 0x65, 0xfd, 0xaa, 0x6a, 0x0a, 0x80, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xfa, 0xd5, 0x05, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
   0x65, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa,
   0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xfd, 0xaa, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xfa, 0x55, 0x55, 0x55, 0x55,
   0x55, 0x55, 0x55, 0x55, 0x55, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xfa, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
   0x55, 0xfd, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa,
   0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xfd, 0xaa, 0xaa,
   0xfe, 0xff, 0x01, 0xf0, 0xff, 0xaf, 0xaa, 0xfa, 0x55, 0x55, 0xff, 0xff,
   0xff, 0xff, 0xff, 0x5f, 0x55, 0xfd, 0xaa, 0xaa, 0x9f, 0xaa, 0xaa, 0xaa,
   0xaa, 0xbe, 0xaa, 0xfa, 0x55, 0x55, 0x4f, 0x55, 0x01, 0x50, 0x55, 0x3d,
   0x55, 0xfd, 0xaa, 0xaa, 0xa7, 0x2a, 0xbe, 0x82, 0xaa, 0xba, 0xaa, 0xfa,
   0x55, 0x55, 0x53, 0x85, 0x5f, 0x15, 0x54, 0x35, 0x55, 0xfd, 0xaa, 0xaa,
   0xab, 0xea, 0xbf, 0xaa, 0xaa, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x57, 0xf1,
   0x5f, 0x55, 0x51, 0x35, 0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xfa, 0xbf, 0xaa,
   0xaa, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x57, 0xfc, 0x5f, 0x55, 0x45, 0x35,
   0x55, 0xfd, 0xaa, 0xaa, 0x2b, 0xfe, 0xbf, 0xaa, 0xaa, 0xba, 0xaa, 0xfa,
   0x55, 0x55, 0x57, 0xff, 0x5f, 0x55, 0x55, 0x35, 0x55, 0xfd, 0xaa, 0xaa,
   0x2b, 0xff, 0xbf, 0xaa, 0x8a, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x97, 0xff,
   0x5f, 0x55, 0x15, 0x35, 0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xff, 0x07, 0xa8,
   0x2a, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x97, 0xff, 0xf3, 0x51, 0x55, 0x35,
   0x55, 0xfd, 0xaa, 0xaa, 0xcb, 0xff, 0xf9, 0xa3, 0x2a, 0xba, 0xaa, 0xfa,
   0x55, 0x54, 0xd7, 0xff, 0xfc, 0x47, 0x55, 0x35, 0x55, 0xfd, 0xaa, 0xaa,
   0xcb, 0xff, 0xfe, 0xaf, 0x2a, 0xba, 0xaa, 0xfa, 0x55, 0x54, 0xd7, 0xff,
   0xfe, 0x4f, 0x55, 0x35, 0x55, 0xfd, 0xaa, 0xa8, 0x8b, 0xaa, 0xfe, 0xaf,
   0x3f, 0xba, 0xaa, 0xfa, 0x55, 0x40, 0x57, 0x55, 0xfe, 0xcf, 0x7f, 0x35,
   0x55, 0xfd, 0xaa, 0xaa, 0x8b, 0xaa, 0xfe, 0xef, 0x7f, 0xba, 0xaa, 0xfa,
   0x55, 0x54, 0x57, 0x55, 0xfc, 0xe7, 0x7f, 0x35, 0x55, 0xfd, 0xaa, 0xaa,
   0x8b, 0xaa, 0xf8, 0xf3, 0x7f, 0xba, 0xaa, 0xfa, 0x55, 0x54, 0x17, 0x55,
   0xf1, 0xf9, 0x7f, 0x35, 0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xaa, 0x02, 0xfc,
   0xbf, 0xba, 0xaa, 0xfa, 0x05, 0x54, 0x17, 0x55, 0x55, 0xff, 0x3f, 0x35,
   0x55, 0xfd, 0x02, 0xaa, 0x2b, 0xaa, 0xaa, 0xff, 0x9f, 0xba, 0xaa, 0xfa,
   0x01, 0x54, 0x57, 0x55, 0x55, 0xff, 0x5f, 0x35, 0x55, 0xfd, 0x02, 0xaa,
   0x2b, 0xaa, 0xaa, 0xff, 0xaf, 0xba, 0xaa, 0xfa, 0x05, 0x55, 0x57, 0x55,
   0x55, 0xff, 0x47, 0x35, 0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xa8, 0xaa, 0xff,
   0xab, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x57, 0x51, 0x55, 0xff, 0x55, 0x35,
   0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xa2, 0xaa, 0xfe, 0xa8, 0xba, 0xaa, 0xfa,
   0x55, 0x55, 0x57, 0x15, 0x55, 0x3f, 0x55, 0x35, 0x55, 0xfd, 0xaa, 0xaa,
   0xab, 0x2a, 0xa8, 0x82, 0xaa, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0x57, 0x55,
   0x01, 0x50, 0x55, 0x35, 0x55, 0xfd, 0xaa, 0xaa, 0xab, 0xaa, 0xaa, 0xaa,
   0xaa, 0xba, 0xaa, 0xfa, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
   0x55, 0xfd, 0xaa, 0xaa, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xaa, 0xfa,
   0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0xfd, 0xaa, 0xaa,
   0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xfa, 0x55, 0x55, 0x55, 0x55,
   0x55, 0x55, 0x55, 0x55, 0x55, 0xfd};


Pixmap 					/* The CD-player icon		*/
	cd_icon;

             
globalvalue
	IO$_AVAILABLE,
	IO$_PACKACK,
	IO$_DIAGNOSE;


/*================================(Backend)===================================
!  SCSI Generic Class Driver #Defines & Variables
!===============================================*/

static char	gk_device [] = {"DECW$CD_PLAYER"};                          

short    gk_chan;
              
/*------------------------------------
! CD-ROM SCSI operation command codes           
!-------------------------------------*/
#define SCSI_STATUS_MASK	0X3E
#define MEDIA_OPCODE		0x1E 
#define MODE_SELECT_OPCODE	0X15
#define PAUSE_OPCODE		0X4B
#define RESUME_OPCODE		0X4B
#define STOP_OPCODE		0x1B
#define READ_SUBCHAN_OPCODE	0X42
#define READ_TOC_OPCODE		0X43                             
#define PLAY_TRACK_OPCODE	0X48
#define PLAYBACK_CONTROL_OPCODE 0XC9
#define PLAYBACK_STATUS_OPCODE	0XC4

#define READ 1
#define WRITE 0

                                                                             
/*  Varibles for saving CD-player state
!======================================*/                               
                                                 
static int
	saved_track_time_sec,
	track_time_sec,			/* Playing time for this track	*/
	total_tracks	= 0,		/* Total track read off this CD	*/
	saved_total_tracks = 0,
	current_track	= 0,		/* Track now playing		*/
	saved_current_track = 0,	/* Track we thought was playing	*/
	random_track	= 0,		/* Track # generated for SHUFFLE*/
	old_random_track= 0,		/* Saved (old) random_track	*/ 
	random_total 	= 0,		/* # of random tracks to SHUFFLE*/
	current_volume	= 0,		/* Current volume-level		*/
	left_volume	= 0,		/* Current left-channel setting	*/
	right_volume	= 0,		/* Current right-channel setting*/
	play_flag 	= FALSE,	/* Flags set/reset by pressing	*/
	cd_paused	= FALSE,	/* the various pushbuttons	*/
	saved_cd_paused	= FALSE,
      	shuffle_flag	= FALSE;
                    
static	unsigned int Track_Address[CD_TRACK_MAX];
			/* Save the start address of each CD track	*/

static	int	Track_Seconds [CD_TRACK_MAX];                           
		      	/* Track time (seconds) for each track on CD	*/

                            
/*============================================================================ 
!  (Frontend) Routines  
!=====================*/

void	init_icon();			/* Setup CD icon		*/
                                                                          
int	String_To_Pixel(),		/* String to Pixel Conversion	*/
	get_icon_size();		/* Which icon-size is needed	*/

Widget	Create_Button(),		/* Create button or arrow	*/
    	Create_Scale(),			/* Create a horizontal scale	*/
	Create_Label();			/* Create a label		*/
        
/*===========================================================================
!  (Frontend to Backend) Routines  
!================================*/

void
	handle_eject_button(),		/* EJECT   button callback	*/
	handle_stop_button(),		/* STOP    button callback	*/
	handle_play_button(),		/* START   button callback	*/
	handle_pause_button(),		/* PAUSE   button callback	*/
	handle_replay_button(),		/* REPLAY  button callback	*/
	handle_shuffle_button(),	/* SHUFFLE botton callback	*/
	handle_exit_button(),		/* EXIT    button callback	*/
   	handle_track_decr(),		/* DECRement CD track callback 	*/
	handle_track_incr(),		/* INCRement CD track callback	*/
	handle_track_scale(),		/* Track-input slider callback	*/
	handle_time_scale(),		/* Track-time  slider callback	*/
	handle_volume_scale(),	   	/* Volume-input slider callback	*/
	handle_balance_scale();		/* Balance-input slider callback*/

/*===========================================================================
!  Backend Routines
!==================*/
        
void
	the_timer(),		  	/* Master program timer		*/
	update_track_time(),		/* Update Track-Time Display	*/
	update_time_scale_max(),	/* Size time-scale to tracktime	*/
    	update_track_info(),	 	/* Update track scale and data	*/
	update_track_max(),		/* Update track-max label	*/
	init_track_scale(),		/* Init track-scale  display	*/
	init_volume_and_balance(),	/* Init volume/balance display	*/
	set_volume_and_balance(),	/* Set CD volume/balance levels	*/
	reset_pause_button(),		/* Reset label to PAUSE		*/
	toggle_pause_label(),		/* Toggle label PAUSE/RESUME	*/
	do_shuffle();			/* Do the actual track shuffle	*/
                              
int	get_random_track();		/* Random number generator	*/


/*===========================================================================
!  (Backend) CD-player specific Routines
!=======================================*/
unsigned int	read_CD_capacity(),	/* # of blocks on current CD	*/
		read_toc_track();	/* Returns start-addr for track	*/

int	read_toc(),	       		/* Get CD table-of-contents	*/
	setup_default_block_size(),	/* Set block size = 512		*/
	play_track(char track_num),	/* Play a track on the CD	*/
	play_MSF(),                     /* Mins/sec/frame format play	*/
	play_partial_track(),		/* Plays portion of a track	*/
	pause_cd(),			/* Suspend playing		*/
	resume_cd(),			/* Resume  playing		*/
	stop_unit(),			/* Stop the CD player		*/
	eject_cd(),			/* Eject the CD			*/
	enable_eject(),			/* Allow manual removal of CD	*/
   	disable_eject();		/* Don't allow manual removal	*/

void	get_volume(),			/* Get current volume of player	*/
	set_volume(),			/* Set the volume of the player	*/
	get_status(),			/* Read CD table-of-contents	*/
	save_track_time(),		/* Save track-time of CD tracks	*/
    	bpt();				/* Null Routine			*/

/*===========================================================================
! VMS specific routines
!======================*/

int	execute_command();	       	/* Sends the actual SCSI cmds	*/
		  			/* to the CD-player		*/
void    exit_handler(),			/* Stop CD/Deassign Channel/etc	*/
	alloc_cd_channel(),    		/* Assigns a channel to CD	*/
    	dealloc_cd_channel();		/* Deassign CD channel		*/


/*===========================================================================
!  List of Widgets (Frontend)
!============================*/
                               
Widget                
	toplevel,
	main_window,
	work_area,
	rc,
	eject_button,
	stop_button,
	play_button,
	pause_button,
	replay_button,
	shuffle_button,
	exit_button,
	decrArrow,
	incrArrow,
	volume_scale,
	balance_scale,
	track_scale,
	time_scale,
	trackMax,
	trackTime,
	trackFrame,
	trackLabel,
	arrowsLabel;

                                            
/*===========================================================================*/
/*===========================================================================*/
/* Other Declarations       
!====================*/
static	Display	*display;		/* Holds display id		*/

XtAppContext ctx;
  
Pixel	color;
       
Arg	args[20];

int	n;		       		/* Generic arg counter		*/

unsigned long int random_number = 1;	/* Holds random numbers required*/
					/* for SHUFFLE operation	*/
                                                             
/*===========================================================================*/
/*===========================================================================*/
/*===========================================================================*/
/*===========================================================================*/
/*                             BEGIN MAIN ROUTINE                            */
                     
main(argc, argv)        
  int argc;                     
                                                                          
  char **argv;

{
  
  /*=======================================================================
  ! Create our application shell, and our main window.
  !=======================================================================*/
  toplevel = XtInitialize(		/* Create ApplicationShell	*/
	"Audio",			/* Name				*/
	"CD",				/* Class			*/
	NULL,			  	/* Options			*/
	0,	       			/* Number of options		*/
	&argc,				/* Address of argc		*/
	argv);				/* Arg value			*/


  main_window = XmCreateMainWindow (	/* Create main-window		*/
      	toplevel,			/* Parent			*/
	"Main",	 			/* name				*/
	args, 0);	  		/* args, # of args		*/

  XtManageChild(main_window);

  display = XtDisplay(toplevel);


  /*=======================================================================
  ! Create a bulletin-board as our work-area, and manage via a row-column
  !=======================================================================*/
  n = 0;				/* Set bulletin-board resources	*/
  XtSetArg( args[n], XmNwidth,  580); ++n;
  XtSetArg( args[n], XmNheight, 100); ++n;
  XtSetArg( args[n], XmNresizePolicy, XmRESIZE_NONE); ++n;  

  color = String_To_Pixel (DEFAULT_BACKGROUND);
  XtSetArg( args[n], XmNbackground, color); ++n;

  work_area = XmCreateBulletinBoard (	/* Create bulletin-board	*/
	main_window,			/* Parent			*/
	"Work",				/* name				*/
	args, n);			/* args, # of args.		*/

  XtManageChild(work_area);
              
  n = 0;				/* Init arg count		*/
  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n;	/* Lay it flat  */
  XtSetArg(args[n], XmNpacking, XmPACK_TIGHT);	++n;	/* How to pack	*/
  XtSetArg( args[n], XmNspacing, 5);	++n;
  XtSetArg( args[n], XmNx, 150);	++n;    
  XtSetArg( args[n], XmNy, 85);	 	++n;                       

  color = String_To_Pixel (DEFAULT_BACKGROUND);
  XtSetArg( args[n], XmNbackground, color); ++n;
 
  rc = XmCreateRowColumn (		/* Create row-col widget inst	*/
	work_area,	   		/* Parent			*/
	"RowCol",			/* Name				*/
	args, n);	  		/* Arglist, Arg count		*/

  XtManageChild(rc);
                 
                  
  /*=======================================================================
  ! Now create a EJECT (i.e. EJECT the CD) pushbutton.
  !   Inputs:	parent, name/label, PUSH_BUTTON/ARROW_LEFT/ARROW_RIGHT,
  !		X, Y, height, width, foreground, background, display-id
  !=======================================================================*/
                                                                       
  eject_button = Create_Button (rc, " EJECT ", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
			DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(eject_button);                     
  XtAddCallback(eject_button, XmNactivateCallback, handle_eject_button, NULL);
  

  /*=======================================================================
  ! Now create a STOP (i.e. STOP the CD) pushbutton.
  !   Inputs:	parent, name/label, PUSH_BUTTON/ARROW_LEFT/ARROW_RIGHT,
  !		X, Y, height, width, foreground, background, display-id
  !=======================================================================*/
                                                                       
  stop_button = Create_Button (rc, " STOP ", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
	     		DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(stop_button);                                 
  XtAddCallback(stop_button, XmNactivateCallback, handle_stop_button, NULL);
                                                                

  /*=======================================================================
  ! Now create a PLAY  CD pushbutton.
  !=======================================================================*/
                        
  play_button = Create_Button (rc, "  PLAY  ", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
			DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(play_button);
  XtAddCallback(play_button, XmNactivateCallback, handle_play_button, NULL);
                                                   

  /*=======================================================================
  ! Now create a PAUSE (i.e. pause/resume selection) pushbutton.
  !=======================================================================*/

  pause_button = Create_Button (rc, "PAUSE  ", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
			DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(pause_button);
  XtAddCallback(pause_button, XmNactivateCallback, handle_pause_button, NULL);


  /*=======================================================================
  ! Now create a REPLAY (i.e. play last song) pushbutton.
  !=======================================================================*/

  replay_button = Create_Button (rc, "REPLAY", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
			DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(replay_button);
  XtAddCallback(replay_button, XmNactivateCallback, handle_replay_button, NULL);

                            
  /*=======================================================================
  ! Add in SHUFFLE pushbutton.
  !=======================================================================*/
                                  
  shuffle_button = Create_Button (rc, "SHUFFLE", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			DEF_PUSHBUTTON_FOREGROUND,
			DEF_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(shuffle_button);              
  XtAddCallback(shuffle_button,XmNactivateCallback,handle_shuffle_button, NULL);
                            

                            
  /*=======================================================================
  ! Add in EXIT pushbutton.
  !=======================================================================*/
                                  
  exit_button = Create_Button (rc, "  EXIT  ", PUSH_BUTTON,
		       	NOT_USED, NOT_USED, BUTTON_HEIGHT, BUTTON_WIDTH,  
			ALT_PUSHBUTTON_FOREGROUND, 
		    	ALT_PUSHBUTTON_BACKGROUND, display);
  XtManageChild(exit_button);
  XtAddCallback(exit_button, XmNactivateCallback, handle_exit_button, NULL);
                            
           
  /*=======================================================================
  ! Add decrement-track Arrow button.
  !=======================================================================*/
                                                                          
  decrArrow = Create_Button (work_area, "DECR", ARROW_LEFT,
     		   	170, 15, 40, 60,           
			ARROW_FOREGROUND,
			ARROW_BACKGROUND, display);
  XtManageChild(decrArrow);          
                              
  XtAddCallback(decrArrow, XmNactivateCallback, handle_track_decr, NULL);
                            
           
  /*=======================================================================
  ! Add increment-track Arrow button.
  !=======================================================================*/
  
  incrArrow = Create_Button (work_area, "INCR", ARROW_RIGHT,
		 	240, 15, 40, 60,
			ARROW_FOREGROUND,
		 	ARROW_BACKGROUND, display);

  XtManageChild(incrArrow);          
                              
  XtAddCallback(incrArrow, XmNactivateCallback, handle_track_incr, NULL);
                                                
                                 
  /*=======================================================================
  ! Add a scale widget to show current volume-level set on the CD.
  !   Inputs:	parent, name/label, X, Y, scale-size, 
  !		scale-min, scale-max, initial scale value,
  !		foreground color, background color,
  !		bottom shadow color, top shadow color,
  !	    	display-id
  !                            
  ! Note:  Start scale at 0, no matter what the actual volume-level min
  !	   value is.
  !=======================================================================*/
                
  volume_scale = Create_Scale (work_area, "Volume", "    Volume Level",
  		0, 1, 130,
  		VOLUME_MINIMUM - VOLUME_MINIMUM,
       		VOLUME_MAXIMUM - VOLUME_MINIMUM,
	   	VOLUME_DEFAULT - VOLUME_MINIMUM,
	   	DEFAULT_FOREGROUND, DEFAULT_BACKGROUND,
       		BOTTOM_SHADOW_COLOR,  TOP_SHADOW_COLOR,
		HORIZONTAL_SCALE, display);
                          
  XtManageChild(volume_scale);
                              
  XtAddCallback(volume_scale,XmNvalueChangedCallback,handle_volume_scale, NULL);
                
  balance_scale = Create_Scale (work_area, "Balance", "(L)    Balance    (R)",
  		0, 70, 130,        
 		-BALANCE_SCALE_MAX, BALANCE_SCALE_MAX, 0,          
	   	DEFAULT_FOREGROUND, DEFAULT_BACKGROUND,
       		BOTTOM_SHADOW_COLOR,  TOP_SHADOW_COLOR,	
		HORIZONTAL_SCALE, display);
                          
  XtManageChild(balance_scale);
                              
  XtAddCallback(balance_scale , XmNvalueChangedCallback,
		handle_balance_scale, NULL);

                                          
  /*=======================================================================
  ! Add a scale widget to show current TRACK-SELECTED on the CD.
  !   Inputs:	parent, name/label, X, Y, scale-size, 
  !		scale-min, scale-max, initial scale value,
  !	      	foreground color, background color,
  !		bottom shadow color, top shadow color,
  !	    	display-id       
  !
  !   Note:	Scale can also be used to change track #.
  !=======================================================================*/
                
  track_scale = Create_Scale (work_area, "This_Track",
		"      Track Now Playing",
  		320, 1, 180,                           
    		CD_TRACK_MIN, CD_TRACK_MAX, CD_TRACK_MIN,
      	   	DEFAULT_FOREGROUND, DEFAULT_BACKGROUND,
       		BOTTOM_SHADOW_COLOR,  TOP_SHADOW_COLOR,	
		HORIZONTAL_SCALE, display);             
                                     
  XtManageChild(track_scale);                               
                              
  XtAddCallback(track_scale,XmNvalueChangedCallback,handle_track_scale, NULL);

                                          
  /*=======================================================================
  ! Add a scale widget to show track-time
  !=======================================================================*/
                
  time_scale = Create_Scale (work_area, "Time_Scale", "",
  		625, 20, 20,                           
  		0, 999, 0,
      	   	DEFAULT_FOREGROUND, DEFAULT_BACKGROUND,
       		BOTTOM_SHADOW_COLOR,  TOP_SHADOW_COLOR,	
		VERTICAL_SCALE, display);             
                                     
  XtManageChild(time_scale);                               
                              
  XtAddCallback(time_scale, XmNvalueChangedCallback,
		handle_time_scale, NULL);
                
                                                    
  /*=======================================================================
  ! Add label widgets to display highest track.
  !   Inputs:	Parent, Name, Actual Label, x,Y, height, width,    
  !	    	foreground color, background color, display id.
  !=======================================================================*/
  n = 0;
  trackMax = Create_Label (work_area, "TM", "99", 500, 25, 30, 30,
			DEFAULT_FOREGROUND,
			DEFAULT_BACKGROUND, display);            
         
  XtManageChild(trackMax);     
                                                    
  /*=======================================================================
  ! Add Frame widget to frame the  TRACK-TIME.   
  !   Inputs:	Parent, Name, Actual Label, x,Y, height, width,    
  !	    	foreground color, background color, display id.
  !=======================================================================*/
                
  n = 0;					/* Init arg count	*/
  XtSetArg( args[n], XmNx, 550);	++n;	/* X Location		*/
  XtSetArg( args[n], XmNy, 20);	 	++n;	/* Y Location		*/
         
  XtSetArg( args[n], XmNshadowType,		/* Type of frame effect	*/
		XmSHADOW_ETCHED_IN);	++n;
              
  color = String_To_Pixel (TOP_SHADOW_COLOR);	/* Frame shadow colors	*/
  XtSetArg( args[n], XmNtopShadowColor, color);	++n;

  color = String_To_Pixel (BOTTOM_SHADOW_COLOR);
  XtSetArg( args[n], XmNbottomShadowColor, color); ++n;
                                             
  XtSetArg( args[n], XmNshadowThickness, SHADOW_THICKNESS+2); ++n;
 
  trackFrame = XmCreateFrame (		/* Create Frame widget inst	*/
	work_area,	   		/* Parent			*/
	"tFrame",			/* Name				*/
	args, n);	  		/* Arglist, Arg count		*/

  XtManageChild(trackFrame);

                                                    
  /*=======================================================================
  ! Add label widgets to display TRACK-TIME.   
  !   Inputs:	Parent, Name, Actual Label, x,Y, height, width,    
  !	    	foreground color, background color, display id.
  !=======================================================================*/
  n = 0;
  trackTime = Create_Label (trackFrame, "L1", "00:00", 0, 0, 30, 60,
			TRACK_TIME_FOREGROUND,
			TRACK_TIME_BACKGROUND, display);
         
  XtManageChild(trackTime);     
  

  /*=======================================================================
  ! Add label widget to add label to track-time display.
  !=======================================================================*/
                                        
  trackLabel = Create_Label (work_area, "L2", "Track Time",
   			540, 55, 30, 70,       
			DEFAULT_FOREGROUND,
			DEFAULT_BACKGROUND, display);            
                               
  XtManageChild(trackLabel);     
  

  /*=======================================================================
  ! Add label widget to add label to Incr/Decr Arrows.
  !=======================================================================*/
                                        
  arrowsLabel = Create_Label (work_area, "L3", "Select Track",
			165, 55, 30, 140,       
     			DEFAULT_FOREGROUND,
			DEFAULT_BACKGROUND, display);            
                             
  XtManageChild(arrowsLabel);     

                     
  /*=======================================================================
  ! Now lets realize everything, allocate the CD, setup our timer
  ! (typically to run once per second), and go into our event loop
  !=======================================================================*/
  
  XtRealizeWidget (toplevel);	/* Lets bring all the widgets up	*/
  
  init_icon();			/* Setup the Cd-player icon		*/
  
  alloc_cd_channel();		/* Allocate a channel for the CD	*/
  
  setup_default_block_size();
  
  the_timer ();			/* And start the clock timer		*/

  update_time_scale_max();	/* Make sure time_scale is correct	*/
  
  enable_eject ();		/* Allow eject until unit is started	*/
                   
  init_volume_and_balance ();	/* Get current volume-levels from CD	*/
				/* And set the balance/volume sliders	*/
  
  XtMainLoop ();                                                

}

/*                              END MAIN ROUTINE                            */
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/
/*==========================================================================*/

            
/*============================================================================
!  init_icon Routine.
!  Initialize/select the CD-reader icon.  The icons that have been included
!  in this program are of equal width and height, and the code assumes this
!  (i.e. if icon changes are made, then coding changes may also have to
!  be made).
!============================================================================*/
                            
void	init_icon()                                                      

{
  int		i,
		icon_size;
  Arg	      	ArgL [2];                               
  Window	icon_window_id = XtWindow(main_window);


  icon_size = get_icon_size();			/* 0=none set		*/

  if (icon_size == 0 ||
      icon_size < MEDIUM_ICON_WIDTH)	    	/* Use smallest icon	*/
    {
    cd_icon = XCreateBitmapFromData(display,
    			icon_window_id,
    			small_icon_bits,                  
    			SMALL_ICON_WIDTH,
    			SMALL_ICON_HEIGHT);
    }
  else
    {
    if (icon_size < LARGE_ICON_WIDTH)		/* Use medium icon	*/
      {
      cd_icon = XCreateBitmapFromData(display,
    			icon_window_id,
    			medium_icon_bits,                  
      			MEDIUM_ICON_WIDTH,
    			MEDIUM_ICON_HEIGHT);
      }
    else					/* Use largest icon	*/
      {
      cd_icon = XCreateBitmapFromData(display,
    			icon_window_id,
    		    	large_icon_bits,                  
      			LARGE_ICON_WIDTH,
    			LARGE_ICON_HEIGHT);
      }
    }

  i = 0;
  XtSetArg (ArgL[i], XmNiconPixmap, cd_icon);	i++;	/* Set PIXMAP	*/
  XtSetArg (ArgL[i], XmNiconName, ICON_LABEL);	i++;	/* And label	*/
  XtSetValues (toplevel, ArgL, i);
     
}                                    

     
/*============================================================================
!  get_icon_size Routine.
!  Get the size of the icon in-use.  Return the largest dimension.
!============================================================================*/

int get_icon_size ()

{
  XIconSize	*size_list;
  int		num_sizes,
		status;
  Window	root_window = XDefaultRootWindow (display);

  status = XGetIconSizes (display, root_window, &size_list, &num_sizes);

  if (status == 0)			/* If no icon-size set then	*/
    {					/* return 0.  Otherwise return	*/
    return 0;				/* the greater dimension...	*/
    }					/* icon-width or icon-height	*/
  else
    {
    if (size_list->max_width > size_list->max_height)
      {
      return size_list->max_width;
      }                           
    else
      {
      return size_list->max_height;
      }
    }
 
}

                         
/*============================================================================
! Create_Button Routine.
! Routine to create the Push or Arrow Buttons on the CD.  The widget-name
! is returned.  Note that X & Y locations are only used if > 0.
!============================================================================*/

Widget Create_Button (
	Widget 	theParent,		/* Name of parent		*/
	char	theName[],		/* Name of the button		*/
	int	button_type,		/* Push or Arrow left/right	*/
       	int	xLoc,			/* X location in window		*/
	int	yLoc,			/* Y location in window		*/
	int    	height,			/* Height (in pixels) of button	*/
       	int	width, 			/* Width (in pixels) of button	*/
	char	f_color[],  		/* Foreground color 		*/
	char	b_color[], 		/* Background color 		*/
	Display *dpy)			/* Display id			*/   
                                     
{	
  Widget	wgt;			/* Widget instance produced	*/
  Pixel		color;			/* Pixel color fore/back ground	*/
  Arg	   	ArgL[20];		/* Argument list	 	*/
  int		i;

  i = 0;				/* Init arg count		*/
                                                      
  if (xLoc > NOT_USED) {
    XtSetArg( ArgL[i], XmNx, xLoc); ++i;	/* X position for button*/
  }

  if (yLoc > NOT_USED) {
    XtSetArg( ArgL[i], XmNy, yLoc); ++i;	/* Y position for button*/
  }
  
  XtSetArg( ArgL[i], XmNheight, height); ++i;	/* Height (in pixels)	*/
  XtSetArg( ArgL[i], XmNwidth, width); ++i;	/* Width  (in pixels)	*/
  
  color = String_To_Pixel (f_color);		/* Get (pixel) color	*/
  XtSetArg( ArgL[i], XmNforeground,color); ++i;	/* Set foreground color	*/
                                         
  color = String_To_Pixel (b_color);		/* Get (pixel) color 	*/
  XtSetArg( ArgL[i], XmNbackground,color); ++i;	/* Set background color	*/
                       
  color = String_To_Pixel (BOTTOM_SHADOW_COLOR);
  XtSetArg( ArgL[i], XmNbottomShadowColor, color); ++i;
                       
  color = String_To_Pixel (TOP_SHADOW_COLOR);
  XtSetArg( ArgL[i], XmNtopShadowColor, color); ++i;

  XtSetArg( ArgL[i], XmNshadowThickness, SHADOW_THICKNESS); ++i;
  
  XtSetArg( ArgL[i], XmNrecomputeSize, True); ++i;
                     
  if (button_type == PUSH_BUTTON)	/* Standard PushButton?		*/
    {					/*   (Yes)			*/
      wgt = XmCreatePushButton(			/* Create Pushbutton	*/
      	theParent,				/* Parent		*/
      	theName,				/* Name			*/
	ArgL, i);		   	     	/* Arglist, Arg count	*/
    }
  else					/*   (No)			*/
    {					/*   Must be an Arrow Button.	*/
      if (button_type == ARROW_RIGHT) 		/* set RIGHT direction	*/
	{
	  XtSetArg( ArgL[i], XmNarrowDirection,
		XmARROW_RIGHT); ++i;          
	}   
      else					/* (or)			*/
	{      					/* set LEFT  direction	*/
	  XtSetArg( ArgL[i], XmNarrowDirection,
		XmARROW_LEFT); ++i;    
	} 
						/* (Now)		*/
      wgt = XmCreateArrowButton(		/* Create Arrow Button	*/
	theParent,				/* Parent		*/
      	theName,				/* Name			*/
	ArgL, i);	   	     		/* Arglist, Arg count	*/
    }

  return(wgt);				/* Return pushbutton/widget.	*/
} 

                                 
/*============================================================================
! Create_Scale Routine.
! Add a scale widget to show current TRACK-SELECTED on the CD.
!   Inputs:	parent, name, title/label, X, Y, scale-size,
!		scale-min, scale-max, initial scale value,
!		bg color, fg color,
!		bottom shadow color, top shadow color,
! 	     	display-id
!============================================================================*/
                
Widget Create_Scale (   
	Widget	theParent,		/* Name of parent		*/
	char	theLabel[],		/* Name of the scale		*/
	char	theTitle[],		/* Title/label of the scale	*/
  	int	xLoc,			/* X location in window		*/
	int	yLoc,			/* Y location in window		*/
       	int	sSize,			/* Size of the scale (pixels)	*/
	int	sMin,			/* Scale minimum value		*/
	int	sMax,			/* Scale maximum value		*/
	int	sInit,			/* Scale initial value		*/
	char	sf_color[],  		/* Foreground color 		*/
	char	sb_color[], 		/* Background color 		*/
	char	bs_color[], 		/* Bottom shadow color		*/
	char	ts_color[], 		/* Top    shadow color		*/
	int	s_orientation,		/* vertical or horizontal	*/
	Display *dpy)			/* Display id			*/
  
{	
  Widget	wgt;			/* Widget instance produced	*/
  Pixel		color;			/* Pixel color			*/
  XmString	Ctitle;			/* Compound-string for title	*/
  Arg	   	ArgL[20];		/* Argument list	 	*/
  int		i;

  i = 0;				/* Init arg count		*/
                                           
  XtSetArg( ArgL[i], XmNsensitive, True); ++i;	/* Allow input		*/
  
  XtSetArg( ArgL[i], XmNx, xLoc); ++i;	/* X position for scale.	*/
  XtSetArg( ArgL[i], XmNy, yLoc); ++i;	/* Y position for scale.	*/
                                       
  XtSetArg( ArgL[i], XmNscaleWidth, sSize); ++i;/* How big is scale	*/
  XtSetArg( ArgL[i], XmNshowValue, True); ++i;	/* Do show value	*/
                               
  XtSetArg( ArgL[i], XmNminimum, sMin);	++i;	/* Min scale		*/
  XtSetArg( ArgL[i], XmNmaximum, sMax); ++i;	/* Max scale		*/
  XtSetArg( ArgL[i], XmNvalue,  sInit);	++i;	/* Initital scale value	*/

  color = String_To_Pixel (sf_color);		/* Get (pixel) color	*/
  XtSetArg( ArgL[i], XmNforeground,color); ++i;	/* Set foreground color	*/

  color = String_To_Pixel (sb_color);		/* Get (pixel) color 	*/
  XtSetArg( ArgL[i], XmNbackground,color); ++i;	/* Set background color	*/

  color = String_To_Pixel (bs_color);		/* Get (pixel) color 	*/
  XtSetArg( ArgL[i], XmNbottomShadowColor,color); ++i;
 
  color = String_To_Pixel (ts_color);		/* Get (pixel) color 	*/
  XtSetArg( ArgL[i], XmNtopShadowColor,color);	++i;
  XtSetArg( ArgL[i], XmNshadowThickness, SHADOW_THICKNESS);  ++i;
                         
  Ctitle = XmStringCreateSimple (theTitle);	/* Compound-str title	*/
  XtSetArg( ArgL[i], XmNtitleString, Ctitle); ++i;  /* Set Scale title	*/

  if (s_orientation == VERTICAL_SCALE)                    
    {
    XtSetArg( ArgL[i], XmNorientation, XmVERTICAL);	++i;
    }
  else
    {
    XtSetArg( ArgL[i], XmNorientation, XmHORIZONTAL);	++i;
    }
                                                  
  wgt = XmCreateScale(			/* Create Scale			*/
      	theParent,			/* Parent			*/      
      	theLabel,			/* Name				*/      
	ArgL, i);		   	/* Arglist, Arg count		*/      

  XmStringFree (Ctitle);		/* Free up memory for title 	*/
       
  return(wgt);				/* Return scale/widget		*/
}                                        
       
                        
/*============================================================================
! Create_Label Routine.
! Add a label widget.  Inputs to this routine are:
!   Parent, Name of widget, Label, X, Y, height, width, colors & display-id.
!============================================================================*/

Widget Create_Label (   
  	Widget	theParent,		/* Name of parent		*/
	char  	theName[],		/* Name of the label		*/
	char	theLabel[],		/* Text for the label		*/
	int	xLoc,	       		/* X location in window		*/
     	int	yLoc,			/* Y location in window		*/
	int	height,			/* height of label.		*/
  	int	width,			/* width of the label		*/
	char	f_color[],  		/* Foreground color 		*/
	char	b_color[], 		/* Background color 		*/
	Display *dpy)			/* Display id			*/
{	
  Widget	wgt;			/* Widget instance produced	*/
  Pixel		color;			/* Pixel color			*/
  XmString	Clabel;			/* Compound-string label	*/
  Arg	   	ArgL[10];     		/* Argument list	 	*/
  int		i;

  i = 0;

  color = String_To_Pixel (f_color);
  XtSetArg( ArgL[i], XmNforeground, color); ++i;
                                     
  color = String_To_Pixel (b_color);
  XtSetArg( ArgL[i], XmNbackground, color); ++i;
       
  XtSetArg( ArgL[i], XmNx, xLoc);  ++i;		/* X position 		*/
  XtSetArg( ArgL[i], XmNy, yLoc);  ++i;		/* Y position 		*/
  XtSetArg( ArgL[i], XmNheight, height);++i;	/* Height (in pixels)	*/
  XtSetArg( ArgL[i], XmNwidth, width);	++i;	/* Width  (in pixels)	*/
                       
  XtSetArg( ArgL[i], XmNlabelType, XmSTRING); ++i;

  Clabel = XmStringCreateSimple (theLabel);	/* Compound-str label	*/
  XtSetArg( ArgL[i], XmNlabelString, Clabel); ++i;	/* Set string	*/
       
  wgt = XmCreateLabel(			/* Create Label Widget instance	*/
	theParent,	       		/* Parent			*/
       	theName,		       	/* Name				*/
	ArgL, i);			/* Arglist, Arg count		*/

  XmStringFree (Clabel);		/* Free up memory from string	*/

  return(wgt);				/* Return Label widget		*/
}

    
/*============================================================================
! String_To_Pixel Routine.
! This routine returns a pixel value when passed a named color.
!   Note:  Variable "display" has been previously declared.
!============================================================================*/

String_To_Pixel(char *spec)

{
  int i;
  Colormap cmap;               
   
  XColor color_struct;

  cmap = XDefaultColormap(display, DefaultScreen(display));

  i    = XParseColor(display, cmap, spec, &color_struct);
  i    = XAllocColor(display, cmap, &color_struct);
                          
  return(color_struct.pixel);
}

                                       
/*============================================================================
! handle_eject_button Routine.  Eject the current cd playing.
!============================================================================*/
                                          
void handle_eject_button(        
  	Widget wgt,
    	caddr_t client_data,
  	XmAnyCallbackStruct *call_data)
{
  play_flag 	= FALSE;	/* Set flag to show not started		*/
  cd_paused	= FALSE;	/* CD is not paused			*/
  shuffle_flag	= FALSE;	/* Not in shuffle mode			*/
  enable_eject();		/* Allow the CD to program-eject	*/
  stop_unit();			/* Spin down the CD (if playing)	*/
  eject_cd();			/* Eject the CD				*/
  reset_pause_button();		/* Set label to PAUSE & flag = FALSE	*/
  init_track_scale();		/* Init "track now playing" display	*/
}

                                          
/*============================================================================
! handle_stop_button Routine.  Stop the current cd playing.
!============================================================================*/
                                          
void handle_stop_button(
  	Widget wgt,
    	caddr_t client_data,
  	XmAnyCallbackStruct *call_data)                                   
{
  play_flag 	= FALSE;	/* Set flag to show not started		*/
  cd_paused	= FALSE;	/* CD is not paused			*/
  shuffle_flag	= FALSE;	/* Not in shuffle mode			*/
  stop_unit();			/* Spin down the CD (if playing)	*/
  reset_pause_button();		/* Set label to PAUSE & flag = FALSE	*/
  enable_eject();		/* Allow  removal of CD			*/
}          

          
/*============================================================================
! handle_play_button Routine.  Start CD on track 1.
!============================================================================*/
                                          
void handle_play_button(
	Widget wgt,
    	caddr_t client_data,
	XmAnyCallbackStruct *call_data)
{                                                        
  play_flag 	= TRUE;		/* Set flag to show now-playing		*/
  cd_paused	= FALSE;	/* CD is not paused			*/
  shuffle_flag	= FALSE;	/* Not in shuffle mode			*/
  reset_pause_button();		/* Make sure CD is not paused		*/
  get_status();			/* Get information about current CD	*/
  XmScaleGetValue (track_scale, &current_track);  /* Get track #	*/
  play_track(current_track);	/* Start the CD playing			*/
  set_volume_and_balance();	/* Set volume and balance levels on CD	*/
  disable_eject();		/* Disable CD eject.			*/
  update_time_scale_max();	/* Set time-scale to correct setting	*/
}

          
/*============================================================================
! handle_pause_button Routine.
! Pause the current CD, and change the button label from "PAUSE" to "RESUME"
! (or) if on "RESUME" then start CD and change button label to "PAUSE".
!============================================================================*/
                                          
void handle_pause_button(
	Widget wgt,
    	caddr_t client_data,                             
	XmAnyCallbackStruct *call_data)
{ 

  if (play_flag  == TRUE)
    {                       
    if (cd_paused == FALSE)	/* Were we paused already?		*/
      {				/* (No)					*/
      cd_paused = TRUE;		/* Set Flag				*/
      toggle_pause_label();	/* Change the button label		*/
      pause_cd();		/* Send PAUSE command to CD		*/
      } 
    else                          
      {				/* (Yes -- we were paused already)	*/
      cd_paused = FALSE;	/* Reset the flag			*/
      toggle_pause_label();	/* Change the button label		*/
      resume_cd();		/* Send RESUME command to CD		*/
      }
    }
} 

          
/*============================================================================
! handle_replay_button Routine.  Replay the current track on the CD.
!============================================================================*/
                                          
void handle_replay_button(
	Widget wgt,
    	caddr_t client_data,
	XmAnyCallbackStruct *call_data)

{                    

  shuffle_flag = FALSE;		/* Not in shuffle mode			*/

  if (play_flag  = TRUE && cd_paused == FALSE)
    {
    play_track(current_track);	/* Play the current track again		*/
    set_volume_and_balance();	/* Set volume and balance levels on CD	*/
    disable_eject();		/* Disable removal of CD		*/
    }
}
    
          
/*============================================================================
! handle_shuffle_button Routine.   
! Play tracks in a random order.  Keep playing in a random order until some
! other button is pushed, or until total_tracks * n are played.
!===========================================================================*/
                                          
void handle_shuffle_button(                                        
	Widget wgt,
    	caddr_t client_data,                       
	XmAnyCallbackStruct *call_data)

{   

  if (play_flag  == TRUE && cd_paused == FALSE)  
    {
      shuffle_flag = TRUE;
      do_shuffle();			/* Play a random track		*/
    }
}
                
          
/*===========================================================================
! handle_exit_button Routine.  Used to exit the program.
!===========================================================================*/
                                          
void handle_exit_button(
	Widget wgt,
    	caddr_t client_data,            
	XmAnyCallbackStruct *call_data)
                               
{
    XtCloseDisplay(XtDisplay(wgt));	/* Get rid of CD panel display	*/
    enable_eject();			/* Allow the CD to eject	*/
    dealloc_cd_channel();		/* Deassign the channel		*/
    exit(0);				/* Bye-Bye			*/
}


/*============================================================================
! handle_track_decr Routine.
! Callback for the << arrow button.  Decrement the track count by one, and
! update the display.  If track count is less than track-min, then set to
! track-max.
!============================================================================*/

void handle_track_decr 	(
	Widget wgt,
	caddr_t client_data,
  	XmAnyCallbackStruct *call_data)
                           
{                                
  int	this_track,               
	next_track;
                       
  shuffle_flag = FALSE;			/* Not in shuffle-mode		*/
                       
  if (play_flag  == TRUE && cd_paused == FALSE)  
    {
      XmScaleGetValue (track_scale, &this_track);
                                 
      next_track = --this_track;  

      if (next_track < 1)
        {          
          next_track = total_tracks;	
        }     
                                            
      play_track (next_track);		/* Start track playing		*/
      set_volume_and_balance();		/* Set vol & bal levels on CD	*/
    }                  
}


/*============================================================================
! handle_track_incr Routine.                      
! Callback for the >> arrow button.  Increment the track count by one, and
! update the select-track display. If track count is greater than track-max,
! then set to track-min.
!============================================================================*/
                       
void handle_track_incr	(  
	Widget	wgt,                                  
	caddr_t	client_data,
	XmAnyCallbackStruct	*call_data)
                   
{                                
  int 	this_track,              
	next_track;

  shuffle_flag = FALSE;			/* Hot in shuffle-mode		*/
              
  if (play_flag  == TRUE && cd_paused == FALSE)  
    {
      XmScaleGetValue (track_scale, &this_track);
  
      next_track = this_track + 1;

      if (next_track > total_tracks)
        {
          next_track = 1;
        }     

      play_track (next_track); 		/* Start track playing	      	*/
      set_volume_and_balance();		/* Set vol & bal levels on CD	*/
    }
}
                       

/*============================================================================
! handle_time_scale Routine.                      
! Callback for track-time slider input.
!============================================================================*/

void handle_time_scale (  
	Widget	wgt,                                  
	caddr_t	client_data,
	XmAnyCallbackStruct	*call_data)
                     
{                                

}                       


/*============================================================================
! handle_track_scale Routine.                      
! Callback for track-slider input.  Get new slider value, and update the
! CD playing.  This allows the slider to be used for input, as well as output.
!============================================================================*/
      
void handle_track_scale (  
	Widget	wgt,                                  
	caddr_t	client_data,
	XmAnyCallbackStruct	*call_data)
                     
{                                
  int	this_track;

  shuffle_flag = FALSE;			/* Hot in shuffle-mode		*/

  if (play_flag  == TRUE && cd_paused == FALSE)  
    {             
      XmScaleGetValue (track_scale, &this_track);
      play_track (this_track);		/* Start track playing		*/
      set_volume_and_balance();		/* Set vol & bal levels on CD	*/
    }
}
  
  
/*============================================================================
! handle_volume_scale Routine.                      
! Callback for volume-slider input.  Get the slider-value from the display
! panel, and update the actual volume-level in the cd-player.  Note that
! the volume-slider starts at 0 (i.e. VOLUME_DEFAULT - VOLUME_MINIMUM) while
! the actual volume-level put into the CD starts at VOLUME_MINIMUM.
!============================================================================*/
                   
void handle_volume_scale (  
	Widget	wgt,                                  
	caddr_t	client_data,
  	XmAnyCallbackStruct	*call_data)

{                                
  set_volume_and_balance();		/* Set vol & bal levels on CD	*/
} 


/*============================================================================
! handle_balance_scale Routine.                      
! Callback for balance-slider input.  Get the slider-value from the display
! panel, and set the balance between the left and right channels
! (i.e. channels 0 & 1).
!============================================================================*/
                   
void handle_balance_scale (  
	Widget	wgt,                                  
	caddr_t	client_data,
  	XmAnyCallbackStruct	*call_data)
          
{                                                      
  set_volume_and_balance();		/* Set vol & bal levels on CD	*/
}
  

/*============================================================================
! the_timer Routine.
! This routine is a timer which runs, gets the track-time status, updates
! the track-time, and then registers itself as a timeout callback to be
! called again.  This routine is executed once every TIMER_INTERVAL, which
! is typically every one second.
!
! The routine also handles automatic track SHUFFLE after the initial
! button-press.
! 
! Note:	The CD-player will automatically go to the next track after the
!	current track is finished playing.
!============================================================================*/
      
void the_timer ()
                           
{                     
  if (shuffle_flag == TRUE)			/* Are we shuffling CD	*/
    {						/* (yes)... did the CD	*/
      if (current_track != random_track)	/* player shift to next	*/
        {					/* track? (yes)... get	*/
        do_shuffle();				/* another random one	*/
        random_total = random_total + 1;	/* BUT... let's not	*/
        if (random_total >= total_tracks*4)	/* play on forever	*/
          {           
          shuffle_flag = FALSE; 
          random_total = 0;
          stop_unit();
          }           
        }
    }    

  get_status();					/* Get CD status	*/
  update_track_info();				/* Inc track/time scale	*/
  update_track_time();				/* and track-time clock*/
  get_volume();					/* Get current volume	*/
  XtAddTimeOut (TIMER_INTERVAL, the_timer);	/* & reset timeout	*/
} 
     

/*============================================================================
! update_track_time Routine.
! This is the common routine for updating the track-time display.
! It is called by the one second timer routine as well as by the button
! callback routines. If the player state has changed, then update the
! appropriate button/slider on the display.
!============================================================================*/
            
void update_track_time ()                                                 
                 
{ 
  Arg		ArgL[5];                                              
  char		track_time_char[6];
  XmString	the_track_time;
  int		track_time_min,
		time_remaining,
		max_time,
  		i = 0;  
     

  /*=====================================================================
  ! 1st lets update the track-time display                               
  !====================================================================*/

	track_time_min = track_time_sec / 60;	/* Figure out time	*/
	track_time_char [0] = track_time_min / 10 + '0';
	track_time_char [1] = track_time_min % 10 + '0';
	track_time_char [2] = ':';
	track_time_char [3] = (track_time_sec % 60) / 10 + '0';
	track_time_char [4] = (track_time_sec % 60) % 10 + '0';
	track_time_char [5] = '\0';
                                    
	the_track_time = XmStringCreateSimple (track_time_char);           
						/* cvt to compound str	*/

	XtSetArg( ArgL[i], XmNlabelString, the_track_time); ++i;
						/* Set arg for new time	*/
	XtSetValues(trackTime, ArgL, i);	/* Update time-display	*/
                         
	XmStringFree (the_track_time);		/* Recover memory	*/

   /*=====================================================================
   ! And now the track-time scale
   !====================================================================*/

	time_remaining = Track_Seconds [current_track] - track_time_sec ;
	XmScaleGetValue (time_scale, &max_time);  /* Get scale-max	*/

	if (time_remaining > max_time)		/* Make sure we don't	*/
	  {					/* exceed scale		*/
	  i = 0;
	  XtSetArg( ArgL[i], XmNmaximum, time_remaining); i++;
	  XtSetValues(time_scale, ArgL, i);	/* Do display update	*/
	  }

  	XmScaleSetValue (time_scale, time_remaining);

}                               
                         
                                                
/*============================================================================
! update_time_scale_max Routine.                 
! Update/reset the maximum value on the time_scale.
!============================================================================*/
                                     
void update_time_scale_max()

{                                              
  int		i = 0;
  Arg	 	ArgL[5];

  XtSetArg( ArgL[i], XmNminimum, 0);		++i;
  XtSetArg( ArgL[i], XmNvalue,   0);		++i;

  if (Track_Seconds[current_track] > 0 && current_track > 0)
    {
    XtSetArg( ArgL[i], XmNmaximum, Track_Seconds[current_track]); ++i;
    }
  else
    {
    XtSetArg( ArgL[i], XmNmaximum, 999);	++i;
    }

  XtSetValues(time_scale, ArgL, i);	/* Do display update	*/
}
  
/*============================================================================
! update_track_max Routine.                 
! Update the label that shows the max track # on the current CD.
!============================================================================*/
     
void update_track_max()

{                                              
  int		i;
  Arg		ArgL[5];
  char		track_max_char[3];
  XmString	the_track_max;

  track_max_char[0] = (total_tracks/10) + '0';	/* Stuff into string	*/
  track_max_char[1] = total_tracks % 10 + '0';
  track_max_char[2] = '\0';

  the_track_max = XmStringCreateSimple (track_max_char);           
						/* cvt to compound str	*/

  i = 0;
  XtSetArg( ArgL[i], XmNlabelString, the_track_max); ++i;
						/* Set arg for new time	*/
  XtSetValues(trackMax, ArgL, i);		/* Update track-max dpy	*/
              
  XmStringFree (the_track_max);			/* Recover memory	*/
}
            
  
/*============================================================================
! update_track_info Routine.                 
! This is the common routine that does the following:
!   1)  Updates display if necessary.
!   2)  Check to see if old CD has been removed (and updates display).
!   3)  If there is a new CD... we save the track time for each track.
!============================================================================*/
     
void update_track_info()

{                                              
  Arg	ArgL[5];			/* Argument list	 	*/
  int	i = 0,				/* Argument counter		*/
	this_track;			/* Track # from track_scale	*/


  /* Make sure track_scale reflects the current track playing
  !==========================================================*/
  XmScaleGetValue (track_scale, &this_track);

  if (this_track != current_track)
    {
    XmScaleSetValue (track_scale, current_track);
    }                       

  /* If the old CD is gone then make sure track-scale max is still ok
  !==================================================================*/
           
  if (saved_total_tracks != total_tracks)	/* We've removed old CD	*/
    {
      if (total_tracks == 0)			/* No CD		*/
  	{
	  saved_total_tracks = 0;
	  init_track_scale();                
	  update_track_max();
	}     
      else					/* New CD		*/
	{         
	  saved_total_tracks = total_tracks;
	  i = 0;
      	  XtSetArg( ArgL[i], XmNmaximum, total_tracks); ++i;
	  XtSetValues(track_scale, ArgL, i);	/* Do display update	*/

	  save_track_time ();		/* Save track-time for each	*/
					/* track on CD (Track_Time[])	*/
	  update_track_max();		/* Display total-tracks on CD	*/
	}
    }
}                                
  
                                                       
/*============================================================================
! init_track_scale Routine.
! Initialize the scale (i.e. set track-slider to initial values).
!============================================================================*/

void init_track_scale ()    

{
  Arg		ArgL[5];  		/* Argument list	 	*/
  int		i, 			/* Argument counter		*/
		track_max;		/* Top-end for the scale.	*/

  i = 0;
  
  if (total_tracks > CD_TRACK_MIN)	/* If there's a CD mounted...	*/
    {					/* then use its track-count	*/
      track_max = total_tracks;		/* to define the scale		*/
    }
  else
    {
      track_max = CD_TRACK_MAX;
    }                
                     
  /* Update scale	*/
  /*====================*/
    XtSetArg( ArgL[i], XmNminimum, CD_TRACK_MIN);	++i;
    XtSetArg( ArgL[i], XmNvalue,   CD_TRACK_MIN);	++i;  
    XtSetArg( ArgL[i], XmNmaximum, track_max);		++i;                  
    XtSetValues (track_scale, ArgL, i);
    current_track = CD_TRACK_MIN;
}   
                  
                             
/*============================================================================
! init_volume_and_balance routine
! Initialize the balance and volume sliders.  Try and use the current settings
! off of the cd-player itself.  Note:  get_volume() modifies the variables
! current_volume, left_volume, and right_volume.
!============================================================================*/

void init_volume_and_balance ()

{
  int	L_volume,
	R_volume,
	C_volume,
	balance_setting;

  get_volume ();  			/* Get values off of cd-player	*/
  L_volume = left_volume;
  R_volume = right_volume;
  C_volume = current_volume;

  if (L_volume < VOLUME_MINIMUM)	/* We need default values for	*/
	L_volume = VOLUME_DEFAULT;	/* slider calculations		*/

  if (R_volume < VOLUME_MINIMUM)
      	R_volume = VOLUME_DEFAULT;

  if (C_volume < VOLUME_MINIMUM)
      	C_volume = VOLUME_DEFAULT;


  /*---------------------------------------------------
  ! Calculate the correct balance-slider setting from
  ! the actual volume levels gotten from the cd-player.
  !----------------------------------------------------*/
  if (L_volume > R_volume)
    {
    balance_setting = -BALANCE_SCALE_MAX +
			(BALANCE_SCALE_MAX * (R_volume - VOLUME_MINIMUM))/   
    		       	(L_volume  - VOLUME_MINIMUM);
    }
  else
    {
    if (L_volume < R_volume)
      {               
      balance_setting = BALANCE_SCALE_MAX - 
			(BALANCE_SCALE_MAX * (L_volume - VOLUME_MINIMUM))/
		     	(R_volume - VOLUME_MINIMUM); 
      }    
    else                                    
      {
      balance_setting = 0;
      }
    }

  /*---------------------------------------------------
  ! Now set the balance and volume sliders.
  !----------------------------------------------------*/
  XmScaleSetValue (balance_scale, balance_setting);

  XmScaleSetValue (volume_scale, C_volume - VOLUME_MINIMUM );
}


/*============================================================================
! set_volume_and_balance Routine.                      
! Get the balance-level, and the volume-level, and set the CD accordingly.
! Note that the volume is set to (VOLUME_MINIMUM + volume_scale), unless
! scale is zero, and then volume is set to zero.
! (i.e. channels 0 & 1).
!============================================================================*/

void set_volume_and_balance()          

{
int	new_balance,
	new_volume,
	L_volume,
	R_volume;

  XmScaleGetValue (volume_scale,  &new_volume);		/* Get volume	*/

  if (new_volume == 0)			/* If scale is 0... then turn	*/
    {					/* volume all the way off	*/
    current_volume = VOLUME_OFF;
    left_volume    = VOLUME_OFF;
    right_volume   = VOLUME_OFF;
    }
  else					/* Else set to minimum + scale	*/
    { 
    current_volume = new_volume + VOLUME_MINIMUM;

    XmScaleGetValue (balance_scale, &new_balance);	/* Get balance	*/

    if (new_balance <= 0)		/* Convert to volume levels for	*/
      {					/* left and right channels	*/
      L_volume = current_volume;                      
      R_volume = current_volume +
  	 	(((current_volume - VOLUME_MINIMUM)
		* new_balance)/ BALANCE_SCALE_MAX );
      }       
    else                                           
      {
      L_volume = current_volume -
  		(((current_volume - VOLUME_MINIMUM)
		* new_balance)/ BALANCE_SCALE_MAX );
      R_volume = current_volume;                      
      }
    left_volume = L_volume;		/* Save left-channel  volume	*/
    right_volume= R_volume;		/* Save right-channel volume	*/
    }

  set_volume(left_volume, right_volume);/* Go out and actually change	*/
					/* the volume on the CD-player	*/

}
     
     
/*============================================================================
! reset_pause_button Routine.
! Reset the PAUSE button (i.e. make sure it says PAUSE, and make sure that
! "cd_paused" is set to FALSE.
!============================================================================*/
  
void reset_pause_button ()

{
  Pixel		color;			/* Needed for changing bg color	*/
  XmString	Cpause;			/* Compound-str for pause label	*/
  Arg	   	ArgL[5];		/* Argument list	 	*/
  int		i;     			/* Arg count			*/

  i = 0;	       			/* Init arg count		*/
                  
  cd_paused = FALSE;			/* Reset flag			*/
  color = String_To_Pixel ("Black");		/* Get (pixel) color 	*/      
  XtSetArg( ArgL[i], XmNbackground,color); ++i;	/* Reset color		*/
  Cpause = XmStringCreateSimple ("PAUSE  ");	/* Cvt to compound-str	*/
  XtSetArg( ArgL[i], XmNlabelString, Cpause); ++i;  /* Reset to "PAUSE"	*/
  XtSetValues (pause_button, ArgL, i);		/* Actually do changes	*/
  XmStringFree (Cpause);			/* Free memory for str	*/
} 

     
/*============================================================================
! toggle_pause_label Routine.
! Change the pause button from PAUSE to RESUME, or RESUME to PAUSE.
!============================================================================*/
  
void toggle_pause_label ()
                            
{
  Pixel		color;			/* Needed for changing bg color	*/
  XmString	Clabel;			/* Compound string for label	*/
  Arg	   	ArgL[5];	      	/* Argument list	 	*/
  int		i;		       	/* Arg count			*/


  i = 0;	       			/* Init arg count		*/

  if (cd_paused == FALSE)
    {                
      color = String_To_Pixel ("Black");	/* Get (pixel) color 	*/
      XtSetArg( ArgL[i], XmNbackground,color); ++i;	/* Set color	*/
      Clabel = XmStringCreateSimple ("PAUSE  ");	/* Create str	*/
      XtSetArg( ArgL[i], XmNlabelString, Clabel); ++i;	/* Set label	*/
    }
  else
    {                
      color = String_To_Pixel (DEFAULT_FOREGROUND);	/* Get  color	*/
      XtSetArg( ArgL[i], XmNbackground,color); ++i;	/* Set color	*/
      Clabel = XmStringCreateSimple ("RESUME");		/* Create str	*/
      XtSetArg( ArgL[i], XmNlabelString, Clabel); ++i;	/* Set label	*/
    }

  XtSetValues (pause_button, ArgL, i);		/* Actually do changes	*/
  XmStringFree (Clabel);			/* Free memory for str	*/
}
                                   

/*============================================================================
! do_shuffle Routine.
! Get a random track between 1 and total_tracks.  Set the current track #
! to that track, and then play the current_track.  Only do a shuffle if a
! CD in the player.
!============================================================================*/

void	do_shuffle ()                  

{

  if (total_tracks > 0)				/* Is CD present?	*/
    {
    random_track = get_random_track();		/* Get any track #	*/
    while (random_track == old_random_track)	/* Make sure it's not	*/
      {						/* the one we just	*/
      random_track = get_random_track();	/* played		*/
      } 
    play_track (random_track);		/* Play the track		*/
    set_volume_and_balance();		/* Set vol & bal levels on CD	*/
    old_random_track = random_track;	/* Save track #			*/
    current_track = random_track;	/* Set current-track #		*/
  }
}

                                
/*============================================================================
! get_random_track Routine.
! Routine which returns a random track number between 1 and
! total_tracks.  Note:  We need a better random # generator (but not now).
!============================================================================*/

int get_random_track()                                                   
                  
{                                               
  random_number = (random_number/(current_track+1))                       
			* 1103515245 + 12345;
  return (((unsigned int) (random_number/65536) % total_tracks)+1); 
}


/*============================================================================
! setup_default_block_size Routine.
! This routine changes the default block size of the CD player
! to 512 bytes and is required for correct callibration of 
! the track time. The mode select command is tried three times
! because if the device has just been reset, the first two will
! fail.                                              
!============================================================================*/

int setup_default_block_size()
  
{                        
  char	mode_select_command [6]	=  {MODE_SELECT_OPCODE, 0x10, 0, 0, 12, 0},
	mode_select_data [12]	= {0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 2, 0};
  int i, status;
                                                             
  for (i=0; i<3; i++)
    {                             
  	status = execute_command (mode_select_command,
    			6, mode_select_data, 12, WRITE);
    	if (status) return status;
    	bpt ();
    }

    return status;   
}   


/*============================================================================
! read_toc Routine.
! This routine reads the table of contents on the CD to determine the
! total number of tracks.
!============================================================================*/

int read_toc ()

{
  int	TTL_tracks = 0,
  	status;

  char	read_toc_command [10] =
		{READ_TOC_OPCODE, 0, 0, 0, 0, 0, 0, 0, 4, 0};
  char	toc_data[4];

  if (!execute_command (read_toc_command, 10, toc_data, 4, READ))
    {
    TTL_tracks = 0;    				/* No CD is present	*/
    }
  else  
    TTL_tracks = toc_data[3] - toc_data[2] + 1;

  return TTL_tracks;
}            

                        
/*============================================================================
! read_toc_track Routine.
! This routine reads the table of contents on the CD for the specified track
! and returns the block/address for the start of that track.
!============================================================================*/
                     
unsigned int read_toc_track (int track_num) 

#define READ_THE_TOC  	0X43                             

{
  unsigned char	read_toc_track_command [12] =
      {READ_THE_TOC, 0, 0, 0, 0, 0, 0, 0, 12, 0};
                                           
  unsigned char	toc_track_data[12];

  int track, status;

  unsigned int addr1, addr2, addr3, addr4, the_addr;
                                                                     
  read_toc_track_command[6] = track_num;
  
  if (!execute_command (read_toc_track_command,
			12, toc_track_data, 12, READ)) return FALSE;

  addr4 = toc_track_data[8];              
  addr3 = toc_track_data[9];                                                 
  addr2 = toc_track_data[10];
  addr1 = toc_track_data[11];

  addr4 = addr4 << 24;		/* Do all necessary byte-shifts		*/
  addr3 = addr3 << 16;
  addr2 = addr2 << 8;
  
  the_addr = addr4 + addr3 + addr2 + addr1;	/* Final address	*/

  return the_addr;		/* And return the block #		*/
}            
  

/*============================================================================
! save_track_time Routine.
! This routine saves the track-time for each track of the CD in the array
! Track_Seconds [].
!============================================================================*/
void save_track_time ()                    

{                        
  unsigned int	track_address[CD_TRACK_MAX],
		end_of_CD,  
		track_units;

  int	last_track,
	track,
	ttl_CD_secs,
	CD_secs,
	CD_mins,
	x;

  last_track = read_toc();		/* Get total # of tracks on CD	*/


  /* Save track address for each track on current CD	*/
  /*====================================================*/
    for (track = 1; track <= last_track; track++)
      {
      track_address [track] = read_toc_track (track);
      } 


  /* Now compute track-time (seconds) for each track)	*/
  /*====================================================*/
    for (track = 1; track <= (last_track - 1); track++)	/* Except last	*/
      {
      track_units = track_address[track+1] - track_address[track];
      Track_Seconds[track] = track_units / (75 * 4);
      }  
  
  end_of_CD = read_CD_capacity ();			/* Now last	*/

  if (SHOW_CD_TIME == 1)
    {
    ttl_CD_secs	= end_of_CD / (75 * 4);
    CD_mins	= ttl_CD_secs / 60;
    CD_secs	= ttl_CD_secs - (CD_mins * 60);
    printf ("=========================== \n");
    printf ("Total CD Play Time = %d:%d \n", CD_mins, CD_secs);
    }

  Track_Seconds[last_track] =
		(end_of_CD - track_address[last_track]) / (75 * 4);      
} 


/*============================================================================
! read_CD_capacity Routine.
!============================================================================*/
unsigned int read_CD_capacity ()

#define CD_CAPACITY		0X25

{
  unsigned char	CD_capacity  [10] = {CD_CAPACITY,  0, 0, 0, 0, 0, 0, 0, 0, 0};

  unsigned char	CD_capacity_data[12];                       

  unsigned int addr1, addr2, addr3, addr4, the_addr;

  int x;
 
  if (!execute_command (CD_capacity, 10, CD_capacity_data, 12, READ))
    {
    return FALSE;
    }

  addr4 = CD_capacity_data[0];		/* Extract the necessary data	*/
  addr3 = CD_capacity_data[1];
  addr2 = CD_capacity_data[2];
  addr1 = CD_capacity_data[3];

  addr4 = addr4 << 24;				/* Do byte-shifts	*/
  addr3 = addr3 << 16;
  addr2 = addr2 << 8;

  the_addr = addr4 + addr3 + addr2 + addr1;	/* Compute address	*/
  
  return the_addr;				/* return the block #	*/
}
        

/*============================================================================
! play_track Routine.            
! This routine plays the specified track on the CD.                        
!============================================================================*/

int play_track (char track_num)        
                                         
{
  int	status;

  char	play_track_command [10] =
		{PLAY_TRACK_OPCODE, 0, 0, 0, 0, 1, 0, 0,  1, 0};
                                                      
  play_track_command [4] = track_num;
  play_track_command [7] = total_tracks;
  status = execute_command(play_track_command, 10, 0, 0, READ);
  disable_eject();
  return status;	
}


/*============================================================================
! pause_cd Routine.
! This routine sends a PAUSE command to the CD-player.
!============================================================================*/

int pause_cd ()
{                                                                  
  char	pause_command [10] =   {PAUSE_OPCODE , 0, 0, 0, 0, 0, 0, 0, 0, 0};

  return execute_command (pause_command, 10, 0, 0, READ);
}


/*============================================================================
! resume_cd Routine.
! This routine sends a RESUME command to the CD-player.
!============================================================================*/

int resume_cd ()
{
  char	resume_command [10] = {RESUME_OPCODE, 0, 0, 0, 0, 0, 0, 0, 1, 0};

  return execute_command (resume_command, 10, 0, 0, READ);
}

    
/*============================================================================
! stop_unit Routine.
! This routine sends a stop command the the CD player.
!============================================================================*/

int stop_unit()

{                        
  char	stop_command [6] = {STOP_OPCODE  , 0, 0, 0, 0, 0};

  return execute_command (stop_command, 6, 0, 0, READ);
}


/*============================================================================
! eject_cd Routine.    
! This routine sends an eject-cd command the the CD player.
!============================================================================*/

int eject_cd()

{                        
  char	eject_command [6]   = {STOP_OPCODE  , 0, 0, 0, 2, 0};

  return execute_command (eject_command, 6, 0, 0, READ);
}                          

                 
/*============================================================================
! enable_eject Routine.     
! This routine enables the manual removal of a CD.
!============================================================================*/

int enable_eject()

{                                            
  char	media_enable [6]   = {MEDIA_OPCODE , 0, 0, 0, 0, 0};

  return execute_command (media_enable, 6, 0, 0, READ);
}                               


/*============================================================================
! disable_eject Routine.    
! This routine disables the manual removal of a CD.
!============================================================================*/

int disable_eject()

{                        
  char	media_disable [6]  = {MEDIA_OPCODE , 0, 0, 0, 1, 0};

  return execute_command (media_disable, 6, 0, 0, READ);
}

                                                
/*============================================================================
! get_volume Routine.     
! This routine gets the volume-level from the cd.
!============================================================================*/

void get_volume()
                           
{
                     
  int  	audio_stat	= 0,
	volume_level	= 0,
	volume_ch0	= 0,  
	volume_ch1	= 0,
	status		= 0;                            

  char 	cd_data [14];

  char	playback_status  [10] =
			{PLAYBACK_STATUS_OPCODE,  0, 0, 0, 0, 0, 0, 0, 14, 0};

        
  status = execute_command (playback_status, 10, cd_data, 14, READ);       

  audio_stat = cd_data[4]  & 0377;	/* Play/Eject=0, Stop/Pause=1	*/
  volume_ch0 = cd_data[11] & 0377;	/* Volume ch0 (low-order 8 bits)*/
  volume_ch1 = cd_data[13] & 0377;	/* Volume ch1 (low-order 8 bits)*/

  if (volume_ch0 > volume_ch1)		/* Make sure the volume-level	*/
    {					/* returned is the highest of	*/
    volume_level = volume_ch0;		/* the two channels		*/
    }
  else
    {
    volume_level = volume_ch1;
    }
                          
  left_volume    = volume_ch0;		/* Save left-channel  volume	*/
  right_volume   = volume_ch1;		/* Save right-channel volume	*/
  current_volume = volume_level;	/* And the higher of the two	*/

  if (volume_level > 0 && audio_stat == 0)
    {					/* Assume we are playing a CD	*/
    play_flag  = TRUE;			/* if status is 0, and volume	*/
    }					/* is not 0 (if volume was 0,	*/
					/* then we could be ejected)	*/
/*
  printf ("L= %d    R= %d     Max = %d    Stat= %d\n",
	  left_volume, right_volume, volume_level, audio_stat);
*/

}                               
  

/*============================================================================
! set_volume Routine.     
! This routine changes the volume of the cd-player in both channels 0 & 1.
!============================================================================*/
                                          
void set_volume(int volume_ch0, int volume_ch1)

{                                            
  int	status;

  char	playback_control [10] =
		{PLAYBACK_CONTROL_OPCODE, 0, 0, 0, 0, 0, 0, 0, 14, 0};

  char	cd_data [14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
                 
  cd_data [10] = 1;
  cd_data [11] = volume_ch0;
  cd_data [12] = 2;
  cd_data [13] = volume_ch1;

  status = execute_command (playback_control, 10, cd_data, 14, WRITE);
               
}                               

           
/*============================================================================
! get_status Routine.
! This routine reads the current status of the CD player to determine the
! total number of tracks, whether the player is playing, and, if so, the
! current track number being played. If any of this information has changed
! since the last time the screen was updated, then the screen is updated
! again.
!============================================================================*/
      
void get_status()        
                
{
  char	read_subchan_command [10] =
		{READ_SUBCHAN_OPCODE, 0, 0x40, 1, 0, 0, 0, 0, 48, 0};

  char	subchan_data [48];

  int	i,
	track_time_units;
                                       
  total_tracks = read_toc();		/* Get total tracks on this CD	*/

  if (total_tracks == 0 || execute_command (read_subchan_command,        
  	10, subchan_data, 48,  READ) == FALSE)
    {
    current_track = 0;
    track_time_sec = 0;
    }                                       
  else
    { 
    current_track = subchan_data[6];
/*
    if (subchan_data[1] == 0x12) cd_paused = TRUE;
    printf ("Subchannel data: ");
    for (i=0; i<20; i++) printf (" %02x", subchan_data[i] & 0xff);
    printf ("\n");
*/
    track_time_units = (subchan_data[13] & 0xff) * 0x10000 + 
    	    		   (subchan_data[14] & 0xff) * 0x100 + 
    			   (subchan_data[15] & 0xff);    

    /*==================================================================
    ! The following operation converts the units (blocks from
    ! beginning of track) in the subchan_data [13], subchan_data [14],
    ! and subchan_data [15] fields into units of seconds. 
    !==================================================================*/
                        
    track_time_sec = track_time_units / (75 * 4);
            
    if ((track_time_sec != saved_track_time_sec) &&
      	    (track_time_sec != (saved_track_time_sec-1)))
      {     
      saved_track_time_sec = track_time_sec;
      }                                                  

    if (subchan_data[1] == 0x13)
      {
      stop_unit ();
      }
    }

  if (current_track != saved_current_track)
    {
    update_time_scale_max();
    saved_current_track = current_track;
    }
}

                            
/*============================================================================
! bpt Routine.
! This is a null routine (spin-wheels).
!============================================================================*/
void bpt ()
         
{
}


/*============================================================================
! exit_handler Routine.
! Callback routine for exit button. Stop the CD from playing, deassign
! the channel to the player, and exit.
!============================================================================*/

void exit_handler ()                                             
{       
  stop_unit ();           	/* spin down the unit		*/
  dealloc_cd_channel();		/* blow away the channel	*/
  exit(1);			/* go away			*/
}
                     

/*============================================================================
!=============================================================================
!=============================================================================
! Below are the only VMS-SPECIFIC routines in the program:
!============================================================================*/

/*============================================================================
! execute_command Routine.
! This routine sends the specified command to the CD player. It does
! so by filling in the generic class driver descriptor and issuing
! an IO$_DIAGNOSE QIO to GKDRIVER.
!============================================================================*/
                    
int execute_command (
		int *command_addr,
		int command_len,
		int data_addr,
		int data_len,
		int rw_flag)
        

/*=====================================
!  SCSI Generic Class Driver Constants 
!=====================================*/
#define FLAGS_READ		1
#define FLAGS_DISCONNECT	2
#define FLAGS_DISCONNECT	2      
#define GOOD_SCSI_STATUS	0
#define OPCODE			0
#define FLAGS			1                       
#define COMMAND_ADDRESS		2       
#define COMMAND_LENGTH		3        
#define DATA_ADDRESS		4          
#define DATA_LENGTH		5           
#define PAD_LENGTH		6            
#define PHASE_TIMEOUT		7         
#define DISCONNECT_TIMEOUT	8    

{

  char	request_sense_command [6] = {3, 0, 0, 0, 18, 0},
  	request_sense_data [18],
	scsi_status;

  int	gk_iosb[2],
    	gk_desc[15],
	i,
	status;

  gk_desc[OPCODE]		= 1;               
  gk_desc[FLAGS]		= rw_flag + FLAGS_DISCONNECT;
  gk_desc[COMMAND_ADDRESS]	= command_addr;
  gk_desc[COMMAND_LENGTH]	= command_len;
  gk_desc[DATA_ADDRESS]		= data_addr;
  gk_desc[DATA_LENGTH]		= data_len;
  gk_desc[PAD_LENGTH]		= 0;      
  gk_desc[PHASE_TIMEOUT]	= 0;   
  gk_desc[DISCONNECT_TIMEOUT]	= 60;
  
  for (i=9; i<15; i++) gk_desc[i] = 0;	/* Clear reserved fields	*/

/*======================================================================
! Issue the QIO to send the inquiry command and receive the inquiry data
!=======================================================================*/
            
  status = sys$qiow (1, gk_chan, IO$_DIAGNOSE, gk_iosb, 0, 0, 
  		   &gk_desc[0], 15*4, 0, 0, 0, 0);


/*==========================================
!  Check the various returned status values
!===========================================*/
                                                             
  if (!(status & 1)) sys$exit (status);

  if (!(gk_iosb[0] & 1)) sys$exit (gk_iosb[0] & 0xffff);

  scsi_status = (gk_iosb[1] >> 24) & SCSI_STATUS_MASK;

  if (scsi_status == GOOD_SCSI_STATUS) return TRUE;

  if (scsi_status == 2)
    {
    bpt ();
    gk_desc[OPCODE]	= 1;
    gk_desc[FLAGS]	= FLAGS_READ + FLAGS_DISCONNECT;
    gk_desc[COMMAND_ADDRESS]	= request_sense_command;
    gk_desc[COMMAND_LENGTH]	= 6;
    gk_desc[DATA_ADDRESS]	= request_sense_data;
    gk_desc[DATA_LENGTH]	= 18;  
    gk_desc[PAD_LENGTH]		= 0;    
    gk_desc[PHASE_TIMEOUT]	= 0; 
    gk_desc[DISCONNECT_TIMEOUT]	= 60;

    for (i=9; i<15; i++) gk_desc[i] = 0;	/* Clear reserved fields */

    status = sys$qiow (1, gk_chan, IO$_DIAGNOSE, gk_iosb, 0, 0, 
    	   &gk_desc[0], 15*4, 0, 0, 0, 0);
    }

  return FALSE;                                                         
}
  	

/*============================================================================
! alloc_cd_channel Routine.                    
! This routine assigns a channel to the CD player.
!============================================================================*/

void alloc_cd_channel ()
	
{
  int	status,
	gk_device_desc[2];

  gk_device_desc[0] = strlen (gk_device);
  gk_device_desc[1] = &gk_device[0];
  status = sys$assign (&gk_device_desc[0], &gk_chan, 0, 0);
  if (!(status & 1))
    {
    printf ("Unable to assign channel to %s", &gk_device[0]);
    exit (status);
    }       
}


/*============================================================================
! dealloc_cd_channel Routine.
! This routine deassigns a channel to the CD player 
!============================================================================*/

void dealloc_cd_channel ()
	
{
  int	status;

  status = sys$dassgn (gk_chan);
  if (!(status & 1))
    {
    printf ("Unable to deassign channel from %s", &gk_device[0]);
    exit (status);
    }
}

/*===========================================================================*/
/*===============================(END PROGRAM)===============================*/
/*===========================================================================*/
/*===========================================================================*/
/*			     Convenience Routines			     */

#if CONVENIENCE_ROUTINES

/*============================================================================
! play_MSF Routine.            
! This routine plays a segment starting at "sm" minutes and "ss" seconds,
! and goes to "em" minutes and "es" seconds.
!
! Note:	The program doesn't use this routine --  It is presented as an FYI
!	in case the user wants to utilize the MSF calls for the CD.
!============================================================================*/
                          
int play_MSF (	int sm, int ss,
		int em, int es)

#define PLAY_MSF_OPCODE		0X47

{
  unsigned char	play_MSF_command [10] =
			{PLAY_MSF_OPCODE, 0, 0, 0, 0, 0, 0, 0,  0, 0};
  int status;
                                                      
  if (sm == 0 && ss < 3) ss = 3;		/* Play starts at 3 sec	*/

  play_MSF_command [3] = sm;			/* Start minutes	*/
  play_MSF_command [4] = ss;			/* start seconds	*/
  play_MSF_command [5] = 0;			/* start frame		*/
                                                      
  play_MSF_command [6] = em;			/* end minutes		*/
  play_MSF_command [7] = es;			/* end seconds		*/      
  play_MSF_command [8] = 0;			/* end frame		*/

  status = execute_command(play_MSF_command, 10, 0, 0, READ);

  return status;	

}
        

/*============================================================================
! play_partial_track Routine.            
! This routine starts at "x" minutes into the current track, and plays for
! "y" minutes.  Note that if you try and play for more minutes than are
! remaining on the CD (from your start)... that nothing will happen!
! (we call that... being feature-rich)
!
! Note:	The program doesn't use this routine --  It is presented as an FYI
!	to illustrate the use of the MSF format for playing a CD.
!============================================================================*/
                                                                          
int play_partial_track (
		int track_num,
		int start_at_minutes,      
		int start_at_seconds,
		int duration_minutes,
		int duration_seconds)

{
  int	track_minutes	= 0,
	track_seconds	= 0,
	begin_minutes	= 0,
	begin_seconds	= 0,
	end_minutes	= 0,
	end_seconds	= 0;
  unsigned int
	total_seconds	= 0,
	start_here	= 0,
	stop_here	= 0,
	actual_CD_stop	= 0;

  total_seconds = read_toc_track (track_num) / (75*4);
				/* Calcuate track start (in seconds)	*/

  track_minutes = total_seconds / 60;
  track_seconds = total_seconds - (track_minutes * 60);

  begin_minutes = track_minutes + start_at_minutes; 
  begin_seconds = track_seconds + start_at_seconds;
				/* Now add in start offset - mins/sec	*/

  end_minutes = begin_minutes + duration_minutes;
  end_seconds = begin_seconds + duration_seconds;
				/* And compute the end    - mins/sec	*/

  start_here = (begin_minutes*60) + begin_seconds;
  stop_here  = (end_minutes*60)   + end_seconds;

  actual_CD_stop = read_CD_capacity() / (75*4);

  if (start_here > actual_CD_stop)		/* If start is greater	*/
    {		 				/* than CD capacity	*/
    return FALSE;				/* exit on error	*/
    }

  if (stop_here > actual_CD_stop)		/* If end is greater...	*/
    {						/* then set to actual	*/
    end_minutes = actual_CD_stop/60;		/* end			*/
    end_seconds = actual_CD_stop - (end_minutes*60);
    }
                                                                          
  printf ("play_MSF   min=%d    sec=%d    min=%d    sec=%d \n",
		begin_minutes, begin_seconds,
		end_minutes,   end_seconds);

  play_MSF (begin_minutes, begin_seconds,
	    end_minutes,   end_seconds);	/* Now play the segment	*/
}

#endif

/*===========================================================================*/
/*=================================(END ALL)=================================*/
/*===========================================================================*/
72.37fooeyPONDA::64423::BELKINthe slow one now will later be fastTue Jan 18 1994 10:4627
I was just able to link the .c program in -.1 with:

$ define/nolog c$include decw$examples,decw$include,sys$library
$ define/nolog vaxc$include c$include
$
$! cc CD_PLAYER                   
$
$ link CD_PLAYER, sys$input/opt
	sys$share:decw$dxmlibshr.exe/share
	sys$share:decw$xmlibshr.exe/share
	sys$share:decw$xlibshr.exe/share
	sys$share:vaxcrtl.exe/share
$ exit



then I did:

$DEFINE DECW$CD_PLAYER 12X5$DKA400:

but when I run CD_PLAYER.EXE I get:

%SYSTEM-F-NOPRIV, no privilege for attempted operation

:-(

josh
72.38TOOK::PECKARThat would be somethingTue Jan 18 1994 12:543
fwiw, there's a cd player for alpha osf which comes with the operating
system as part of the motif examples. Its called xcd.
72.39PONDA::64423::BELKINthe slow one now will later be fastTue Jan 18 1994 13:168
Yabut I don't have an alpha (keep dreamin'! :-)

I think that maybe the cdplayer I found does not require you to reboot your
werkstation to make sure the default scsi driver does not get loaded.
This means that I wouldn't have to reboot to go from playing audio to reading
cdroms - unlike the version in decw$examples.

thanks anyway, Josh
72.40ROCK::FROMMIt&#039;s hard to care about a don&#039;t care.Tue Jan 18 1994 13:275
josh,

what happened when you tried the cd player i sent to you

- rich
72.41no joyPONDA::64423::BELKINthe slow one now will later be fastTue Jan 18 1994 15:3919
re     <<< Note 72.40 by ROCK::FROMM "It's hard to care about a don't care." >>>

>what happened when you tried the cd player i sent to you

I haven't tried that one yet.  It needs privs and to have my 
workstation rebooted, with futzing with the sysgen params for  SCSI generic
class drivers.  I don't have privs since my workstation boots into a big
cluster.  Any progress with the cdplayer is a result of the sysman's good
will (of which he has, but he's also busy).  
I just got him to install (with privs) the version I posted back a few notes
but when I run it I get %SYSTEM-F-CTRLERR, fatal controller error.
This version says its OK with Motif 1.0 and VMS V5.5.
We're running Motif 1.1 and VMS 5.5 - so for all I know, its a Motif problem.
My RRD-42 works fine for reading CD-ROMS of VMS docs.
Maybe I have to punt this cdplayer version and go with the newer ones
(either Rich's or the one in decw$examples).
But then I have to mess with sysgen and I lose use of the RRD42 for CD ROMS.

josh
72.42does chmod work on VMS ???QUARRY::petertrigidly defined areas of doubt and uncertaintyTue Jan 18 1994 15:4511
Josh, while not familiar with the VMS side of things, typically in order to
use the cd-rom for an audio player, you need read-write access to the 
CDROM device.  This is so you can change the volume from the software
window.  I would expect if you are just reading documents, read-only is 
OK.  I know how to do this in ODSF land, but don't know if you need to reboot
or whatever after setting things up.  Of course, in the strange way you
describe it, it sounds almost like you need the sysadmin person to set up
the device for you.  Strange....


PeterT
72.43TOOK::PECKARThat would be somethingTue Jan 18 1994 17:103
rebooting seems a bit severe. Both Unix and vms devices can be 
mounted/unmounted/dismounted
72.44BIODTL::JCJust one thing I ask of youWed Jan 19 1994 10:1611
re          <<< Note 72.43 by TOOK::PECKAR "That would be something" >>>


>rebooting seems a bit severe. Both Unix and vms devices can be 
>mounted/unmounted/dismounted


true, but if you change non-dyn sysgen pars or need to load a different
driver, you need to reboot.

josh, can you see the cd drive doing a "show dev" ?
72.45the thick plottens...PONDA::64423::BELKINthe slow one now will later be fastWed Jan 19 1994 12:1511
>josh, can you see the cd drive doing a "show dev" ?

Hmmm.. well I could see the drive reading CDroms and I'd like to see it
play audio CDs... not sure I could see that RRD042 doing a "show dev".


:-))))
kinda thick today, ain't I?  ;-)    Yes, I can see the drive with a 
show dev dk.  I can use it perfectly well to mount bookreader VMS docs.

Josh
72.46labeling program ?AWECIM::HANNANBeyond description...Fri May 03 1996 16:365
    Is there a tape label program for the PC out there ?   
    A friend is looking for something like this.

    Thanks,
    Ken
72.47AWECIM::RUSSOclaimin!Fri May 03 1996 16:486
    
    >>A friend is looking for something like this.
    
    Hmmmmm....Ken just got a pc this week, too......hmmmmm ;^)
    
    Hogan
72.48MKOTS3::JOLLIMOREAlways stop at the topFri May 03 1996 16:554
	ken,
	
	have you checked WinTaper (Note 455) ?
	it's more than a label program though.
72.49AWECIM::HANNANBeyond description...Mon May 06 1996 09:528
>    Hmmmmm....Ken just got a pc this week, too......hmmmmm ;^)
    
Correction: I've had a pc @ HLO for about a year now...

And I don't need a tape label maker when I have the old trusty
postscript program to hack at when needed.  ;-)

/Ken