From: bnc@portia.si.macsch.com (Brian Casey)
Newsgroups: comp.unix.aix
Subject: Re: CD-ROM for audio
Keywords: CD-ROM, Audio
Date: 27 Jan 93 18:24:49 GMT
Organization: The MacNeal-Schwendler Corporation

In article <Jan26.174131.54628@yuma.ACNS.ColoState.EDU> copeland@lamar.ColoState.EDU (Jeffrey Copeland) writes:
>
>I started to convert xcdplayer, but gave up.  Since I'm also root I just use
>play.  The problem (If I can remember) was in trying to find register and/or
>port flags/addresses for the cd-rom.  If someone could get ahold of the source
>code for IBM's play it shouldn't be too difficult,  I just couldn't 
>locate the appropriate header files.
>
>Jeff Copeland -- Atmospheric Science



Attached is the source code to a very basic version of an audio CD player
for the IBM RISC System/6000.  Although in its current state, this code
only plays a CD from beginning to end, the source includes functions that
could be used to add a lot of additional features.

If you name this file playcd.c, you can compile and link it using the
following command:

	make playcd

After creating the executable, you must change the owner to root, and 
change the mode to setuid; only root has privileges to access the CD
drive for audio functions.

One favor - if you put together a full featured program, please send me
a copy.  I like to see how other people do things like this.  Thanks.

#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/cdrom.h>
#include <signal.h>
#include <setjmp.h>
#include <math.h>
 
 
#define STRAIGHT 1
#define STRAIGHT2 2
#define RANDOM  3
#define PROGRAMMED 4
#define HALT  5

#define CD_POSITION  0xC0
#define CD_PLAYAUDIO 0xC1
#define CD_PAUSE     0xC2
#define CD_OPEN      0xC4
#define CD_CLOSE     0xC5
#define CD_SENSE     0xC6
#define CD_READINFO  0xC7

#define PSEUDOHEX(i) ( ((i)/10) * 16 + ((i) % 10) )
#define REALHEX(i)   ( (((i) & 0xf0) >> 4) * 10 + ( (i) & 0x0f) )

#define True 1
#define False 0

typedef int Boolean;
 
int fd = -1;

int TrackInfo[100];
int local_time[100];
char rsbuf[4];
char pingbuf[10];
 
int ping_track();
void play_same();
void Oops() ;
Boolean test_unit_ready();
 
typedef enum { Mute=0, Left_channel=1, Right_channel=2, Stereo=3 }
        Play_mode_type;
Play_mode_type Last_play_mode = Stereo;
 
/******************************************************************************/
 
int ping_track()
{
  struct sc_iocmd         pt;
  int                     i, rc;
 
  for (i = 0; i < 10; i++)
    pingbuf[i] = 0xAA;
  pt.command_length = 0x0A;
  pt.scsi_cdb[0] = CD_SENSE;
  pt.scsi_cdb[1] = 0x09;
  for (i = 3 ; i < 9 ; i++) {
    pt.scsi_cdb[i] = 0x00;
  }
 
  pt.flags              = 0x08 | B_READ;
  pt.buffer             = pingbuf;
  pt.data_length        = 0x0A;
  pt.timeout_value      = 0x05;
  pt.status_validity    = 0x00;
  pt.scsi_bus_status    = 0x00;
  pt.adapter_status     = 0x00;
  
  rc = ioctl(fd, CDIOCMD, &pt);
  return(pingbuf[0]);
}
 
/******************************************************************************/
 
int play_straight(track)
uchar track;
{
  struct sc_iocmd         pt;
  int                     i, rc;
 
  if (test_unit_ready()==False) {
    Oops(&pt);
  }
  /* issue the play command */
  pt.command_length = 0x0A;
  pt.scsi_cdb[0] = CD_POSITION;
  pt.scsi_cdb[1] = 0x00; /* Do not play right away - pause after search */
  pt.scsi_cdb[2] = PSEUDOHEX(track);
  for (i = 3 ; i < 9 ; i ++) {
    pt.scsi_cdb[i] = 0x00;
  }
  pt.scsi_cdb[9] = 0x80; /* Position to given track */
  pt.flags              = SC_ASYNC;
  pt.buffer             = NULL;
  pt.data_length        = 0x00;
  pt.timeout_value      = 0x05;
  pt.status_validity    = 0x00;
  pt.scsi_bus_status    = 0x00;
  pt.adapter_status     = 0x00;
  rc = ioctl(fd, CDIOCMD, &pt);
  if (rc == -1) {
    Oops(&pt);
  } else {
    play_same();
  }
}
 
/******************************************************************************/
 
