File indexing completed on 2024-04-21 04:54:23

0001 /*
0002  * This file is part of WorkMan, the civilized CD player library
0003  * Copyright (C) 1991-1997 by Steven Grimm <koreth@midwinter.com>
0004  * Copyright (C) by Dirk Försterling <milliByte@DeathsDoor.com>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public
0017  * License along with this library; if not, write to the Free
0018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0019  *
0020  *
0021  * IRIX specific.
0022  *
0023  * Taken from the kscd distribution
0024  *
0025  * Paul Kendall
0026  * paul@orion.co.nz, or
0027  * paul@kcbbs.gen.nz
0028  */
0029 
0030 #if defined(sgi) || defined(__sgi)
0031 
0032 #include "include/wm_config.h"
0033 
0034 /*
0035  * Yes, it was designed for WorkMan 1.4b3
0036  * Because I did start over from 1.3a, I disable it here.
0037  * There is no guarantee of getting working code by defining
0038  * CDDA yourself.
0039  *
0040  */
0041 #undef CDDA
0042 /*#define CDDA*/
0043 
0044 #include <sys/types.h>
0045 #include <sys/time.h>
0046 #include <stdio.h>
0047 #include <ctype.h>
0048 #include <string.h>
0049 #include <fcntl.h>
0050 #include <stdlib.h>
0051 #include <unistd.h>
0052 #include <signal.h>
0053 #include <sigfpe.h>
0054 #include <dmedia/cdaudio.h>
0055 #include "dmedia/audio.h"
0056 #include <errno.h>
0057 
0058 #include "include/wm_struct.h"
0059 #include "include/wm_cdtext.h"
0060 
0061 #define WM_MSG_CLASS WM_MSG_CLASS_PLATFORM
0062 
0063 void *malloc();
0064 char *strchr();
0065 
0066 int min_volume = 0;
0067 int max_volume = 255;
0068 
0069 #ifdef CDDA
0070 static int playing = STOPPED;
0071 static CDPLAYER *icd;
0072 static CDPARSER *icdp;
0073 static CDFRAME cdbuf[12];
0074 static ALport audioport;
0075 static ALconfig aconfig;
0076 static struct itimerval audiotimer = { {0,0}, {0,25000} };
0077 static int cdtrack=0;
0078 static int cdframe=0;
0079 static int cdstopframe=0;
0080 
0081 /*
0082  * Platform specific internal functions for CDDA
0083  */
0084 void
0085 cbprognum(void *arg, CDDATATYPES type, CDPROGNUM* prognum)
0086 {
0087   cdtrack = prognum->value;
0088 } /* cbprognum() */
0089 
0090 void
0091 cbabstime(void *arg, CDDATATYPES type, struct cdtimecode* atime)
0092 {
0093   cdframe = CDtctoframe(atime);
0094   if( cdframe == cdstopframe )
0095     playing = STOPPED;
0096 } /* cbabstime() */
0097 
0098 void
0099 cbplayaudio(void *arg, CDDATATYPES type, short* audio)
0100 {
0101     if(playing != PLAYING) return;
0102     ALwritesamps(audioport, audio, CDDA_NUMSAMPLES);
0103 } /* cbplayaudio() */
0104 
0105 static void
0106 alarmsignal()
0107 {
0108   int n, i;
0109   if(playing != PLAYING) return;
0110   if( ALgetfilled(audioport) < CDDA_NUMSAMPLES*8 )
0111     {
0112       /* Only get more samples and play them if we're getting low
0113        * this ensures that the CD stays close to the sound
0114        */
0115       n = CDreadda(icd, cdbuf, 12);
0116       if( n == 0 ) return;
0117       for( i=0 ; i<12 ; i++ )
0118     CDparseframe(icdp, &cdbuf[i]);
0119     }
0120   signal(SIGALRM, alarmsignal);
0121   setitimer(ITIMER_REAL, &audiotimer, NULL);
0122 } /* alarmsignal() */
0123 #endif
0124 
0125 /*--------------------------------------------------------*
0126  * Initialize the drive.  A no-op for the generic driver.
0127  *--------------------------------------------------------*/
0128 int
0129 gen_init( struct wm_drive *d )
0130 {
0131 #ifdef CDDA
0132   long Param[4];
0133   /* Set the audio rate to 44100Hz 16bit 2s-comp stereo */
0134   aconfig = ALnewconfig();
0135   ALsetwidth(aconfig, AL_SAMPLE_16);
0136   ALsetsampfmt(aconfig, AL_SAMPFMT_TWOSCOMP);
0137   ALsetchannels(aconfig, 2);
0138   Param[0] = AL_OUTPUT_RATE;      Param[1] = AL_RATE_44100;
0139   Param[2] = AL_CHANNEL_MODE;     Param[3] = AL_STEREO;
0140   ALsetparams(AL_DEFAULT_DEVICE, Param, 4);
0141   audioport = ALopenport("KDE KSCD Audio", "w", aconfig);
0142 
0143   /* setup cdparser */
0144   icdp = CDcreateparser();
0145   CDaddcallback(icdp, cd_audio, (CDCALLBACKFUNC)cbplayaudio, 0);
0146   CDaddcallback(icdp, cd_pnum, (CDCALLBACKFUNC)cbprognum, 0);
0147   CDaddcallback(icdp, cd_atime, (CDCALLBACKFUNC)cbabstime, 0);
0148 
0149   /* Lets handle those floating point exceptions expeditiously. */
0150   sigfpe_[_UNDERFL].repls = _ZERO;
0151   handle_sigfpes(_ON, _EN_UNDERFL, NULL, _ABORT_ON_ERROR, NULL);
0152 #endif
0153   return 0;
0154 } /* gen_init() */
0155 
0156 /*-------------------------------------------------------------*
0157  * Open the CD and figure out which kind of drive is attached.
0158  *-------------------------------------------------------------*/
0159 int
0160 gen_open( struct wm_drive *d )
0161 {
0162     CDSTATUS s;
0163 
0164     if (d->fd < 0)      /* Device already open? */
0165     {
0166         d->daux = CDopen(d->cd_device, "r");
0167         if (d->daux == 0) {
0168             return -6;
0169         }
0170 
0171         d->fd = 1;
0172 #ifdef CDDA
0173         icd = d->daux;
0174 #endif
0175     } else {
0176         wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "gen_open(): [device is open (fd=%d)]\n", d->fd);
0177     }
0178 
0179     CDgetstatus(d->daux, &s);
0180     if( s.state == CD_NODISC || s.state == CD_ERROR )
0181         return 1;
0182 
0183     return 0;
0184 } /* gen_open() */
0185 
0186 /*----------------------------------*
0187  * Send a SCSI command out the bus.
0188  *----------------------------------*/
0189 int
0190 gen_scsi( struct wm_drive *d, unsigned char *xcdb, int cdblen,
0191      char *retbuf, int retbuflen, int getreply)
0192 {
0193   return -1;
0194 } /* gen_scsi() */
0195 
0196 int
0197 gen_close( struct wm_drive *d )
0198 {
0199   if(d->fd != -1) {
0200     wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "closing the device\n");
0201     close(d->fd);
0202     d->fd = -1;
0203   }
0204   return 0;
0205 }
0206 
0207 /*--------------------------------------------------------------------------*
0208  * Get the current status of the drive: the current play mode, the absolute
0209  * position from start of disc (in frames), and the current track and index
0210  * numbers if the CD is playing or paused.
0211  *--------------------------------------------------------------------------*/
0212 int
0213 gen_get_drive_status( struct wm_drive *d, int oldmode,
0214                       int *mode, int *pos, int *track,
0215                       int *index )
0216 {
0217 #ifdef CDDA
0218   *mode = playing;
0219   *track = cdtrack;
0220   *pos = cdframe;
0221   *index = 0;
0222 #else
0223   CDSTATUS s;
0224   if( CDgetstatus(d->daux, &s)==0 )
0225     return -1;
0226   *pos = CDmsftoframe(s.min,s.sec,s.frame);
0227   *track = s.track;
0228   *index = 0;
0229   switch( s.state )
0230     {
0231     case CD_READY:  *mode = WM_CDM_STOPPED;
0232       break;
0233     case CD_STILL:
0234     case CD_PAUSED: *mode = WM_CDM_PAUSED;
0235       break;
0236     case CD_PLAYING: *mode = WM_CDM_PLAYING;
0237       break;
0238     default:        *mode = WM_CDM_UNKNOWN;
0239     }
0240 #endif
0241   return 0;
0242 } /* gen_get_drive_status() */
0243 
0244 /*-------------------------------------*
0245  * Get the number of tracks on the CD.
0246  *-------------------------------------*/
0247 int
0248 gen_get_trackcount( struct wm_drive *d, int *tracks )
0249 {
0250   CDSTATUS s;
0251   if( CDgetstatus(d->daux, &s)==0 )
0252     return -1;
0253   *tracks = s.last;
0254   return 0;
0255 } /* gen_get_trackcount() */
0256 
0257 /*---------------------------------------------------------*
0258  * Get the start time and mode (data or audio) of a track.
0259  *---------------------------------------------------------*/
0260 int
0261 gen_get_trackinfo( struct wm_drive *d, int track, int *data, int *startframe)
0262 {
0263   CDTRACKINFO i;
0264   int ret = CDgettrackinfo(d->daux, track, &i);
0265   if( ret == 0 )
0266     return -1;
0267   *data = 0;
0268   *startframe = CDmsftoframe(i.start_min,i.start_sec,i.start_frame);
0269   return 0;
0270 } /* gen_get_trackinfo() */
0271 
0272 /*-------------------------------------*
0273  * Get the number of frames on the CD.
0274  *-------------------------------------*/
0275 int
0276 gen_get_cdlen( struct wm_drive *d, int *frames )
0277 {
0278   CDSTATUS s;
0279   if( CDgetstatus(d->daux, &s)==0 )
0280     return -1;
0281   *frames = CDmsftoframe(s.total_min,s.total_sec,s.total_frame);
0282   return 0;
0283 } /* gen_get_cdlen() */
0284 
0285 /*------------------------------------------------------------*
0286  * Play the CD from one position to another (both in frames.)
0287  *------------------------------------------------------------*/
0288 int
0289 gen_play( struct wm_drive *d, int start, int end )
0290 {
0291 #ifdef CDDA
0292   int m, s, f;
0293   CDframetomsf(start, &m, &s, &f);
0294   CDseek(icd, m, s, f);
0295   cdstopframe = end;
0296   playing = PLAYING;
0297   signal(SIGALRM, alarmsignal);
0298   setitimer(ITIMER_REAL, &audiotimer, NULL);
0299 #else
0300   int m, s, f;
0301   CDframetomsf(start, &m, &s, &f);
0302   CDplayabs(d->daux, m, s, f, 1);
0303 #endif
0304   return 0;
0305 } /* gen_play() */
0306 
0307 /*---------------*
0308  * Pause the CD.
0309  *---------------*/
0310 int
0311 gen_pause( struct wm_drive *d )
0312 {
0313 #ifdef CDDA
0314   playing = WM_CDM_PAUSED;
0315 #else
0316   CDSTATUS s;
0317   if( CDgetstatus(d->daux, &s)==0 )
0318     return -1;
0319   if(s.state == CD_PLAYING)
0320     CDtogglepause(d->daux);
0321 #endif
0322   return 0;
0323 } /* gen_pause() */
0324 
0325 /*-------------------------------------------------*
0326  * Resume playing the CD (assuming it was paused.)
0327  *-------------------------------------------------*/
0328 int
0329 gen_resume( struct wm_drive *d )
0330 {
0331 #ifdef CDDA
0332   playing = WM_CDM_PLAYING;
0333   signal(SIGALRM, alarmsignal);
0334   setitimer(ITIMER_REAL, &audiotimer, NULL);
0335 #else
0336   CDSTATUS s;
0337   if( CDgetstatus(d->daux, &s)==0 )
0338     return -1;
0339   if(s.state == CD_PAUSED)
0340     CDtogglepause(d->daux);
0341 #endif
0342   return 0;
0343 } /* gen_resume() */
0344 
0345 /*--------------*
0346  * Stop the CD.
0347  *--------------*/
0348 int
0349 gen_stop( struct wm_drive *d )
0350 {
0351 #ifdef CDDA
0352   playing = WM_CDM_STOPPED;
0353 #else
0354   CDstop(d->daux);
0355 #endif
0356   return 0;
0357 } /* gen_stop() */
0358 
0359 /*----------------------------------------*
0360  * Eject the current CD, if there is one.
0361  *----------------------------------------*/
0362 int
0363 gen_eject( struct wm_drive *d )
0364 {
0365 #ifdef CDDA
0366   playing = WM_CDM_STOPPED;
0367 #endif
0368   CDeject(d->daux);
0369   return 0;
0370 } /* gen_eject() */
0371 
0372 /*----------------------------------------*
0373  * Close the CD tray
0374  *
0375  * Please edit and send changes to
0376  * milliByte@Deathsdoor.com
0377  *----------------------------------------*/
0378 
0379 int
0380 gen_closetray(struct wm_drive *d)
0381 {
0382   return -1;
0383 } /* gen_closetray() */
0384 
0385 /*---------------------------------------------------------------------*
0386  * Set the volume level for the left and right channels.  Their values
0387  * range from 0 to 100.
0388  *---------------------------------------------------------------------*/
0389 int
0390 gen_set_volume( struct wm_drive *d, int left, int right )
0391 {
0392   long Param[4];
0393   Param[0] = AL_LEFT_SPEAKER_GAIN;      Param[1] = left*255/100;
0394   Param[2] = AL_RIGHT_SPEAKER_GAIN;     Param[3] = right*255/100;
0395   ALsetparams(AL_DEFAULT_DEVICE, Param, 4);
0396   return 0;
0397 } /* gen_set_volume() */
0398 
0399 /*---------------------------------------------------------------------*
0400  * Read the initial volume from the drive, if available.  Each channel
0401  * ranges from 0 to 100, with -1 indicating data not available.
0402  *---------------------------------------------------------------------*/
0403 int
0404 gen_get_volume( struct wm_drive *d, int *left, int *right )
0405 {
0406   long Param[4];
0407   Param[0] = AL_LEFT_SPEAKER_GAIN;      Param[1] = 0;
0408   Param[2] = AL_RIGHT_SPEAKER_GAIN;     Param[3] = 0;
0409   ALgetparams(AL_DEFAULT_DEVICE, Param, 4);
0410   *left = Param[1] * 100 / 255;
0411   *right = Param[3] * 100 / 255;
0412   return 0;
0413 } /* gen_get_volume() */
0414 
0415 #endif
0416