Subject: Re: audio CD players for NetBSD
To: Boudreault Benoit <boudreab@ERE.UMontreal.CA>
From: Scott Reynolds <scottr@edsi.org>
List: port-mac68k
Date: 01/27/1996 11:53:21
On Sat, 27 Jan 1996, Boudreault Benoit wrote:

> i was wondering if there is an audio CD player around that doesnt need Xwindows to run
> if it exists, anyway to point me in the right direction? :)

I've appended a little program I found somewhere -- not quite sure where,
someone might have given it to me :-) -- which works on my Mac + AppleCD
600e.  Note:  I haven't been particularly trusting of the CDIOC*
ioctl()'s, and I've had disk corruption that I can attribute only to using
the CD-ROM.  Your mileage may vary, but if I were you I'd make sure I have
a backup of anything important. 

Having said that, I've been using this recently quite a bit (in an 
attempt to reproduce the problem) and it's not yet given me a problem 
with my -current kernel.

--scott

#!/bin/sh
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	Makefile
#	cdplay.c
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
XPROG= cdplay
X
X.include <bsd.prog.mk>
END-of-Makefile
echo x - cdplay.c
sed 's/^X//' >cdplay.c << 'END-of-cdplay.c'
X#include <stdio.h>
X#include <errno.h>
X#include <sys/file.h>
X#include <sys/cdio.h>
X#include <sys/ioctl.h>
X
X#define DEVICE "/dev/rcd0c"
X
X#define COMMAND(s) strncmp(cmd,s,strlen(s))==0
X
Xstruct cd_toc_entry toc_buffer[100];
X
Xint cd_fd = -1;
Xint standalone;
X
Xchar *cmd;
X
Xint  pause (), resume (), stop (), eject (), setvol (int, int),
X     read_toc_header (struct ioc_toc_header *), read_toc_entry (int),
X     play_msf (int, int, int, int, int, int), play_track (int, int),
X     get_vol (int *, int *), status (int *, int *, int *, int *);
Xvoid open_cd ();
Xint input ();
X
Xmain (int argc, char **argv)
X{
X    int rc;
X
X    standalone = isatty (0);
X    while (input ()) {
X	rc = 0;
X	open_cd ();
X	if (COMMAND ("play")) {
X	    int start, end;
X	    sscanf (cmd+4, "%d %d", &start, &end);
X	    rc = play_track (start, end);
X	} else if (COMMAND ("help")) {
X		printf("play, pause, resume, stop, eject, setvol, getvol, tochdr, msfplay, tocentry, status, quit\n");
X	} else if (COMMAND ("pause"))
X	    rc = pause ();
X	else if (COMMAND ("resume"))
X	    rc = resume ();
X	else if (COMMAND ("stop"))
X	    rc = stop ();
X	else if (COMMAND ("eject")) {
X	    rc = eject ();
X	    close (cd_fd);
X	    cd_fd = -1;
X	} else if (COMMAND ("setvol")) {
X	    int l, r;
X	    sscanf (cmd+6, "%d %d", &l, &r);
X	    rc = setvol (l, r);
X	} else if (COMMAND ("getvol")) {
X	    int r, l;
X	    rc = getvol (&l, &r);
X	    printf ("Volume: left %d, right %d\n", l, r);
X	} else if (COMMAND ("tochdr")) {
X	    struct ioc_toc_header h;
X	    rc = read_toc_header (&h);
X	    printf ("%d %d %d\n", h.len, h.starting_track, h.ending_track);
X	} else if (COMMAND ("msfplay")) {
X	    int m1, m2, s1, s2, f1, f2;
X	    sscanf(cmd+7, "%d%d%d%d%d%d", &m1, &s1, &f1, &m2, &s2, &f2);
X	    rc = play_msf (m1, s1, f1, m2, s2, f2);
X	} else if (COMMAND ("tocentry")) {
X	    struct ioc_toc_header h;
X	    int i, n;
X	    rc = read_toc_header (&h);
X	    n =  h.ending_track - h.starting_track + 1;
X	    rc = read_toc_entry ((n+2)*sizeof(struct cd_toc_entry));
X	    toc_buffer[n].track = 255;
X	    for (i = 0; i <= n; i++)
X#ifdef __NetBSD__
X		printf ("Track %d: %d %d %d\n",
X			toc_buffer[i].track,
X			toc_buffer[i].addr[1],
X			toc_buffer[i].addr[2],
X			toc_buffer[i].addr[3]);
X#else
X		printf ("%d %d %d %d\n",
X			toc_buffer[i].track,
X			toc_buffer[i].addr.msf.minute,
X			toc_buffer[i].addr.msf.second,
X			toc_buffer[i].addr.msf.frame);
X#endif
X	} else if (COMMAND ("status")) {
X	    int trk, m, s, f;
X	    if (cd_fd < 0) 
X		rc = -1; /* assume ejected */
X	    else
X		rc = status (&trk, &m, &s, &f);
X	    printf ("%d %02d %d %d %d\n", rc, trk, m, s, f);
X	} else if (COMMAND("quit"))
X	    break;
X	fflush (stdout);
X	if (rc < 0 && standalone)
X	    perror("cdplayer");
X    }
X    exit (0);
X}
Xint
Xplay_track (int start, int end)
X{
X    struct ioc_play_track t;
X
X    t.start_track = start;
X    t.start_index = 1;
X    t.end_track = end;
X    t.end_index = 1;
X    return ioctl (cd_fd, CDIOCPLAYTRACKS, &t);
X}
Xint
Xpause ()
X{
X    return ioctl (cd_fd, CDIOCPAUSE);
X}
Xint
Xresume ()
X{
X    return (ioctl (cd_fd, CDIOCRESUME));
X}
Xint
Xstop ()
X{
X    return ioctl (cd_fd, CDIOCSTOP);
X}
Xint
Xeject ()
X{
X    int rc = ioctl (cd_fd, CDIOCALLOW);
X    return rc ? rc : ioctl (cd_fd, CDIOCEJECT);
X}
Xint
Xsetvol (int l, int r)
X{
X    struct ioc_vol v;
X    
X    v.vol[0] = l;
X    v.vol[1] = r;
X    v.vol[2] = 0;
X    v.vol[3] = 0;
X    return ioctl (cd_fd, CDIOCSETVOL, &v);
X}
Xint
Xgetvol (int  *l, int *r) 
X{
X    struct ioc_vol v;
X    if (ioctl (cd_fd, CDIOCGETVOL, &v) < 0) 
X	return -1;
X    *l = v.vol[0];
X    *r = v.vol[1];
X    return 0;
X}
Xint
Xread_toc_header (struct ioc_toc_header *h)
X{
X    return ioctl (cd_fd, CDIOREADTOCHEADER, (char *) h);
X}
Xint
Xread_toc_entry (int len)
X{
X    struct ioc_read_toc_entry t;
X
X    t.address_format = CD_MSF_FORMAT;
X    t.starting_track = 0;
X    t.data_len = len;
X    t.data = toc_buffer;
X    return ioctl (cd_fd, CDIOREADTOCENTRYS, (char *) &t);
X}
Xint
Xplay_msf (int start_m, int start_s, int start_f, 
X	  int end_m, int end_s, int end_f)
X{
X    struct ioc_play_msf a;
X
X    a.start_m = start_m;
X    a.start_s = start_s;
X    a.start_f = start_f;
X    a.end_m = end_m;
X    a.end_s = end_s;
X    a.end_f = end_f;
X    return ioctl (cd_fd, CDIOCPLAYMSF, (char *) &a);
X}
Xint
Xstatus (int *trk, int *min, int *sec, int *frame)
X{
X    struct ioc_read_subchannel s;
X    struct cd_sub_channel_info data;
X    bzero(&s, sizeof(s));
X    s.data = &data;
X    s.data_len = sizeof (data);
X    s.address_format = CD_MSF_FORMAT;
X    s.data_format = CD_CURRENT_POSITION;
X    open_cd ();
X    if (ioctl (cd_fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 
X	    return -1;
X    *trk = s.data->what.position.track_number;
X#ifdef __NetBSD__
X    *min = s.data->what.position.reladdr[1];
X    *sec = s.data->what.position.reladdr[2];
X    *frame = s.data->what.position.reladdr[3];
X#else
X    *min = s.data->what.position.reladdr.msf.minute;
X    *sec = s.data->what.position.reladdr.msf.second;
X    *frame = s.data->what.position.reladdr.msf.frame;
X#endif
X    return s.data->header.audio_status;
X}
X    
Xint
Xinput ()
X{
X    int	len;
X
X    if (standalone)
X	fprintf (stderr, "CD>");
X#ifdef __NetBSD__
X    cmd = fgetln (stdin, &len); 
X#else
X    cmd = fgetline (stdin, 0); 
X#endif
X    return cmd != 0;
X}
Xvoid
Xopen_cd ()
X{
X    int trk, m, s, f;
X    extern int errno;
X
X    if (cd_fd > -1)
X	return;
X    cd_fd = open (DEVICE, O_RDONLY);
X    if (cd_fd < 0) {
X	if (errno == ENXIO)
X	    return; /* open says 'Device not configured if there is no cd in */
X	perror("open");
X	exit (1);
X    }
X    if (status (&trk, &m, &s, &f) < 0 ) {
X	close (cd_fd);
X	cd_fd = -1;
X    }
X}
END-of-cdplay.c
exit