get_times(min, max, new_max)
int min, max;
int *new_max;
{
  struct sc_iocmd pt;
  int i, rc;
  int max_flag = 1;
  int track_loop;
  int time_loop;
  int minutes = 0;
  int seconds = 0;
 
  if (test_unit_ready()==False) {
    Oops(&pt);
    return(-1);
  }
 
  /* issue the read disc info command */
  pt.command_length = 0x0A;
  pt.scsi_cdb[0] = CD_READINFO;
  pt.scsi_cdb[1] = 0x02;
  for (i = 3 ; i < 9 ; i ++) {
    pt.scsi_cdb[i] = 0x00;
  }
 
  pt.scsi_cdb[9] = 0x80;
  pt.flags              = 0x08 | B_READ;
  pt.buffer             = rsbuf;
  pt.data_length        = 0x04;
  pt.timeout_value      = 0x05;
  pt.status_validity    = 0x00;
  pt.scsi_bus_status    = 0x00;
  pt.adapter_status     = 0x00;
 
  local_time[0] = 0;
  for (track_loop = min; track_loop <= max; track_loop++) {
    pt.scsi_cdb[2] = PSEUDOHEX(track_loop);
    
    for (i = 0; i < 4; i++)
      rsbuf[i] = 0x00;
    
    rc = ioctl(fd, CDIOCMD, &pt);
    
    minutes = REALHEX(rsbuf[0]);
    seconds = REALHEX(rsbuf[1]);
 
    if (rc == -1) {
      minutes = -1;
      seconds = -1;
      scanf("%d",&i);
      if (max_flag) {
	*new_max = track_loop - 1;
	max_flag = 0;
      }
    }
 
    local_time[track_loop] = 60 * minutes + seconds;
  }
 
  /* For the last track, we must get the total disk time to determine its
   * length
   */
 
  /* issue the read disc info command */
  pt.command_length = 0x0A;
  pt.scsi_cdb[0] = CD_READINFO;
  pt.scsi_cdb[1] = 0x01;
  for (i = 3 ; i < 9 ; i ++) {
    pt.scsi_cdb[i] = 0x00;
  }
 
  pt.flags              = 0x08 | B_READ;
  pt.buffer             = rsbuf;
  pt.data_length        = 0x04;
  pt.timeout_value      = 0x05;
  pt.status_validity    = 0x00;
  pt.scsi_bus_status    = 0x00;
  pt.adapter_status     = 0x00;
  rc = ioctl(fd, CDIOCMD, &pt);
  
  minutes = REALHEX(rsbuf[0]);
  seconds = REALHEX(rsbuf[1]);
  
  local_time[max+1] = 60 * minutes + seconds;
 
 
  for (track_loop = min; track_loop <= max; track_loop++)
    TrackInfo[track_loop] = local_time[track_loop + 1] - local_time[track_loop];
 
}
 
/******************************************************************************/
 
int get_tracks(min, max)
int *min, *max;
{
  struct sc_iocmd         pt;
  int                     i, rc;
 
  if (test_unit_ready()==False) {
    Oops(&pt);
    return(0);
  }
 
  /* issue the play command */
  pt.command_length = 0x0A;
  pt.scsi_cdb[0] = CD_READINFO;
  for (i = 1 ; i < 9 ; i ++) {
    pt.scsi_cdb[i] = 0x00;
  }
 
  for (i = 0; i < 4; i++)
    rsbuf[i] = 0xAA;
 
  pt.scsi_cdb[9] = 0x80;
  pt.flags              = 0x08 | B_READ;
  pt.buffer             = rsbuf;
  pt.data_length        = 0x04;
  pt.timeout_value      = 0x05;
  pt.status_validity    = 0x00;
  pt.scsi_bus_status    = 0x00;
  pt.adapter_status     = 0x00;
  
  rc = ioctl(fd, CDIOCMD, &pt);
  if (rc == -1) {
    Oops(&pt);
    return(rc);
  }
  *min = REALHEX(rsbuf[0]);
  *max = REALHEX(rsbuf[1]);
  return(1);
}
 
/******************************************************************************/
 
int open_CD(which)
int which;
{
  char buffer[20];

  if (fd == -1) {
    sprintf(buffer, "/dev/rcd%d", which);
    fd = openx(buffer, O_RDONLY, NULL, SC_DIAGNOSTIC);
  }
  return fd;
}
 
void close_CD()
{
  if ( fd != -1 ) {
    close(fd);
  }
}
 
Boolean test_unit_ready()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  /* Issue 2 test unit ready's */
  for (i=0 ; i<2 ; i++) {
    pt.command_length = 0x06;
    for (i = 0 ; i < 6 ; i ++) {
    pt.scsi_cdb[i] = 0x00;
  }
    pt.flags              = 0x00;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
  }
  if (rc == -1) {
/*
    Oops(&pt);
*/
    return False;
  }
  return True;
}
 
void cd_info()
{
  int first,last;
  int new_last;
  
  get_tracks(&first, &last);
  get_times(first, last, &new_last);
  ping_track();
}
 
int track_seconds(int Track)
{
  return TrackInfo[Track];
}
 
int which_track_is_playing()
{
  ping_track();
  return REALHEX(pingbuf[2]);
}

