Here are diffs for workman to run on BSDI. You'll also need an XView3.0 library. These diffs are vs. BETA 4.0.1 (posted to alt.sources and others around 19/20 December 1992) I've included a completely new version of hardware.c, since I took out all the sun/ultrix/hpux code that was there to make it readable while debugging. =================================================================== RCS file: RCS/Imakefile,v retrieving revision 1.1 diff -c -r1.1 Imakefile *** /tmp/RCSA000284 Sat Jan 23 12:25:13 1993 --- Imakefile Sat Jan 23 12:22:35 1993 *************** *** 15,23 **** #define HasInfoFiles YES ! DEFINES = $(SOLARIS2) DEPLIBS = XViewClientDepLibs ! LOCAL_LIBRARIES = XViewClientLibs INFOFILES = workman.info --- 15,25 ---- #define HasInfoFiles YES ! DEFINES = $(SOLARIS2) -DSOUNDBLASTER DEPLIBS = XViewClientDepLibs ! LOCAL_LIBRARIES = XViewClientLibs -lcdrom -lrpc ! CC=/usr/local/bin/gcc -fno-builtin ! CDEBUGFLAGS=-g -O INFOFILES = workman.info =================================================================== RCS file: RCS/cdinfo.c,v retrieving revision 1.1 diff -c -r1.1 cdinfo.c *** /tmp/RCSA000284 Sat Jan 23 12:25:13 1993 --- cdinfo.c Sat Jan 23 12:22:53 1993 *************** *** 14,20 **** char *strchr(), *getenv(); struct play *playlist = NULL; ! struct cdinfo thiscd, *cd = &thiscd; int cur_track = -1; /* Current track number, starting at 1 */ int cur_index = 0; /* Current index mark */ --- 14,20 ---- char *strchr(), *getenv(); struct play *playlist = NULL; ! struct cdinfo_wm thiscd, *cd = &thiscd; int cur_track = -1; /* Current track number, starting at 1 */ int cur_index = 0; /* Current index mark */ *************** *** 27,33 **** int cur_cdlen; /* Length in seconds of entire CD */ int cur_ntracks; /* Number of tracks on CD (= tracks + sections) */ int cur_nsections; /* Number of sections currently defined */ ! int cur_cdmode; /* CD play mode (1=play, 3=pause, 4=stop, 5=eject) */ int cur_listno; /* Current index into the play list, if playing */ char * cur_artist; /* Name of current CD's artist */ char * cur_cdname; /* Album name */ --- 27,33 ---- int cur_cdlen; /* Length in seconds of entire CD */ int cur_ntracks; /* Number of tracks on CD (= tracks + sections) */ int cur_nsections; /* Number of sections currently defined */ ! enum cd_modes cur_cdmode; int cur_listno; /* Current index into the play list, if playing */ char * cur_artist; /* Name of current CD's artist */ char * cur_cdname; /* Album name */ *************** *** 594,600 **** */ struct playlist * new_list(cd, listname) ! struct cdinfo *cd; char *listname; { int nlists = 0; --- 594,600 ---- */ struct playlist * new_list(cd, listname) ! struct cdinfo_wm *cd; char *listname; { int nlists = 0; =================================================================== RCS file: RCS/database.c,v retrieving revision 1.1 diff -c -r1.1 database.c *** /tmp/RCSA000284 Sat Jan 23 12:25:13 1993 --- database.c Sun Dec 20 15:11:47 1992 *************** *** 175,181 **** */ char * print_cdinfo(cd, prefs) ! struct cdinfo *cd; int prefs; { int i; --- 175,181 ---- */ char * print_cdinfo(cd, prefs) ! struct cdinfo_wm *cd; int prefs; { int i; =================================================================== RCS file: RCS/display.c,v retrieving revision 1.1 diff -c -r1.1 display.c *** /tmp/RCSA000284 Sat Jan 23 12:25:14 1993 --- display.c Sat Jan 23 12:23:10 1993 *************** *** 43,49 **** extern int num_names, num_nalloc; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_cdmode, cur_ntracks, cur_nsections, cur_lasttrack; extern int cur_frame; extern char *cur_cdname, *cur_artist; extern int displayed_track, pop_track, *pop_list, pop_listsize, pl_item, --- 43,50 ---- extern int num_names, num_nalloc; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_ntracks, cur_nsections, cur_lasttrack; ! extern enum cd_modes cur_cdmode; extern int cur_frame; extern char *cur_cdname, *cur_artist; extern int displayed_track, pop_track, *pop_list, pop_listsize, pl_item, *************** *** 634,644 **** window1_objects *ip; { static char trk_time[6], abs_time[6]; ! static int old_cdmode = -1; int pos; /* If we're on a different track than we used to be, update the track info */ ! if (displayed_track != cur_track && cur_cdmode != 5) new_track(ip); /* Update the current play mode */ --- 635,645 ---- window1_objects *ip; { static char trk_time[6], abs_time[6]; ! static enum cd_modes old_cdmode = UNKNOWN; int pos; /* If we're on a different track than we used to be, update the track info */ ! if (displayed_track != cur_track && cur_cdmode != EJECTED) new_track(ip); /* Update the current play mode */ *************** *** 706,717 **** TRUE, NULL); } ! if (xv_get(Workman_goodies->a, PANEL_INACTIVE) == (cur_cdmode == 1 || ! cur_cdmode == 3)) { ! xv_set(Workman_goodies->a, PANEL_INACTIVE, cur_cdmode != 1 && ! cur_cdmode != 3, NULL); ! if (cur_cdmode != 1 && cur_cdmode != 3) xv_set(Workman_goodies->b, PANEL_INACTIVE, TRUE, NULL); } } --- 707,718 ---- TRUE, NULL); } ! if (xv_get(Workman_goodies->a, PANEL_INACTIVE) == ! (cur_cdmode == PLAYING || cur_cdmode == PAUSED)) { ! xv_set(Workman_goodies->a, PANEL_INACTIVE, ! cur_cdmode != PLAYING && cur_cdmode != PAUSED, NULL); ! if (cur_cdmode != PLAYING && cur_cdmode != PAUSED) xv_set(Workman_goodies->b, PANEL_INACTIVE, TRUE, NULL); } } *************** *** 910,916 **** xv_set(pu->playmode, PANEL_VALUE, get_playmode(), NULL); displayed_track = -1; ! cur_cdmode = 4; } /* --- 911,917 ---- xv_set(pu->playmode, PANEL_VALUE, get_playmode(), NULL); displayed_track = -1; ! cur_cdmode = STOPPED; } /* *************** *** 1051,1057 **** xv_set(Workman_window1->songpos, PANEL_VALUE, cur_pos_rel, NULL); ! if (dont_retry && cur_cdmode == 5) { old_retry = dont_retry; dont_retry = 0; --- 1052,1058 ---- xv_set(Workman_window1->songpos, PANEL_VALUE, cur_pos_rel, NULL); ! if (dont_retry && cur_cdmode == EJECTED) { old_retry = dont_retry; dont_retry = 0; =================================================================== RCS file: RCS/struct.h,v retrieving revision 1.1 diff -c -r1.1 struct.h *** /tmp/RCSA000284 Sat Jan 23 12:25:15 1993 --- struct.h Sat Jan 23 12:22:14 1993 *************** *** 50,56 **** int *list; /* List of tracks */ }; ! struct cdinfo { char artist[84]; /* Artist's name */ char cdname[84]; /* Disc's name */ int ntracks; /* Number of tracks on the disc */ --- 50,56 ---- int *list; /* List of tracks */ }; ! struct cdinfo_wm { char artist[84]; /* Artist's name */ char cdname[84]; /* Disc's name */ int ntracks; /* Number of tracks on the disc */ *************** *** 66,71 **** }; /* The global variable "cd" points to the struct for the CD that's playing. */ ! extern struct cdinfo *cd; struct playlist *new_list(); --- 66,73 ---- }; /* The global variable "cd" points to the struct for the CD that's playing. */ ! extern struct cdinfo_wm *cd; struct playlist *new_list(); + + enum cd_modes { UNKNOWN=-1, TRACK_DONE=0, PLAYING=1, PAUSED=3, STOPPED=4, EJECTED=5 }; =================================================================== RCS file: RCS/ui_cdinfo.c,v retrieving revision 1.1 diff -c -r1.1 ui_cdinfo.c *** /tmp/RCSA000284 Sat Jan 23 12:25:15 1993 --- ui_cdinfo.c Sat Jan 23 11:22:18 1993 *************** *** 43,49 **** extern int num_names, num_nalloc, my_cdname, my_artist; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_cdmode, cur_ntracks, cur_nsections, cur_lasttrack; extern int cur_frame; extern char *cur_cdname, *cur_artist; extern int displayed_track, pop_track, *pop_list, pop_listsize, pl_item, --- 43,50 ---- extern int num_names, num_nalloc, my_cdname, my_artist; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_ntracks, cur_nsections, cur_lasttrack; ! extern enum cd_modes cur_cdmode; extern int cur_frame; extern char *cur_cdname, *cur_artist; extern int displayed_track, pop_track, *pop_list, pop_listsize, pl_item, *************** *** 436,442 **** Panel_item item; Event *event; { ! int old_cdmode = cur_cdmode; kill_stats(Workman_window1); wipe_cdinfo(); --- 437,443 ---- Panel_item item; Event *event; { ! enum cd_modes old_cdmode = cur_cdmode; kill_stats(Workman_window1); wipe_cdinfo(); *************** *** 443,452 **** load(); init_stats(Workman_window1); show_stats(Workman_window1); ! if (old_cdmode == 3) { ! cur_cdmode = 3; ! xv_set(Workman_window1->mode, PANEL_VALUE, 3, NULL); } info_modified = 0; } --- 444,453 ---- load(); init_stats(Workman_window1); show_stats(Workman_window1); ! if (old_cdmode == PAUSED) { ! cur_cdmode = PAUSED; ! xv_set(Workman_window1->mode, PANEL_VALUE, PAUSED, NULL); } info_modified = 0; } =================================================================== RCS file: RCS/workman_stubs.c,v retrieving revision 1.1 diff -c -r1.1 workman_stubs.c *** /tmp/RCSA000284 Sat Jan 23 12:25:15 1993 --- workman_stubs.c Sat Jan 23 11:24:18 1993 *************** *** 69,75 **** plpopup_objects *Workman_plpopup; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_cdmode, cur_ntracks, cur_lasttrack, cur_firsttrack, cur_listno; extern int cur_frame; extern int cd_fd; extern int exit_on_eject, suppress_locking; --- 69,76 ---- plpopup_objects *Workman_plpopup; extern int cur_track, cur_pos_abs, cur_pos_rel, cur_tracklen, cur_cdlen, ! cur_ntracks, cur_lasttrack, cur_firsttrack, cur_listno; ! extern enum cd_modes cur_cdmode; extern int cur_frame; extern int cd_fd; extern int exit_on_eject, suppress_locking; *************** *** 93,99 **** int was_repeating = 0; int info_modified = 0; int show_titles = 1; ! #ifdef hpux int dismiss_button = 1; #else int dismiss_button = 0; --- 94,100 ---- int was_repeating = 0; int info_modified = 0; int show_titles = 1; ! #if defined(hpux) || defined(__bsdi__) int dismiss_button = 1; #else int dismiss_button = 0; *************** *** 366,379 **** int w; { window1_objects *ip = Workman_window1; ! static int old_cdmode, new_image = 0, initted_volume = 0; Xv_opaque old_image; if (xv_get(ip->mode, PANEL_VALUE) != 5 || ! dont_retry) switch (cd_status()) { case 0: /* No CD in drive */ ! cur_cdmode = 5; ! if (old_cdmode != 5) { if (!xv_get(ip->tracks, PANEL_INACTIVE)) { --- 367,381 ---- int w; { window1_objects *ip = Workman_window1; ! static int new_image = 0, initted_volume = 0; ! static enum cd_modes old_cdmode; Xv_opaque old_image; if (xv_get(ip->mode, PANEL_VALUE) != 5 || ! dont_retry) switch (cd_status()) { case 0: /* No CD in drive */ ! cur_cdmode = EJECTED; ! if (old_cdmode != EJECTED) { if (!xv_get(ip->tracks, PANEL_INACTIVE)) { *************** *** 385,391 **** } break; case 1: /* CD in drive, what state is it in? */ ! if (cur_cdmode == 0) /* Done with track... */ { donewithcd: if (xv_get(Workman_goodies->abrepeat, --- 387,393 ---- } break; case 1: /* CD in drive, what state is it in? */ ! if (cur_cdmode == TRACK_DONE) /* Done with track... */ { donewithcd: if (xv_get(Workman_goodies->abrepeat, *************** *** 407,413 **** play_next_entry(); if (cd_status() != 1) return (handle_timer(c, w)); ! if (cur_cdmode == 4) /* Done with CD */ { xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL); --- 409,415 ---- play_next_entry(); if (cd_status() != 1) return (handle_timer(c, w)); ! if (cur_cdmode == STOPPED) /* Done with CD */ { xv_set(Workman_goodies->abrepeat, PANEL_VALUE, FALSE, NULL); *************** *** 467,473 **** cur_track = cur_firsttrack; /* The slider has been moved... */ ! if (time_wanted > -1 && cur_cdmode == 1) { play_from_pos(time_wanted); time_wanted = -2; --- 469,475 ---- cur_track = cur_firsttrack; /* The slider has been moved... */ ! if (time_wanted > -1 && cur_cdmode == PLAYING) { play_from_pos(time_wanted); time_wanted = -2; *************** *** 484,491 **** if (cur_lasttrack != -1 && cur_track > cur_lasttrack) goto donewithcd; ! if (cur_cdmode != 4 && cur_cdmode != 3 || old_cdmode != ! cur_cdmode) show_stats(ip); break; --- 486,493 ---- if (cur_lasttrack != -1 && cur_track > cur_lasttrack) goto donewithcd; ! if (cur_cdmode != STOPPED && cur_cdmode != PAUSED ! || old_cdmode != cur_cdmode) show_stats(ip); break; *************** *** 517,523 **** show_stats(ip); cd_status(); if ((cur_playnew && !found_in_rc) || get_autoplay() || ! cur_cdmode == 1) make_initial_playlist(get_playmode()); break; } --- 519,525 ---- show_stats(ip); cd_status(); if ((cur_playnew && !found_in_rc) || get_autoplay() || ! cur_cdmode == PLAYING) make_initial_playlist(get_playmode()); break; } *************** *** 548,554 **** make_initial_playlist(playmode) int playmode; { ! if (cur_cdmode == 1) { if (playmode == 1) { --- 550,556 ---- make_initial_playlist(playmode) int playmode; { ! if (cur_cdmode == PLAYING) { if (playmode == 1) { *************** *** 598,606 **** window1_objects *ip = Workman_window1; int track, playmode; ! if (cur_cdmode == 5 && dont_retry) handle_timer(NULL, NULL); ! if (cur_cdmode == 5 || (cur_track == -1 && (value == 0 || value == 2))) { xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); return; --- 600,608 ---- window1_objects *ip = Workman_window1; int track, playmode; ! if (cur_cdmode == EJECTED && dont_retry) handle_timer(NULL, NULL); ! if (cur_cdmode == EJECTED || (cur_track == -1 && (value == 0 || value == 2))) { xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); return; *************** *** 608,614 **** switch (value) { case 0: /* back a track */ ! if (cur_cdmode == 1) { play_prev_track(); cd_status(); --- 610,616 ---- switch (value) { case 0: /* back a track */ ! if (cur_cdmode == PLAYING) { play_prev_track(); cd_status(); *************** *** 623,629 **** cur_pos_abs = cur_frame / 75; } ! if (cur_cdmode == 1 || cur_cdmode == 4) xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE)) --- 625,631 ---- cur_pos_abs = cur_frame / 75; } ! if (cur_cdmode == 1 || cur_cdmode == STOPPED) xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE)) *************** *** 636,648 **** break; case 1: /* play */ ! if (cur_cdmode == 3) { pause_cd(); show_stats(ip); break; } ! if (cur_cdmode == 4) { /* XXX should call make_initial_playlist() */ track = xv_get(ip->tracks, PANEL_VALUE) + 1; --- 638,650 ---- break; case 1: /* play */ ! if (cur_cdmode == PAUSED) { pause_cd(); show_stats(ip); break; } ! if (cur_cdmode == STOPPED) { /* XXX should call make_initial_playlist() */ track = xv_get(ip->tracks, PANEL_VALUE) + 1; *************** *** 656,668 **** { pl_find_track(track); cur_track = track; ! cur_cdmode = 1; play_from_pos(0); displayed_track = -1; } } } ! if (cur_cdmode != 1) play_next_entry(); cd_status(); --- 658,670 ---- { pl_find_track(track); cur_track = track; ! cur_cdmode = PLAYING; play_from_pos(0); displayed_track = -1; } } } ! if (cur_cdmode != PLAYING) play_next_entry(); cd_status(); *************** *** 675,684 **** break; case 2: /* forward a track */ ! if (cur_cdmode == 1) { play_next_track(); ! if (cur_cdmode == 4) goto stopped; cd_status(); } --- 677,686 ---- break; case 2: /* forward a track */ ! if (cur_cdmode == PLAYING) { play_next_track(); ! if (cur_cdmode == STOPPED) goto stopped; cd_status(); } *************** *** 692,698 **** cur_pos_abs = cur_frame / 75; } ! if (cur_cdmode == 1 || cur_cdmode == 4) xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE)) --- 694,700 ---- cur_pos_abs = cur_frame / 75; } ! if (cur_cdmode == PLAYING || cur_cdmode == STOPPED) xv_set(ip->mode, PANEL_VALUE, cur_cdmode, NULL); if (xv_get(Workman_goodies->abrepeat, PANEL_VALUE)) *************** *** 841,851 **** { window1_objects *ip = Workman_window1; ! if (cur_cdlen > 0 && cur_cdmode != 5) { if (value == -1) { ! if (cur_cdmode == 1 || cur_cdmode == 3) xv_set(item, PANEL_VALUE, cur_track - 1, NULL); else { --- 843,853 ---- { window1_objects *ip = Workman_window1; ! if (cur_cdlen > 0 && cur_cdmode != EJECTED) { if (value == -1) { ! if (cur_cdmode == PLAYING || cur_cdmode == PAUSED) xv_set(item, PANEL_VALUE, cur_track - 1, NULL); else { *************** *** 859,865 **** else cur_track = value + 1; ! if (cur_cdmode == 1) { pl_find_track(cur_track); play_from_pos(0); --- 861,867 ---- else cur_track = value + 1; ! if (cur_cdmode == PLAYING) { pl_find_track(cur_track); play_from_pos(0); *************** *** 885,891 **** time_wanted = value; ! if (cur_cdmode == 4 && cur_track > 0) { if (! xv_get(Workman_goodies->timemode_track, PANEL_VALUE)) sprintf(time, "%02d:%02d", value / 60, value % 60); --- 887,893 ---- time_wanted = value; ! if (cur_cdmode == STOPPED && cur_track > 0) { if (! xv_get(Workman_goodies->timemode_track, PANEL_VALUE)) sprintf(time, "%02d:%02d", value / 60, value % 60); *************** *** 1654,1664 **** { int track, index; ! if (cur_cdmode != 4) { ! change_mode(NULL, 4, NULL); ! cur_cdmode = 4; ! xv_set(Workman_window1->mode, PANEL_VALUE, 4, NULL); } for (track = 1; track <= cd->ntracks; track++) --- 1656,1666 ---- { int track, index; ! if (cur_cdmode != STOPPED) { ! change_mode(NULL, STOPPED, NULL); ! cur_cdmode = STOPPED; ! xv_set(Workman_window1->mode, PANEL_VALUE, STOPPED, NULL); } for (track = 1; track <= cd->ntracks; track++) *************** *** 1684,1690 **** Notify_client c; Destroy_status s; { ! if (s == DESTROY_CHECKING && cur_cdmode != 5) { keep_settings(Workman_window1); if (info_modified) --- 1686,1692 ---- Notify_client c; Destroy_status s; { ! if (s == DESTROY_CHECKING && cur_cdmode != STOPPED) { keep_settings(Workman_window1); if (info_modified) *************** *** 1733,1743 **** int sig; Notify_signal_mode when; { ! if (cur_cdmode == 1) { ! change_mode(NULL, 3, NULL); ! cur_cdmode = 3; ! xv_set(Workman_window1->mode, PANEL_VALUE, 3, NULL); } return (NOTIFY_DONE); --- 1735,1745 ---- int sig; Notify_signal_mode when; { ! if (cur_cdmode == PLAYING) { ! change_mode(NULL, PAUSED, NULL); ! cur_cdmode = PAUSED; ! xv_set(Workman_window1->mode, PANEL_VALUE, PAUSED, NULL); } return (NOTIFY_DONE); *************** *** 1749,1759 **** int sig; Notify_signal_mode when; { ! if (cur_cdmode == 4 || cur_cdmode == 3) { ! change_mode(NULL, 1, NULL); ! cur_cdmode = 1; ! xv_set(Workman_window1->mode, PANEL_VALUE, 1, NULL); } return (NOTIFY_DONE); --- 1751,1761 ---- int sig; Notify_signal_mode when; { ! if (cur_cdmode == STOPPED || cur_cdmode == PAUSED) { ! change_mode(NULL, PLAYING, NULL); ! cur_cdmode = PLAYING; ! xv_set(Workman_window1->mode, PANEL_VALUE, PLAYING, NULL); } return (NOTIFY_DONE); *************** *** 1765,1775 **** int sig; Notify_signal_mode when; { ! if (cur_cdmode == 1 || cur_cdmode == 3) { ! change_mode(NULL, 4, NULL); ! cur_cdmode = 4; ! xv_set(Workman_window1->mode, PANEL_VALUE, 4, NULL); } return (NOTIFY_DONE); --- 1767,1777 ---- int sig; Notify_signal_mode when; { ! if (cur_cdmode == PLAYING || cur_cdmode == PAUSED) { ! change_mode(NULL, STOPPED, NULL); ! cur_cdmode = STOPPED; ! xv_set(Workman_window1->mode, PANEL_VALUE, STOPPED, NULL); } return (NOTIFY_DONE); =================================================================== *** /dev/null Sat Jan 23 12:13:25 1993 --- hardware.new.c Sat Jan 23 12:23:41 1993 *************** *** 0 **** --- 1,734 ---- + /* + * @(#)hardware.c 1.12 12/17/92 + * + * Get information about a CD. + */ + static char *ident = "@(#)hardware.c 1.12 12/17/92"; + + #include + #include + #include + #include + #include + #include + #include + # include + # include + #include "struct.h" + #ifdef SOUNDBLASTER + #include + #endif + + void *malloc(); + char *strchr(); + + # define MAX_LINE_LENGTH 100 /* For reading uerf */ + + struct cdinfo *find_cdrom(); + + extern struct play *playlist; + extern struct cdinfo_wm thiscd, *cd; + + struct cdinfo *cur_cd = 0; + + /* + * The minimum volume setting for the Sun and DEC CD-ROMs is 128 but for other + * machines this might not be the case. + */ + #ifdef SOUNDBLASTER + int min_volume = 0; + int max_volume = 15; + #else + int min_volume = 128; + int max_volume = 255; + #endif + + char *cd_device = NULL; + + extern int cur_track, cur_index, cur_lasttrack, cur_firsttrack, cur_pos_abs, + cur_frame, cur_pos_rel, cur_tracklen, cur_cdlen, cur_ntracks, + cur_nsections, cur_listno, cur_stopmode, exit_on_eject, + cur_balance; + extern enum cd_modes cur_cdmode; + extern char *cur_artist, *cur_cdname, *cur_trackname; + extern char cur_contd, cur_avoid; + + static int pause_frame; + static int pause_track; + + #ifdef SOUNDBLASTER + static int mixer_fd = -2; + #endif + + static + debug_printf() + {} + + struct cdinfo * + find_cdrom() + { + struct cdinfo *cdinfo; + if ((cdinfo = cdopen(0)) == NULL) { + fprintf(stderr, "No cdrom found by libcdrom\n"); + exit(1); + } + cd_device = "found"; + pause_frame = 0; + + #ifdef SOUNDBLASTER + if (mixer_fd < -1) + mixer_fd = open ("/dev/sb_mixer", O_RDWR, 0); + if (mixer_fd == -1) + fprintf (stderr,"SoundBlaster mixer not found; will use direct CD volume control\n"); + #endif + + return cdinfo; + } + + /* + * read_toc() + * + * Read the table of contents from the CD. Return a pointer to a cdinfo + * struct containing the relevant information (minus artist/cdname/etc.) + * This is a static struct. Returns NULL if there was an error. + * + * XXX allocates one trackinfo too many. + */ + struct cdinfo_wm * + read_toc() + { + struct playlist *l; + struct cdinfo hdr; + struct track_info *entry; + int i, pos; + + if (cur_cd == 0) + return(NULL); + + thiscd.artist[0] = thiscd.cdname[0] = '\0'; + thiscd.whichdb = thiscd.otherrc = thiscd.otherdb = NULL; + thiscd.length = 0; + thiscd.autoplay = thiscd.playmode = thiscd.volume = 0; + thiscd.ntracks = cur_cd->ntracks; + if (thiscd.lists != NULL) + { + for (l = thiscd.lists; l->name != NULL; l++) + { + free(l->name); + free(l->list); + } + free(thiscd.lists); + thiscd.lists = NULL; + } + + if (thiscd.trk != NULL) + free(thiscd.trk); + + thiscd.trk = malloc((thiscd.ntracks + 1) * sizeof(struct trackinfo)); + if (thiscd.trk == NULL) + { + perror("malloc"); + return (NULL); + } + for (i = 0; i <= thiscd.ntracks; i++) + { + int min, sec, frames; + entry = &cur_cd->tracks[i]; + thiscd.trk[i].data = + thiscd.trk[i].avoid = entry->control & + 0x4 ? 1 : 0; + frame_to_msf(entry->nframes, &min, &sec, &frames); + thiscd.trk[i].length = min * 60 + sec; + thiscd.trk[i].start = entry->start_frame; + thiscd.trk[i].songname = thiscd.trk[i].otherrc = + thiscd.trk[i].otherdb = NULL; + thiscd.trk[i].contd = 0; + thiscd.trk[i].volume = 0; + thiscd.trk[i].track = i + 1; + thiscd.trk[i].section = 0; + } + + /* Now compute actual track lengths. */ + + for (i = 0; i < thiscd.ntracks; i++) + { + if (thiscd.trk[i].data) + thiscd.trk[i].length = (thiscd.trk[i + 1].start - + thiscd.trk[i].start) * 2; + if (thiscd.trk[i].avoid) + strmcpy(&thiscd.trk[i].songname, "DATA TRACK"); + } + + thiscd.length = cur_cd->total_frames / 75; + + return (&thiscd); + } + + /* + * cd_status() + * + * Return values: + * + * 0 No CD in drive. + * 1 CD in drive. + * 2 CD has just been inserted (TOC has been read) + * 3 CD has just been removed + * + * Updates cur_track, cur_pos_rel, cur_pos_abs and other variables. + */ + int + cd_status() + { + struct cdstatus status; + int ret = 1; + + if (cur_cd == 0) + { + cur_cd = find_cdrom(); + cur_cdmode = EJECTED; + } + + + if (cdstatus (cur_cd, &status) < 0) { + cur_cdmode = TRACK_DONE; /* waiting for next track. */ + return ret; + } + + if (cur_cdmode == EJECTED) /* CD has been ejected */ + { + cur_pos_rel = cur_pos_abs = cur_frame = 0; + + if ((cd = read_toc()) == NULL) + { + cdclose(cur_cd); + cur_cd = 0; + if (exit_on_eject) + exit(0); + else + return (0); + } + cur_nsections = 0; + cur_ntracks = cd->ntracks; + cur_cdlen = cd->length; + load(); + cur_artist = cd->artist; + cur_cdname = cd->cdname; + cur_cdmode = STOPPED; + ret = 2; + } + + switch (status.state) { + case cdstate_playing: + cur_cdmode = PLAYING; + dopos: + cur_pos_abs = status.abs_frame / 75; + cur_frame = status.abs_frame; + + /* Only look up the current track number if necessary. */ + if (cur_track < 1 || cur_frame < cd->trk[cur_track-1].start || + cur_frame >= (cur_track >= cur_ntracks ? + (cur_cdlen + 1) * 75 : + cd->trk[cur_track].start)) + { + cur_track = 0; + while (cur_track < cur_ntracks && cur_frame >= + cd->trk[cur_track].start) + cur_track++; + } + if (cur_track >= 1 && status.track_num > + cd->trk[cur_track-1].track) + cur_track++; + + cur_index = status.index_num; + doall: + if (cur_track >= 1 && cur_track <= cur_ntracks) + { + cur_trackname = cd->trk[cur_track-1].songname; + cur_avoid = cd->trk[cur_track-1].avoid; + cur_contd = cd->trk[cur_track-1].contd; + cur_pos_rel = (cur_frame - + cd->trk[cur_track-1].start) / 75; + if (cur_pos_rel < 0) + cur_pos_rel = -cur_pos_rel; + } + + if (playlist != NULL && playlist[0].start) + { + cur_pos_abs -= cd->trk[playlist[cur_listno-1]. + start - 1].start / 75; + cur_pos_abs += playlist[cur_listno-1].starttime; + } + if (cur_pos_abs < 0) + cur_pos_abs = cur_frame = 0; + + if (cur_track < 1) + cur_tracklen = cd->length; + else + cur_tracklen = cd->trk[cur_track-1].length; + break; + + case cdstate_paused: + /* the MITSUMI drive doesn't have a "paused" state, + so it never gets here. + that's what the pause_frame stuff is about in + cdstate_stopped below. */ + if (cur_cdmode == PLAYING || cur_cdmode == PAUSED) + { + cur_cdmode = PAUSED; + goto dopos; + } + else + cur_cdmode = STOPPED; + goto doall; + case cdstate_stopped: + if (cur_cdmode == PLAYING) /* playing */ + { + cur_cdmode = TRACK_DONE; + break; + } else if (cur_cdmode == PAUSED) + goto dopos; + default: + cur_cdmode = STOPPED; + cur_lasttrack = cur_firsttrack = -1; + goto doall; + } + return (ret); + } + + /* + * scale_volume(vol, max) + * + * Return a volume value suitable for passing to the CD-ROM drive. "vol" + * is a volume slider setting; "max" is the slider's maximum value. + * + * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack + * increases much faster toward the top end of the volume scale than it + * does at the bottom. To make up for this, we make the volume scale look + * sort of logarithmic (actually an upside-down inverse square curve) so + * that the volume value passed to the drive changes less and less as you + * approach the maximum slider setting. The actual formula looks like + * + * (max^2 - (max - vol)^2) * (max_volume - min_volume) + * v = --------------------------------------------------- + min_volume + * max^2 + * + * If your system's volume settings aren't broken in this way, something + * like the following should work: + * + * return ((vol * (max_volume - min_volume)) / max + min_volume); + */ + scale_volume(vol, max) + int vol, max; + { + #ifdef SOUNDBLASTER + return ((vol * (max_volume - min_volume)) / max + min_volume); + #else + return ((max * max - (max - vol) * (max - vol)) * + (max_volume - min_volume) / (max * max) + min_volume); + #endif + } + + /* + * unscale_volume(cd_vol, max) + * + * Given a value between min_volume and max_volume, return the volume slider + * value needed to achieve that value. + * + * Rather than perform floating-point calculations to reverse the above + * formula, we simply do a binary search of scale_volume()'s return values. + */ + unscale_volume(cd_vol, max) + int cd_vol, max; + { + int vol, incr, scaled; + + for (vol = max / 2, incr = max / 4 + 1; incr; incr /= 2) + { + scaled = scale_volume(vol, max); + if (cd_vol == scaled) + break; + if (cd_vol < scaled) + vol -= incr; + else + vol += incr; + } + + if (vol < 0) + vol = 0; + else if (vol > max) + vol = max; + + return (vol); + } + + /* + * cd_volume(vol, bal, max) + * + * Set the volume levels. "vol" and "bal" are the volume and balance knob + * settings, respectively. "max" is the maximum value of the volume knob + * (the balance knob is assumed to always go from 0 to 20.) + */ + void + cd_volume(vol, bal, max) + int vol, bal, max; + { + int left, right; + if (cur_cd == NULL) + return; + + + /* + * Set "left" and "right" to volume-slider values accounting for the + * balance setting. + * + * XXX - the maximum volume setting is assumed to be in the 20-30 range. + */ + if (bal < 9) + right = vol - (9 - bal) * 2; + else + right = vol; + if (bal > 11) + left = vol - (bal - 11) * 2; + else + left = vol; + + /* Adjust the volume to make up for the CD-ROM drive's weirdness. */ + left = scale_volume(left, max); + right = scale_volume(right, max); + + #ifdef SOUNDBLASTER + /* Send a Mixer IOCTL */ + if (mixer_fd >= 0) { + struct sb_mixer_levels levels; + if (ioctl(mixer_fd, MIXER_IOCTL_READ_LEVELS, &levels) == 0) { + levels.cd.l = left; + levels.cd.r = right; + (void) ioctl(mixer_fd, MIXER_IOCTL_SET_LEVELS, &levels); + } else + perror("SoundBlaster mixer read failed"); + } + #endif + cdvolume (cur_cd, ((left + right)/2) * 100 / 255); + return; + } + + /* + * pause_cd() + * + * Pause the CD, if it's in play mode. If it's already paused, go back to + * play mode. + */ + void + pause_cd() + { + struct cdstatus status; + + if (cur_cd == 0) /* do nothing if there's no CD! */ + return; + + switch (cur_cdmode) { + case PLAYING: /* playing */ + cur_cdmode = PAUSED; + + if (cdstatus (cur_cd, &status) < 0) + return; + if (status.state != cdstate_playing) { + debug_printf (1, "pause while not playing\n"); + pause_frame = cur_cd->tracks[0].start_frame; + } else { + pause_frame = status.abs_frame; + pause_track = status.track_num; + #if 0 + debug_printf (1, "pause at frame %d %s\n", + pause_frame, + cdrom_frame_to_str (pause_frame)); + #endif + } + if (cdstop (cur_cd) < 0) + return; + + break; + case PAUSED: /* paused */ + cur_cdmode = PLAYING; + if (pause_frame < cur_cd->tracks[0].start_frame) { + debug_printf (1, "adjusing pause_frame to start\n"); + pause_frame = cur_cd->tracks[0].start_frame; + } + + #if 0 + debug_printf (1, "resume at frame %d (%s)\n", + pause_frame, cdrom_frame_to_str (pause_frame)); + #endif + + if (cdplay (cur_cd, pause_frame, cur_cd->total_frames) < 0) + return; + pause_frame = 0; + break; + } + } + + /* + * stop_cd() + * + * Stop the CD if it's not already stopped. + */ + void + stop_cd() + { + if (cur_cd == 0) + return; + + if (cur_cdmode != STOPPED) + { + cur_lasttrack = cur_firsttrack = -1; + cur_cdmode = STOPPED; + cur_track = 1; + (void) cdstop (cur_cd); + } + } + + /* + * play_chunk(start, end) + * + * Play the CD from one position to another (both in frames.) + */ + void + play_chunk(start, end) + int start, end; + { + + if (cur_cd == NULL) + return; + + end--; + if (start >= end) + start = end-1; + + if (cdplay (cur_cd, start, end) < 0) + return; + } + + /* + * play_cd(starttrack, pos, endtrack) + * + * Start playing the CD or jump to a new position. "pos" is in seconds, + * relative to start of track. + */ + void + play_cd(start, pos, end) + int start, pos, end; + { + + if (cd == NULL) + return; + + cur_firsttrack = start; + start--; + end--; + cur_lasttrack = end; + + play_chunk(cd->trk[start].start + pos * 75, end >= cur_ntracks ? + cur_cdlen * 75 : cd->trk[end].start - 1); + } + + /* + * Set the offset into the current track and play. -1 means end of track + * (i.e., go to next track.) + */ + void + play_from_pos(pos) + int pos; + { + if (pos == -1) + if (cd) + pos = cd->trk[cur_track - 1].length - 1; + if (cur_cdmode == PLAYING) + play_cd(cur_track, pos, playlist[cur_listno-1].end); + } + + /* + * Eject the current CD, if there is one, and set the mode to 5. + * + * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the + * CD contains a mounted filesystem. + */ + eject_cd() + { + if (cur_cdmode == EJECTED) /* Already ejected! */ + return (0); + if (cur_cd) { + /* noop on MITSUMI */ + cdeject (cur_cd); + cdclose (cur_cd); + cur_cd = 0; + } + if (exit_on_eject) + exit(0); + + cur_track = -1; + cur_cdlen = cur_tracklen = 1; + cur_pos_abs = cur_pos_rel = cur_frame = 0; + cur_cdmode = EJECTED; + + return (0); + } + + /* Try to keep the CD open all the time. This is run in a subprocess. */ + void + keep_cd_open() + { + int fd; + struct flock fl; + extern end; + + for (fd = 0; fd < 256; fd++) + close(fd); + + if (fork()) + exit(0); + + if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0) + exit(0); + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0; + fl.l_len = 0; + if (fcntl(fd, F_SETLK, &fl) < 0) + exit(0); + + if (open(cd_device, 0) >= 0) + { + brk(&end); + pause(); + } + + exit(0); + } + + /* + * find_trkind(track, index) + * + * Start playing at a particular track and index, optionally using a particular + * frame as a starting position. Returns a frame number near the start of the + * index mark if successful, 0 if the track/index didn't exist. + * + * This is made significantly more tedious (though probably easier to port) + * by the fact that CDROMPLAYTRKIND doesn't work as advertised. The routine + * does a binary search of the track, terminating when the interval gets to + * around 10 frames or when the next track is encountered, at which point + * it's a fair bet the index in question doesn't exist. + */ + find_trkind(track, index, start) + int track, index, start; + { + int top = 0, bottom, current, interval, ret = 0, i; + + if (cd == NULL) + return; + + for (i = 0; i < cur_ntracks; i++) + if (cd->trk[i].track == track) + break; + bottom = cd->trk[i].start; + + for (; i < cur_ntracks; i++) + if (cd->trk[i].track > track) + break; + + top = i == cur_ntracks ? (cd->length - 1) * 75 : cd->trk[i].start; + + if (start > bottom && start < top) + bottom = start; + + current = (top + bottom) / 2; + interval = (top - bottom) / 4; + + do { + play_chunk(current, current + 75); + + if (cd_status() != 1) + return (0); + while (cur_frame < current) + if (cd_status() != 1 || cur_cdmode != PLAYING) + return (0); + else + susleep(1); + + if (cd->trk[cur_track - 1].track > track) + break; + + if (cur_index >= index) + { + ret = current; + current -= interval; + } + else + current += interval; + interval /= 2; + } while (interval > 2); + + return (ret); + } + + /* + * Simulate usleep() using select(). + */ + susleep(usec) + int usec; + { + struct timeval tv; + + timerclear(&tv); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return (select(0, NULL, NULL, NULL, &tv)); + } + + /* + * Read the initial volume from the drive, if available. Set cur_balance to + * the balance level (0-20, 10=centered) and return the proper setting for + * the volume knob. + * + * "max" is the maximum value of the volume knob. + */ + read_initial_volume(max) + int max; + { + int left, right; + + #ifdef SOUNDBLASTER + /* Send a Mixer IOCTL */ + if (mixer_fd >= 0) { + struct sb_mixer_levels levels; + if (ioctl(mixer_fd, MIXER_IOCTL_READ_LEVELS, &levels) == 0) { + left = levels.cd.l; + right = levels.cd.r; + } else + perror("SoundBlaster mixer read failed"); + } + #endif + left = unscale_volume(left, max); + right = unscale_volume(right, max); + + if (left < right) + { + cur_balance = (right - left) / 2 + 11; + if (cur_balance > 20) + cur_balance = 20; + + return (right); + } + else if (left == right) + { + cur_balance = 10; + return (left); + } + else + { + cur_balance = (right - left) / 2 + 9; + if (cur_balance < 0) + cur_balance = 0; + + return (left); + } + }