home *** CD-ROM | disk | FTP | other *** search
- /*
- * cdreader - Plays an audio CD through the SGI Audio Processor.
- * You can play CDs through the monophonic speaker on your SGI Indigo,
- * or you can connect an amp to the line-out jacks for some
- * REAL quality sound.
- *
- * Original Author: Patrick Wolfe (pwolfe@kai.com, uunet!kailand!pwolfe)
- * This software is Copyright (c) 1992 by Patrick J. Wolfe.
- * See the end of this file for the complete copyright notice.
- */
-
- #define VERSION "1.4"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- /* for errno */
- #include <errno.h>
- /* for signal() */
- #include <signal.h>
- /* for getopt() */
- #include <getopt.h>
- /* for CD*() routines */
- #include <cdaudio.h>
- /* for AL*() routines */
- #include <audio.h>
- /* for schedctl() */
- #include <limits.h>
- #include <sys/prctl.h>
- #include <sys/schedctl.h>
- /* for X11/Motif interface */
- #include <X11/Intrinsic.h>
- #include <Xm/Xm.h>
- #include <Xm/CascadeB.h>
- #include <Xm/Frame.h>
- #include <Xm/MainW.h>
- #include <Xm/PushB.h>
- #include <Xm/PushBG.h>
- #include <Xm/RowColumn.h>
- #include <Xm/MessageB.h>
- #include <Xm/Form.h>
-
- #ifdef WATCH_ABUF
- /* for setitimer */
- #include <sys/time.h>
- int monitor_interval = 15; /* number of seconds between abufs left reports */
- int show_bufsleft = 0; /* flag to indicate that it's time to report */
- int total_samps = 0; /* number of samples the audio buffer will hold */
- #endif /* WATCH_ABUF */
-
- /*
- * Most of the common messages are here, for easy customization and
- * translation for foreign languages. We're not ALL ignorant bastards.
- */
-
- /* button labels */
- #define PLAY_NAME "Play"
- #define PREV_NAME "Prev"
- #define PAUSE_NAME "Pause"
- #define NEXT_NAME "Next"
- #define SHUFFLE_NAME "Shuffle"
- #define TRACKS_NAME "Tracks"
- #define STOP_NAME "Stop"
- #define EJECT_NAME "Eject"
- #define QUIT_NAME "Quit"
- #define INFO_NAME "Info"
- #define HELP_NAME "Help"
-
- /* status messages */
- char *Playing_Msg = "Playing Track";
- char *Stopped_Msg = "Stopped";
- char *Paused_Msg = "Paused at Track";
- char *Total_Msg = "Total time on disk";
- char *Track_Word = "Track";
- char *Length_Word = "Length";
-
- /* error messages */
- char *DISC_NOT_READY = "Disc Not Ready";
- char *CANNOT_READ_SCSI = "\
- Your cheapo CDrom drive does NOT support reading audio data\n\
- across the SCSI bus. You should have bought one from SGI!";
- char *TOO_MANY_TRACKS = "Too many audio tracks on this disc!\nrecompile with larger MAX_TRACK_INFO.";
- char *CDOPEN_FAILED = "CDopen failed\nCannot Open CDrom device";
- char *CDGETSTATUS_FAILED = "CDgetstatus failed\nCannot get status of CDrom device";
- char *CDGETTRACKINFO_FAILED = "CDgettrackinfo failed";
- char *CDSEEKTRACK_FAILED = "CDseektrack failed\nCannot find track";
- char *CDEJECT_FAILED = "cannot eject disc - not stopped";
-
-
-
- #define SAMPLES_PER_FRAME (CDDA_DATASIZE/2)
-
- /* valid states for main process loop control */
- #define STOPPED 0 /* we are stopped */
- #define PAUSED 1 /* we were playing, and are now paused */
- #define PLAYING 2 /* we are playing music */
- #define STARTING 3 /* start playing at beginning of the disk */
- #define CONTINUE 4 /* start playing where you left off */
- #define STOPPING 5 /* we were playing, and are about to stop */
- #define PAUSING 6 /* we were playing, and are about to pause */
- #define START_TRACK 9 /* start playing at the beginning of the current track */
-
- /* maximum number of tracks to store info for */
- /* I *have* seen up to 28 tracks on a single CD, but none longer */
- #define MAX_TRACK_INFO 64
-
- /* audio stuff */
- ALport audio_port = NULL;
- CDPLAYER *cd_device = NULL;
- CDPARSER *cd_parser = NULL;
- CDFRAME *cd_buffer = NULL;
-
- /* cd stuff */
- struct cdinformation {
- short length_min; /* track length */
- short length_sec;
- } track_info[MAX_TRACK_INFO];
- int first_track = 0; /* first track on the disk */
- int last_track = 0; /* index into track_info for entry AFTER last one we have info for */
- int current_track = -1; /* number of track currently playing */
- int total_min = 0; /* minutes part of total running time on current disk */
- int total_sec = 0; /* second part of total running time on current disk */
- int play_index = -1; /* index into playlist for shuffle mode, -1 means that shuffle is not on */
- int play_list[MAX_TRACK_INFO]; /* order of tracks to play */
- int cd_readsize = 12; /* the normal number of frames to read at one time (CDbestreadsize fills this in) */
- int cd_init_readsize = 200; /* initial number of frames to read at the beginning of the disc */
- int status = STOPPING; /* main process loop status */
-
- /* X11 stuff */
- XtAppContext appcon;
- Widget main_window,
- label,
- play_button,
- prev_button,
- pause_button,
- next_button,
- shuffle_button,
- tracks_button,
- info_button,
- stop_button,
- eject_button;
- static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
-
-
- Display_Warning (message)
- char *message;
- {
- Widget button;
- Widget warning_box;
- XmString title_string = NULL;
- XmString message_string = NULL;
- Arg args[4];
- register int n;
-
- message_string = XmStringCreateLtoR (message, charset);
- title_string = XmStringCreateLtoR ("Cdreader Warning!", charset);
-
- n = 0;
- XtSetArg (args[n], XmNdialogTitle, title_string); n++;
- XtSetArg (args[n], XmNmessageString, message_string); n++;
- warning_box = XmCreateWarningDialog (main_window, "warning", args, n);
- button = XmMessageBoxGetChild (warning_box, XmDIALOG_CANCEL_BUTTON);
- XtUnmanageChild (button);
- button = XmMessageBoxGetChild (warning_box, XmDIALOG_HELP_BUTTON);
- XtUnmanageChild (button);
- if (title_string) XtFree (title_string);
- if (message_string) XtFree (message_string);
- XtManageChild (warning_box);
- }
-
-
- set_message (message)
- char *message;
- {
- XmString label_string;
- Arg args[30];
- int ctr;
-
- ctr = 0;
- label_string = XmStringCreate (message, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- XtSetValues (label, args, ctr);
- XmStringFree (label_string);
- }
-
-
- int
- get_track_info ()
- {
- CDSTATUS cd_status;
- CDTRACKINFO cd_info;
-
- if ((cd_device == NULL) && ((cd_device = CDopen(0, "r")) == NULL)) {
- Display_Warning (CDOPEN_FAILED);
- return (1);
- }
-
- /* display disk info */
- if (CDgetstatus(cd_device, &cd_status) == 0) {
- status = STOPPING;
- Display_Warning (CDGETSTATUS_FAILED);
- return (1);
- }
- /* don't start unless it's ready */
- if (cd_status.state != CD_READY) {
- status = STOPPING;
- Display_Warning (DISC_NOT_READY);
- return (1);
- }
- if (! cd_status.scsi_audio) {
- status = STOPPING;
- Display_Warning (CANNOT_READ_SCSI);
- return (1);
- }
- total_min = cd_status.total_min;
- total_sec = cd_status.total_sec;
-
- /* get track information */
- for (first_track = last_track = cd_status.first;
- (last_track <= cd_status.last) && (last_track < MAX_TRACK_INFO);
- last_track++) {
- if (CDgettrackinfo(cd_device, last_track, &cd_info) == 0) {
- status = STOPPING;
- Display_Warning (CDGETTRACKINFO_FAILED);
- return (1);
- }
- track_info[last_track].length_min = cd_info.total_min;
- track_info[last_track].length_sec = cd_info.total_sec;
- }
- if (last_track >= MAX_TRACK_INFO) {
- Display_Warning (TOO_MANY_TRACKS);
- return (1);
- }
-
- /* find the best number of frames to read at a time */
- cd_readsize = CDbestreadsize (cd_device);
-
- return (0);
- }
-
-
- /* called as signal handler, and when the quit button is pressed */
- void
- quit_pgm ()
- {
- CDdeleteparser(cd_parser); /* free parser memory */
- if (cd_device != NULL) {
- CDclose(cd_device); /* close CD player port */
- }
- if (audio_port != NULL) {
- ALcloseport(audio_port); /* close audio port */
- }
- exit (0);
- }
-
-
- /* called by pressing the EJECT button */
- void
- eject_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- if (status == STOPPED) {
- if ((cd_device == NULL) && ((cd_device = CDopen(0, "r")) == NULL)) {
- Display_Warning (CDOPEN_FAILED);
- }
- else {
- CDeject(cd_device);
- CDclose(cd_device);
- cd_device = NULL;
- }
- }
- else {
- Display_Warning (CDEJECT_FAILED);
- }
- }
-
-
- /* called by pressing the STOP button */
- void
- stop_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- play_index = -1;
- status = STOPPING;
- }
-
-
- /* called by pressing the PAUSE button */
- void
- pause_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- if (status == PLAYING) {
- status = PAUSING;
- }
- }
-
-
- /* called by pressing the PLAY button */
- void
- play_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- if (status == STOPPED) {
- status = STARTING;
- }
- else if (status == PAUSED) {
- status = CONTINUE;
- }
- }
-
-
- /* called by pressing the PREV button */
- void
- prev_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- char message[64];
-
- if ((cd_device == NULL) && get_track_info()) { /* opens cd_device and gets track_info[] */
- status = STOPPING;
- return;
- }
-
- if ((status == PLAYING) || (status == PAUSED) || (status == STOPPED)) {
- if (play_index == -1) {
- current_track--;
- if (current_track < first_track) {
- current_track = first_track;
- }
- }
- else { /* shuffling */
- play_index--;
- if (play_index < first_track) {
- play_index = first_track;
- }
- current_track = play_list[play_index];
- }
-
- if (CDseektrack(cd_device, current_track) == -1) {
- (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
- Display_Warning (message);
- status = STOPPING;
- }
- else if (status == PLAYING) {
- status = CONTINUE;
- }
- else {
- status = PAUSING;
- }
- }
- }
-
-
- /* called by pressing the NEXT button */
- void
- next_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- char message[64];
-
- if ((cd_device == NULL) && get_track_info()) { /* opens cd_device and gets track_info[] */
- status = STOPPING;
- return;
- }
-
- if ((status == PLAYING) || (status == PAUSED) || (status == STOPPED)) {
- if (play_index < 0) {
- current_track++;
- if (current_track >= last_track) {
- current_track = first_track;
- status = STOPPING;
- return;
- }
- }
- else { /* shuffling */
- play_index++;
- if (play_index >= last_track) {
- current_track = first_track;
- status = STOPPING;
- return;
- }
- current_track = play_list[play_index];
- }
-
- if (CDseektrack(cd_device, current_track) == -1) {
- (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
- Display_Warning (message);
- status = STOPPING;
- }
- else if (status == PLAYING) {
- status = CONTINUE;
- }
- else {
- status = PAUSING;
- }
- }
- }
-
-
- /* called by pressing the SHUFFLE button
- * plays all tracks on the disk in a random order
- */
- void
- shuffle_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- double jdb;
- int i, j, m, d = 1;
- int played[MAX_TRACK_INFO];
-
- if (get_track_info()) { /* opens cd_device and gets track_info[] */
- status = STOPPING;
- return;
- }
-
- m = last_track - 1;
-
- /* initialize played array to -1's, indicating track hasn't been selected to play yet */
- for (i = first_track; i < last_track; i++) {
- played[i] = 0;
- }
-
- /* seed is our process id */
- srand ((u_int) getpid());
-
- for (i = first_track; i < last_track; i++) {
- j = rand( );
- jdb = (double)j / (double)(RAND_MAX + 1);
- j = (int)(jdb * m) + 1;
- for (; played[j]; j += d) {
- if (j < first_track) {
- j = last_track;
- }
- else if (j >= last_track) {
- j = first_track;
- }
- }
- d = d * -1; /* switch direction */
- play_list[i] = j;
- played[j] = 1;
- }
-
- play_index = first_track;
- current_track = play_list[play_index];
- status = START_TRACK;
- }
-
-
- /* called by pressing the TRACKS button */
- /* show info about the entire disk */
- void
- tracks_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- Widget button;
- Widget message_box;
- XmString title_string = NULL;
- XmString message_string = NULL;
- XmString button_string = NULL;
- Arg args[4];
- register int n;
- int track;
- char message[4096];
- char line[256];
-
- if ((status == STOPPED) && get_track_info() ) {
- return; /* if stopped, try to re-read the track info - might be a new disc */
- }
- if ((status != PLAYING) && (status != PAUSED) && (status != STOPPED)) {
- return; /* ignore this button during odd status changes */
- }
- (void) sprintf (message, "%s = %02d:%02d\n\n", Total_Msg, total_min, total_sec);
-
- /* show info about each track */
- for (track = first_track; track < last_track; track++) {
- (void) sprintf (line, "\t%s %2d: %s %02d:%02d\n", Track_Word, track, Length_Word,
- track_info[track].length_min, track_info[track].length_sec);
- (void) strcat (message, line);
- }
-
- title_string = XmStringCreateLtoR ("Cdreader Track List", charset);
- button_string = XmStringCreateLtoR ("Close", charset);
- message_string = XmStringCreateLtoR (message, charset);
-
- n = 0;
- XtSetArg (args[n], XmNdialogTitle, title_string); n++;
- XtSetArg (args[n], XmNokLabelString, button_string); n++;
- XtSetArg (args[n], XmNmessageString, message_string); n++;
- message_box = XmCreateMessageDialog (main_window, "tracks", args, n);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
- XtUnmanageChild (button);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
- XtUnmanageChild (button);
- if (title_string) XtFree (title_string);
- if (button_string) XtFree (button_string);
- if (message_string) XtFree (message_string);
- XtManageChild (message_box);
- }
-
-
- /* called by pressing the INFO button */
- void
- info_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- Widget button;
- Widget message_box;
- char message[2048];
- XmString title_string = NULL;
- XmString message_string = NULL;
- XmString button_string = NULL;
- Arg args[4];
- register int n;
-
- (void) sprintf (message, "\
- Cdreader V%s plays an audio compact disc loaded in an SGI cdrom drive through\n\
- the Audio Processor.\n\
- \n\
- Cdreader uses the libcdaudio routines to read the digital data directly from\n\
- the cdrom drive, and plays it through the Audio Processor. You can listen on\n\
- the Indigo's speaker, or even better, buy a cable with a stereo mini-plug on\n\
- one end, and two phono plugs on the other, and connect from your Indigo's\n\
- line out jack to your stereo amplifier's cd in or tape in jacks.\n\
- \n\
- Cdreader will probably only work with an SGI's cdrom drive and under release\n\
- 4.0.1 (or later) of the Irix operating system. The program will tell you if\n\
- your cdrom drive doesn't support reading audio over the SCSI bus. It uses\n\
- about 5-6%% of the cpu, and 4%% of the SCSI bus bandwidth. Use of other\n\
- programs which change the audio processor's parameters is discouraged (but\n\
- sure can make you chuckle).\n\
- \n\
- Original Author:\n\
- \tPatrick Wolfe\n\
- \tSystem Programmer/Operations Manager\n\
- \tKuck & Associates\n\
- \t1906 Fox Drive\n\
- \tChampaign, IL 61820\n\
- \tInternet: pwolfe@kai.com\n\
- \tUUCP: uunet!kailand!pwolfe\n\
- \tvoice: (217) 356-2288\n\
- \tFAX: (217) 356-5199\n\
- copyright (c) 1992 Patrick J. Wolfe\n", VERSION);
-
- message_string = XmStringCreateLtoR (message, charset);
- button_string = XmStringCreateLtoR ("Close", charset);
- title_string = XmStringCreateLtoR ("Cdreader Information", charset);
-
- n = 0;
- XtSetArg (args[n], XmNdialogTitle, title_string); n++;
- XtSetArg (args[n], XmNokLabelString, button_string); n++;
- XtSetArg (args[n], XmNmessageString, message_string); n++;
- message_box = XmCreateMessageDialog (w, "credit", args, n);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
- XtUnmanageChild (button);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
- XtUnmanageChild (button);
- if (title_string) XtFree (title_string);
- if (button_string) XtFree (button_string);
- if (message_string) XtFree (message_string);
- XtManageChild (message_box);
- }
-
-
- /* called by pressing the HELP button */
- void
- help_callback (w, client_data, call_data)
- Widget w;
- caddr_t client_data; /* unused */
- caddr_t call_data; /* unused */
- {
- Widget button;
- Widget message_box;
- char message[2048];
- XmString title_string = NULL;
- XmString message_string = NULL;
- XmString button_string = NULL;
- Arg args[4];
- register int n;
-
- (void) sprintf (message, "\
- Cdreader V%s plays an audio compact disc loaded in an SGI cdrom drive through\n\
- the Audio Processor.\n\n\
- To get started, load an audio CD in the caddy, and insert it into your cd drive\n\
- with the clear side of the caddy facing up.\n\n\
- The buttons function as follows:\n\
- \tPlay - plays an audio disk\n\
- \tShuffle - plays the whole disk in a random order\n\
- \tStop - stops playback\n\
- \tPause - suspends playback - press Play to continue\n\
- \tNext - selects the next track\n\
- \tPrev - selects the previous track\n\
- \tTracks - displays a table of tracks and their lengths\n\n\
- \tEject - ejects the disk from the cdrom drive\n\
- The buttons are context sensitive, for example, the eject button won't function\n\
- unless the program is in the \"Stopped\" state. Buttons are are not active will\n\
- appear dimly shaded.\n\n\
- Near the top of the window is a menu bar. On the bar are three buttons:\n\
- \tQuit - terminates the program\n\
- \tInfo - give the author some credit!\n\
- \tHelp - uh, you're looking at it\n\
- ", VERSION);
-
- message_string = XmStringCreateLtoR (message, charset);
- button_string = XmStringCreateLtoR ("Close", charset);
- title_string = XmStringCreateLtoR ("Cdreader Help", charset);
-
- n = 0;
- XtSetArg (args[n], XmNdialogTitle, title_string); n++;
- XtSetArg (args[n], XmNokLabelString, button_string); n++;
- XtSetArg (args[n], XmNmessageString, message_string); n++;
- message_box = XmCreateMessageDialog (w, "helpbox", args, n);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_CANCEL_BUTTON);
- XtUnmanageChild (button);
- button = XmMessageBoxGetChild (message_box, XmDIALOG_HELP_BUTTON);
- XtUnmanageChild (button);
- if (title_string) XtFree (title_string);
- if (button_string) XtFree (button_string);
- if (message_string) XtFree (message_string);
- XtManageChild (message_box);
- }
-
-
- /* called only when the program (track) number changes */
- void
- cd_pnum_callback (arg, type, data)
- int arg;
- CDDATATYPES type;
- struct cdprognum *data;
- {
- char message[32];
-
- if (play_index == -1) {
- current_track = data->value;
- (void) sprintf (message, "%s %d - %s %2d:%02d", Playing_Msg, current_track, Length_Word,
- track_info[current_track].length_min,
- track_info[current_track].length_sec);
- set_message (message);
- }
- else if (data->value != current_track) { /* shuffling and the track changed */
- play_index++;
- if (play_index >= last_track) {
- status = STOPPING;
- }
- else {
- current_track = play_list[play_index];
- status = START_TRACK;
- }
- }
- }
-
-
- /* called for every frame - data is already byte swapped and de-emphasized */
- void
- cd_audio_callback (arg, type, data)
- int arg;
- CDDATATYPES type;
- void *data;
- {
- ALwritesamps (audio_port, data, SAMPLES_PER_FRAME);
- }
-
-
- int
- init_audio ()
- {
- ALconfig aconfig;
- long pvbuf[6];
-
- if (audio_port == NULL) {
- /* initialize the audio port */
- aconfig = ALnewconfig ();
-
- /*
- * create the maximum size audio buffer we can,
- * in another attempt to avoid pauses in the music.
- */
- ALsetqueuesize (aconfig, SAMPLES_PER_FRAME * cd_init_readsize);
-
- #ifdef WATCH_ABUF
- total_samps = SAMPLES_PER_FRAME * cd_init_readsize;
- printf ("allocating an audio buffer that can hold %d samples\n", total_samps);
- #endif /* WATCH_ABUF */
-
- /*
- * set the sample to 16 bit width and stereo. Yes, I know it these are the
- * defaults ... TODAY, but I've gotten into trouble before by assuming the
- * defaults would never change change. Besides, it doesn't hurt.
- */
- ALsetwidth (aconfig, AL_SAMPLE_16);
- ALsetchannels (aconfig, AL_STEREO);
-
- audio_port = ALopenport ("cdreader", "w", aconfig);
-
- /* free audio port config buffer immediately */
- ALfreeconfig(aconfig);
-
- if (audio_port == NULL) {
- Display_Warning ("Could not open a port to the Audio Processor!");
- return (1);
- }
-
- /* set audio port output sampling rate to 44.1 kHz */
- pvbuf[0] = AL_OUTPUT_RATE;
- pvbuf[1] = AL_RATE_44100;
- ALsetparams (AL_DEFAULT_DEVICE, pvbuf, 2);
- }
- return (0);
- }
-
-
- int
- init_cd ()
- {
- /* allocate a buffer to read CD data into */
- if (cd_buffer == (CDFRAME *) NULL) {
- cd_buffer = (CDFRAME *) malloc (cd_init_readsize * CDDA_BLOCKSIZE);
- if (cd_buffer == (CDFRAME *) NULL) {
- Display_Warning ("cannot allocate enough memory for a cd digital data buffer");
- return (1);
- }
- }
-
- /* create parser structure */
- if (cd_parser == NULL) {
- cd_parser = CDcreateparser ();
- if (cd_parser == NULL) {
- Display_Warning ("SERIOUS ERROR!\nCDcreateparser failed");
- return (1);
- }
-
- /* initialize parser structure */
- CDresetparser(cd_parser);
-
- /* define callback routines for CDparseframe() */
- CDsetcallback (cd_parser, cd_audio, cd_audio_callback, 0);
- CDsetcallback (cd_parser, cd_pnum, cd_pnum_callback, 0);
- }
- return (0);
- }
-
-
- void
- init_motif (argc, argv)
- int argc;
- char **argv;
- {
- Display *display;
- Widget app_shell, menu_bar, cascade, frame, form, row_column;
- XmString label_string;
- Arg args[30];
- int ctr;
-
- XtToolkitInitialize ();
- appcon = XtCreateApplicationContext ();
- display = XtOpenDisplay (appcon, NULL, "cdreader", "Cdreader", NULL, 0, &argc, argv);
- if (!display) {
- XtWarning ("cdreader: Can't open your X display, exiting...");
- exit (0);
- }
-
- app_shell = XtAppCreateShell ("cdreader", "Cdreader", applicationShellWidgetClass, display, NULL, 0);
-
- /* XtGetApplicationResources (app_shell, &AppData, resources, XtNumber(resources), NULL, 0); */
-
- ctr = 0;
- main_window = XmCreateMainWindow (app_shell, "main1", args, ctr);
- XtManageChild (main_window);
-
- ctr = 0;
- menu_bar = XmCreateMenuBar (main_window, "menu_bar", args, ctr);
- XtManageChild (menu_bar);
-
- ctr = 0;
- cascade = XmCreateCascadeButton (menu_bar, "Quit", args, ctr);
- XtManageChild (cascade);
- XtAddCallback (cascade, XmNactivateCallback, quit_pgm, NULL);
-
- ctr = 0;
- cascade = XmCreateCascadeButton (menu_bar, "Info", args, ctr);
- XtManageChild (cascade);
- XtAddCallback (cascade, XmNactivateCallback, info_callback, NULL);
-
- ctr = 0;
- cascade = XmCreateCascadeButton (menu_bar, "Help", args, ctr);
- XtManageChild (cascade);
- XtAddCallback (cascade, XmNactivateCallback, help_callback, NULL);
-
- /* let the menu bar know who's the help button around here */
- ctr = 0;
- XtSetArg (args[ctr], XmNmenuHelpWidget, cascade); ctr++;
- XtSetValues (menu_bar, args, ctr);
-
- /* create form to hold everything */
- ctr = 0;
- form = XmCreateForm (main_window, "form", args, ctr);
- XtManageChild (form);
-
- /* create label gadget inside frame */
- ctr = 0;
- label_string = XmStringCreate ("Stopped", charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- XtSetArg (args[ctr], XmNwidth, 230); ctr++;
- XtSetArg (args[ctr], XmNheight, 35); ctr++;
- XtSetArg (args[ctr], XmNrecomputeSize, False); ctr++;
- XtSetArg (args[ctr], XmNleftAttachment, XmATTACH_FORM); ctr++;
- XtSetArg (args[ctr], XmNrightAttachment, XmATTACH_FORM); ctr++;
- XtSetArg (args[ctr], XmNtopAttachment, XmATTACH_FORM); ctr++;
- label = XmCreateLabelGadget (form, "label", args, ctr);
- XtManageChild (label);
-
- /* create frame mainwindow */
- ctr = 0;
- XtSetArg (args[ctr], XmNmarginWidth, 2); ctr++;
- XtSetArg (args[ctr], XmNmarginHeight, 2); ctr++;
- XtSetArg (args[ctr], XmNshadowThickness, 1); ctr++;
- XtSetArg (args[ctr], XmNshadowType, XmSHADOW_OUT); ctr++;
- XtSetArg (args[ctr], XmNleftAttachment, XmATTACH_FORM); ctr++;
- XtSetArg (args[ctr], XmNrightAttachment, XmATTACH_FORM); ctr++;
- XtSetArg (args[ctr], XmNtopAttachment, XmATTACH_WIDGET); ctr++;
- XtSetArg (args[ctr], XmNtopWidget, label); ctr++;
- XtSetArg (args[ctr], XmNbottomAttachment, XmATTACH_FORM); ctr++;
- frame = XmCreateFrame (form, "frame", args, ctr);
- XtManageChild (frame);
-
- /* create rowcolumn in frame to manage buttons */
- ctr = 0;
- XtSetArg (args[ctr], XmNpacking, XmPACK_COLUMN); ctr++;
- XtSetArg (args[ctr], XmNnumColumns, 4); ctr++;
- row_column = XmCreateRowColumn (frame, "row_column", args, ctr);
- XtManageChild (row_column);
-
- /* create buttons by column */
- ctr = 0;
- label_string = XmStringCreateLtoR (PLAY_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- play_button = XmCreatePushButtonGadget (row_column, PLAY_NAME, args, ctr);
- XtManageChild (play_button);
- XtAddCallback (play_button, XmNarmCallback, play_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (PREV_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- prev_button = XmCreatePushButtonGadget (row_column, PREV_NAME, args, ctr);
- XtManageChild (prev_button);
- XtAddCallback (prev_button, XmNarmCallback, prev_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (PAUSE_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- pause_button = XmCreatePushButtonGadget (row_column, PAUSE_NAME, args, ctr);
- XtManageChild (pause_button);
- XtAddCallback (pause_button, XmNarmCallback, pause_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (NEXT_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- next_button = XmCreatePushButtonGadget (row_column, NEXT_NAME, args, ctr);
- XtManageChild (next_button);
- XtAddCallback (next_button, XmNarmCallback, next_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (SHUFFLE_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- shuffle_button = XmCreatePushButtonGadget (row_column, SHUFFLE_NAME, args, ctr);
- XtManageChild (shuffle_button);
- XtAddCallback (shuffle_button, XmNarmCallback, shuffle_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (TRACKS_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- tracks_button = XmCreatePushButtonGadget (row_column, TRACKS_NAME, args, ctr);
- XtManageChild (tracks_button);
- XtAddCallback (tracks_button, XmNarmCallback, tracks_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (STOP_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- stop_button = XmCreatePushButtonGadget (row_column, STOP_NAME, args, ctr);
- XtManageChild (stop_button);
- XtAddCallback (stop_button, XmNarmCallback, stop_callback, NULL);
- XmStringFree (label_string);
-
- ctr = 0;
- label_string = XmStringCreateLtoR (EJECT_NAME, charset);
- XtSetArg (args[ctr], XmNlabelString, label_string); ctr++;
- eject_button = XmCreatePushButtonGadget (row_column, EJECT_NAME, args, ctr);
- XtManageChild (eject_button);
- XtAddCallback (eject_button, XmNarmCallback, eject_callback, NULL);
- XmStringFree (label_string);
-
- /* set MainWindow areas */
- XmMainWindowSetAreas (main_window, menu_bar, NULL, NULL, NULL, form);
-
- /* put them all on the screen */
- XtRealizeWidget (app_shell);
- }
-
-
- #ifdef WATCH_ABUF
- void
- heartbeat ()
- {
- show_bufsleft = 1;
- signal (SIGALRM, heartbeat);
- }
- #endif /* WATCH_ABUF */
-
-
- main (argc, argv)
- int argc;
- char *argv[];
- {
- #ifdef WATCH_ABUF
- struct itimerval itbuf;
- #endif /* WATCH_ABUF */
- XEvent an_event;
- int frame_ctr, frames_to_play;
- char message[64];
-
- /*
- * Try to increase the scheduling priority of this process. This should help
- * reduce pauses in the music, due to cpu scheduling conflicts by making
- * cdreader one of the highest priority processes in the system.
- *
- * The schedctl() system call will fail (silently) unless the program is installed
- * setuid to root, or the kernel is reconfigured to allow mere mortals to use
- * non-degrading priorities. See the SCHEDCTL(2) and AUTOCONFIG(1M) manpages,
- * and the Irix Programming Guide Vol 2, section 14.2.3 for complete details.
- *
- * That's what I did, and it's pretty easy! Basically, * become superuser,
- * edit /usr/sysgen/master.d/disp, find the variable "ndpri_hilim", change it's
- * value to "NDPHIMAX", run "autoconfig" and reboot.
- *
- * We don't care if it fails, probably the user doesn't have permission.
- *
- * WARNING! when testing new code, DON'T do this! (this is
- * the voice of experience talking, so listen up!) If you get
- * into an infinite loop, your system will LOCK UP tight!
- * (because cdreader will be the highest priority process,
- * and you won't be able to kill it)
- *
- */
- #ifndef TESTING
- (void) schedctl (NDPRI, 0, NDPHIMAX+1);
- #endif
-
- /* lose any setuid priviledges assigned to allow schedctl to succeed */
- (void) seteuid (getuid());
-
- (void) signal (SIGHUP, quit_pgm); /* should really trap everything, right? */
- (void) signal (SIGINT, quit_pgm);
- (void) signal (SIGQUIT, quit_pgm);
- (void) signal (SIGTERM, quit_pgm);
-
- init_motif (argc, argv); /* initialize the X11/Motif user interface */
-
- /* main process loop */
- for (;;) {
- switch (status) {
-
- case PAUSED:
- case STOPPED:
- XtAppNextEvent (appcon, &an_event);
- XtDispatchEvent (&an_event);
- break;
-
- case PAUSING:
- (void) sprintf (message, "%s %d", Paused_Msg, current_track);
- set_message (message);
-
- XtSetSensitive (play_button, True);
- XtSetSensitive (stop_button, True);
- XtSetSensitive (pause_button, False);
- XtSetSensitive (shuffle_button, False);
- XtSetSensitive (eject_button, False);
-
- #ifdef WATCH_ABUF
- /* turn off monitor timer */
- signal (SIGALRM, SIG_IGN);
- itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = 0;
- itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
- if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
- perror ("setitimer");
- return;
- }
- #endif /* WATCH_ABUF */
-
- status = PAUSED;
- break;
-
- case STOPPING:
- set_message (Stopped_Msg);
- current_track = 1;
- if (cd_device != NULL) {
- CDclose (cd_device);
- cd_device = NULL;
- }
-
- XtSetSensitive (play_button, True);
- XtSetSensitive (shuffle_button, True);
- XtSetSensitive (eject_button, True);
- XtSetSensitive (pause_button, False);
- XtSetSensitive (stop_button, False);
-
- #ifdef WATCH_ABUF
- /* turn off monitor timer */
- signal (SIGALRM, SIG_IGN);
- itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = 0;
- itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
- if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
- perror ("setitimer");
- return;
- }
- #endif /* WATCH_ABUF */
-
- status = STOPPED;
- break;
-
- case STARTING:
- if (get_track_info()) { /* opens cd_device and gets track_info[] */
- status = STOPPING;
- break;
- }
- current_track = first_track; /* play whole disk from the start */
- play_index = -1;
-
- case START_TRACK:
- if (CDseektrack(cd_device, current_track) == -1) {
- (void) sprintf (message, "%s %d", CDSEEKTRACK_FAILED, current_track);
- Display_Warning (message);
- status = STOPPING;
- break;
- }
- /* FALLTHROUGH */
-
- case CONTINUE:
- if (init_audio() || init_cd()) { /* initialize audio port and cd structures */
- status = STOPPING;
- break;
- }
-
- (void) sprintf (message, "%s %d - %s %2d:%02d", Playing_Msg, current_track, Length_Word,
- track_info[current_track].length_min,
- track_info[current_track].length_sec);
- set_message (message);
-
- while (XtAppPending (appcon)) { /* process any pending X events */
- XtAppNextEvent (appcon, &an_event);
- XtDispatchEvent (&an_event);
- }
-
- XtSetSensitive (pause_button, True);
- XtSetSensitive (stop_button, True);
- XtSetSensitive (play_button, False);
- XtSetSensitive (shuffle_button, False);
- XtSetSensitive (eject_button, False);
-
- #ifdef WATCH_ABUF
- show_bufsleft = 0;
- signal (SIGALRM, heartbeat);
- itbuf.it_value.tv_sec = itbuf.it_interval.tv_sec = monitor_interval;
- itbuf.it_value.tv_usec = itbuf.it_interval.tv_usec = 0;
- if (setitimer (ITIMER_REAL, &itbuf, (struct itimerval *) 0) == -1) {
- perror ("setitimer");
- return;
- }
- #endif /* WATCH_ABUF */
-
- /*
- * read enough cd data to fill the audio buffer, to help
- * cover any later pauses due to cpu scheduling.
- * Be aware that we might still have some audio data left over
- * from a previous pause.
- */
- frames_to_play = CDreadda (cd_device, &cd_buffer[0], cd_init_readsize);
-
- /* process any pending X events */
- while (XtAppPending (appcon)) {
- XtAppNextEvent (appcon, &an_event);
- XtDispatchEvent (&an_event);
- }
-
- if (frames_to_play < 1) {
- status = STOPPING;
- }
- else {
- status = PLAYING;
- }
- break;
-
- case PLAYING:
-
- #ifdef IRIX401_CDREADDA_BUG
- /*
- * BUG! The manpage for CDreadda() says it returns the number
- * of frames read. In reality, it returns the number of bytes read
- * into the buffer. Divide by CDDA_BLOCKSIZE to get the number of frames.
- *
- * I'd prefer it to work like the manpage says, return the number of frames.
- * This is supposed to be fixed in the next release of Irix (after 4.0.1).
- */
- frames_to_play = frames_to_play / CDDA_BLOCKSIZE;
- #endif /* IRIX401_CDREADDA_BUG */
-
- /* process CD data */
- for (frame_ctr = 0; frame_ctr < frames_to_play; frame_ctr++) {
- CDparseframe (cd_parser, &cd_buffer[frame_ctr]);
- }
-
- /* process any pending X events */
- while (XtAppPending (appcon)) {
- XtAppNextEvent (appcon, &an_event);
- XtDispatchEvent (&an_event);
- }
-
- /* still playing? read more CD data */
- if (status == PLAYING) {
- frames_to_play = CDreadda (cd_device, &cd_buffer[0], cd_readsize);
- if (frames_to_play < 1) { /* end of disc */
- status = STOPPING;
- }
- }
-
- #ifdef WATCH_ABUF
- if (show_bufsleft) {
- show_bufsleft = 0;
- printf ("abufs left = %d\n", total_samps - ALgetfilled(audio_port));
- }
- #endif /* WATCH_ABUF */
-
- /* process any pending X events */
- while (XtAppPending (appcon)) {
- XtAppNextEvent (appcon, &an_event);
- XtDispatchEvent (&an_event);
- }
- break;
-
- default:
- Display_Warning ("Cdreader has become horribly confused.\nYou should quit and start the program over");
- status = STOPPING;
- }
- }
-
- /* NOTREACHED */
- }
-
- /*
- * Original Author: Patrick Wolfe (pwolfe@kai.com, uunet!kailand!pwolfe)
- *
- * This software is Copyright (c) 1992 by Patrick J. Wolfe.
- *
- * Permission is hereby granted to copy, distribute or otherwise
- * use any part of this package as long as you do not try to make
- * money from it or pretend that you wrote it. This copyright
- * notice must be maintained in any copy made.
- *
- * Use of this software constitutes acceptance for use in an AS IS
- * condition. There are NO warranties with regard to this software.
- * In no event shall the author be liable for any damages whatsoever
- * arising out of or in connection with the use or performance of this
- * software. Any use of this software is at the user's own risk.
- *
- * If you make modifications to this software that you feel
- * increases it usefulness for the rest of the community, please
- * email the changes, enhancements, bug fixes as well as any and
- * all ideas to me. This software is going to be maintained and
- * enhanced as deemed necessary by the community.
- *
- * Patrick J. Wolfe
- * uunet!kailand!pwolfe
- * pwolfe@kai.com
- */
-