int time_gone()
{
  ping_track();
  return(REALHEX(pingbuf[4]) * 60 + REALHEX(pingbuf[5]));
}
 
void open_tray()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    /* issue the tray open command */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_OPEN;
    pt.scsi_cdb[1] = 0x01;
    for (i = 2 ; i < 9 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0x80;
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void close_tray()
/* This does not seem to work */
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    /* issue the tray close command */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_CLOSE;
    pt.scsi_cdb[1] = 0x01;
    for (i = 2 ; i < 9 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0x80;
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}

int CD_Position(track, totime)
int track;
int totime;
{
  struct sc_iocmd         pt;
  int                     i, rc;

  rc = totime + local_time[track];
  if ( test_unit_ready() ) {
    /* issue the position command */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_POSITION;
    for (i = 1 ; i < 9 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[2] = PSEUDOHEX(rc / 60);
    pt.scsi_cdb[3] = PSEUDOHEX(rc % 60);
    pt.scsi_cdb[9] = 0x40; /* Position to given time */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
  return rc;
}

void mute()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    Last_play_mode = Mute;
    /* issue the play audio command with muting on */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PLAYAUDIO;
    pt.scsi_cdb[1] = Last_play_mode; /* Muting on */
    for (i = 2 ; i < 8 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0xC0;  /* Type of play: playback completion ignored */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void play_left_channel()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    Last_play_mode = Left_channel;
    /* issue the play audio command with left channel only */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PLAYAUDIO;
    pt.scsi_cdb[1] = Left_channel; /* Left channel on */
    for (i = 2 ; i < 8 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0xC0;  /* Type of play: playback completion ignored */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void play_right_channel()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    Last_play_mode = Right_channel;
    /* issue the play audio command with right channel only */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PLAYAUDIO;
    pt.scsi_cdb[1] = Right_channel; /* Right channel on */
    for (i = 2 ; i < 8 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0xC0;  /* Type of play: playback completion ignored */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void play_stereo()
{
  struct sc_iocmd         pt;
  int                     i, rc;

  if ( test_unit_ready() ) {
    Last_play_mode = Stereo;
    /* issue the play audio command in stereo mode */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PLAYAUDIO;
    pt.scsi_cdb[1] = Last_play_mode; /* Both left and right channel */
    for (i = 2 ; i < 8 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0xC0;  /* Type of play: playback completion ignored */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void play_same()
{
  struct sc_iocmd         pt;
  int                     i, rc;
  if ( test_unit_ready() ) {
    /* issue the play audio command with the left/right/stereo unchanged */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PLAYAUDIO;
    pt.scsi_cdb[1] = Last_play_mode; /* unchanged play mode */
    for (i = 2 ; i < 8 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.scsi_cdb[9] = 0xC0;  /* Type of play: playback completion ignored */
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
      Oops(&pt);
    }
  }
}
 
void pause()
{
  struct sc_iocmd         pt;
  int                     i, rc;

  if ( test_unit_ready() ) {
    /* issue the still command */
    pt.command_length = 0x0A;
    pt.scsi_cdb[0] = CD_PAUSE;
    pt.scsi_cdb[1] = Last_play_mode; /* unchanged play mode */
    for (i = 2 ; i < 9 ; i ++) {
      pt.scsi_cdb[i] = 0x00;
    }
    pt.flags              = SC_ASYNC;
    pt.buffer             = NULL;
    pt.data_length        = 0x00;
    pt.timeout_value      = 0x05;
    pt.status_validity    = 0x00;
    pt.scsi_bus_status    = 0x00;
    pt.adapter_status     = 0x00;
    rc = ioctl(fd, CDIOCMD, &pt);
    if (rc == -1) {
/*
      Oops(&pt);
*/
    }
  }
}

jmp_buf env ;

main()
{
	int min, max, newmax, i ;
	extern int upd() ;

	open_CD(0) ;
	play_straight(1) ;
	get_tracks(&min,&max) ;
	get_times(min,max,&newmax) ;
	for (i = 1 ; i <= max ; i++)
		printf("%2d. %2d:%02d\n",i,TrackInfo[i]/60,TrackInfo[i] % 60) ;
	exit(0) ;
}	

void Oops()
{
}

int upd()
{
	int i, t1, t2, m1, m2, s1, s2 ;

	signal(SIGALRM,upd) ;
	alarm(1) ;
	return ;
}
/*
	i = which_track_is_playing() ;
	t1 = time_gone() ;
	m1 = t1 / 60 ;
	s1 = t1 % 60 ;
	t2 = track_seconds(i) ;
	m2 = t2 / 60 ;
	s2 = t2 % 60 ;

	fprintf(stderr,"\rTrack: %2d  %2d:%02d of %2d:%02d",
		i, m1, s1, m2, s2) ;
	fflush(stderr) ;
	if (i <= 0)
	{	
		close_CD() ;
		exit(0) ;
	}
	alarm(1) ;
	longjmp(env,1) ;
	return ;
}
*/
Newsgroups: comp.unix.aix