This is playcd.c in view mode; [Download] [Up]
/* -*-C-*- ******************************************************************************* * * File: play3401.c * RCS: /usr/local/lib/cvs/play3401/play3401.c,v 1.3 1994/03/03 19:10:36 cedman Exp * Description: Play Toshiba 3401 * Author: Carl Edman * Created: Wed May 5 21:34:47 1993 * Modified: Thu Mar 3 13:48:25 1994 (Carl Edman) cedman@capitalist.princeton.edu * Modified: Sat Apr 08 1995 (Juergen Sell) js@icem.de + support the NEC player (3Xi that is, if it matters) + force search for drive to begin at /dev/sd2 hardcoded (this should become a paramter) * Modified Sat Apr 08 1995 js + support -d<number> parameter to set start search device to /dev/sd<number> * Modified Wed Apr 12 1995 js + added -l option to produce frames-listing + incorporated toshiba and nec support in a single source * Language: C * Package: N/A * Status: Alpha * * (C) Copyright 1993, but otherwise this file is perfect freeware. * ******************************************************************************* */ /* define exactly one of the following */ #if (0) /* Toshiba 3401 */ #define TOSHIBA #define NO_TRACK (0xaa) #define OPCODE (0x28) #define CONTROL (1<<6) #define DEVICE "TOSHIBA CD-ROM XM-3401TA" /* or try "TOSHIBA CD-ROM XM-4101TA" */ #define LBA (BCD((rp+offset)/(75*60))<<24)+(BCD(((rp+offset)/75)%60)<<16)+(BCD((rp+offset)%75)<<8) #else if (0) /* nec 3x */ #define NO_TRACK (0xA2) #define OPCODE (0xD4) #define CONTROL (0) #define DEVICE "NEC CD-ROM DRIVE:500" #define LBA (rp+offset) #endif #include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <libc.h> #include <signal.h> #include <errno.h> #include <sys/file.h> #include <sys/types.h> #include <sys/resource.h> #include <sound/sound.h> #include <sound/sounddriver.h> #include <sound/utilsound.h> #include "scsicommands.h" #define BCD(c) (((c)%10)+((((c)/10)%10)<<4)) #define BLOCKSIZE (2352) #define BUFBLOCK (6*75) #define READBLOCK (27) #define TRACKNO (100) #define GETNO() for(c=0;isascii(*d) && isdigit(*d);d++) c= (c*10)+(*d-'0') struct Mode { u_int data_length:8, medium_type:8, dev_parameter:8, bdescriptor_length:8; u_int density:8, nblocks:24; u_int mbz1:8, block_length:24; }; struct Toc_track_descriptor { u_int mbz1:8, adr:4, control:4, track_number:8, mbz2:8; u_int address; }; struct Toc { u_int toc_data_length:16, first:8, last:8; struct Toc_track_descriptor track[TRACKNO]; }; volatile int done,fillup; volatile int readp,playp; port_t devicePort,ownerPort,streamPort,replyPort; condition_t sync_threads; mutex_t position; cthread_t play_t; char *buf; struct Toc toc; int errflg=0,dontejectflg=0,recordflg=0,playflg=0; extern int getopt(int ac,char *av[],char *opts); extern int optind; extern char *optarg; int interpret_duration(const char *str,int *sf,int *ef) { int c,i; const char *d; for(i=0,d=str;*d;d++) if (*d=='-') i++; if (i>1) return -1; d=str; if (*d=='#') { d++; GETNO(); for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break; if (i>=TRACKNO) return -1; *sf=toc.track[i].address; if (*d=='+') d++; } else { *sf=toc.track[0].address; } if (*d && *d!='-') { GETNO(); if (*d==':') { d++; *sf+=c*60*75; GETNO(); if (c>=60) return -1; *sf+=c*75; if (*d==':') { d++; GETNO(); if (c>=75) return -1; *sf+=c; } } else { *sf+=c; } } if (!*d) d=str; else if (*d=='-') d++; else return -1; if (*d=='#') { d++; GETNO(); for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==c) break; if (i>=TRACKNO) return -1; if (*d=='+') { *ef=toc.track[i].address; d++; } else { *ef=toc.track[i+1].address; } } else if (*d=='\0') { for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==NO_TRACK) break; if (i>=TRACKNO) return -1; *ef=toc.track[i].address; } else { *ef=toc.track[0].address; } if (*d && *d!='-') { GETNO(); if (*d==':') { d++; *ef+=c*60*75; GETNO(); if (c>=60) return -1; *ef+=c*75; if (*d==':') { d++; GETNO(); if (c>=75) return -1; *ef+=c+1; } else { *ef+=75; } } else { *ef+=c+1; } } if (*d && *d!=-1) return -1; if (*sf<toc.track[0].address) return -1; for(i=0;i<TRACKNO;i++) if (toc.track[i].track_number==NO_TRACK) break; if (i>=TRACKNO) return -1; if (*ef>toc.track[i].address) return -1; return (*sf<*ef); } void play_suspend(int sig) { snddriver_stream_control(streamPort,0,SNDDRIVER_PAUSE_STREAM); signal(sig,SIG_DFL); raise(sig); } void play_continue(int sig) { signal(SIGTSTP,play_suspend); snddriver_stream_control(streamPort,0,SNDDRIVER_RESUME_STREAM); } void setdone(int sig) { snddriver_stream_control(streamPort,0,SNDDRIVER_ABORT_STREAM); done=1; } void play_completed(void *arg,int tag) { playp=tag; } any_t play_thread(any_t arg) { int rp,pp,tp,ep; unsigned short *p,*e,*r; int protocol=0; int err; snddriver_handlers_t handlers = { 0,0,0,play_completed,0,0,0,0,0,0,0,0 }; msg_header_t *replyMsg = 0; if (playflg) { replyMsg=malloc(MSG_SIZE_MAX); port_allocate(task_self(),&replyPort); SNDAcquire(SND_ACCESS_OUT,10,0,0,0,0,&devicePort,&ownerPort); snddriver_stream_setup(devicePort,ownerPort,SNDDRIVER_STREAM_TO_SNDOUT_44,vm_page_size/2,2,176400,352800,&protocol,&streamPort); } mutex_lock(position); tp=readp; while(!done) { while (!done && ((fillup && (readp<playp+(BUFBLOCK*3)/4))|| (!fillup && (readp<=tp)))) condition_wait(sync_threads,position); fillup=0; rp=readp; pp=playp; mutex_unlock(position); ep=tp; while (tp<rp) { ep=tp+75; if (ep>rp) ep=rp; if (tp%BUFBLOCK+(ep-tp)>BUFBLOCK) ep=tp+BUFBLOCK-(tp%BUFBLOCK); p=(unsigned short *)(buf+((tp%BUFBLOCK)*BLOCKSIZE)); e=(unsigned short *)(buf+((((ep-1)%BUFBLOCK)+1)*BLOCKSIZE)); for(r=p;r<e;r++) *r=NXSwapShort(*r); if (playflg) err=snddriver_stream_start_writing(streamPort, p,e-p, ep, 0,0, 0,1,0,0,0,0, replyPort); if (recordflg) write(1,p,(e-p)*sizeof(*p)); tp=ep; } mutex_lock(position); if (playflg) { replyMsg->msg_size=MSG_SIZE_MAX; replyMsg->msg_local_port=replyPort; while (msg_receive(replyMsg, RCV_TIMEOUT,0)==RCV_SUCCESS) { err=snddriver_reply_handler(replyMsg,&handlers); if (playp>=tp) fillup=1; condition_broadcast(sync_threads); } } else { playp=ep; condition_broadcast(sync_threads); } } done=1; mutex_unlock(position); if (playflg) { free(replyMsg); port_deallocate(task_self(),replyPort); SNDRelease(SND_ACCESS_OUT,devicePort,ownerPort); } return arg; } int main(int ac,char *av[]) { int c; int startframe,endframe; struct Mode page,opage; int aDeviceId= 0; int listFlag= 0; while((c=getopt(ac,av,"leprd:"))!=EOF) switch(c) { case 'l': listFlag++; break; case 'e': dontejectflg++; break; case 'p': playflg++; break; case 'r': recordflg++; break; case 'd': if (!sscanf( optarg, "%d", &aDeviceId) ) errflg++; break; case '?': default: errflg++; } if (geteuid()) { fprintf(stderr,"%s was not installed SUID root.\n",av[0]); exit(1); } if (errflg) { fprintf(stderr,"Usage: %s [-l] [-e] [-r] [-p] [-d<n>] duration ...\n",av[0]); exit(2); } if (playflg==0 && recordflg==0) playflg++; position=mutex_alloc(); sync_threads=condition_alloc(); signal(SIGHUP ,setdone); signal(SIGINT ,setdone); signal(SIGQUIT,setdone); signal(SIGILL ,setdone); signal(SIGTRAP,setdone); signal(SIGIOT ,setdone); signal(SIGEMT ,setdone); signal(SIGFPE ,setdone); signal(SIGBUS ,setdone); signal(SIGSEGV,setdone); signal(SIGSYS ,setdone); signal(SIGPIPE,setdone); signal(SIGTERM,setdone); signal(SIGXCPU,setdone); signal(SIGXFSZ,setdone); signal(SIGTSTP,play_suspend); signal(SIGCONT,play_continue); scsisettimeout(10); //js origianl 10 if (scsigetdev(DEVICE, aDeviceId)==-1) //js, begin at /dev/sd2 { fprintf(stderr,"Can't find CD player -- this version of %s is compiled for %s only.\n",av[0], DEVICE); //js exit(3); } if (scsiread6s(&opage,sizeof(opage),0x1a,0,0,0,sizeof(opage),0)) { fprintf(stderr,"Can't read mode page.\n"); exit(4); } opage.data_length=0; page=opage; page.density=0x82; page.block_length=0x930; #ifdef TOSHIBA if (scsiwrite6s(&page,sizeof(page),0x15,0,0,0,sizeof(page),0)) { fprintf(stderr,"Can't write mode page.\n"); exit(5); } #endif buf=malloc(BUFBLOCK*BLOCKSIZE); done=0; fillup=1; if (scsiread10(&toc,sizeof(toc),0x43,0,0,0,1,0,0,0,sizeof(toc),0)) { fprintf(stderr,"Can't read CDs table of contents.\n"); goto end; } for(c=0;c<TRACKNO;c++) { int i=toc.track[c].address; toc.track[c].address=(i&0xff)+75*((i>>8)&0xff)+75*60*((i>>16)&0xff); if (listFlag /* > 0 */) { if (toc.track[c].track_number != 0) fprintf(stderr, "[%d] %d\n", toc.track[c].track_number, toc.track[c].address/75); } } setpriority(PRIO_PROCESS,0,-10); playp=readp=0; play_t=cthread_fork(play_thread,0); if (recordflg) { SNDSoundStruct sndheader; sndheader.magic=SND_MAGIC; sndheader.dataLocation=28; sndheader.dataSize=0; /* a lie, but /usr/bin/sndplay dosen't care */ sndheader.dataFormat=SND_FORMAT_LINEAR_16; sndheader.samplingRate=SND_RATE_HIGH; sndheader.channelCount=2; sndheader.info[0]=0; sndheader.info[1]=0; sndheader.info[2]=0; sndheader.info[3]=0; write(1,&sndheader,28); /* write 28-byte header */ } for(c=optind;(c<ac) && !done;c++) { int offset,rp,pp,ep; if (!strcmp(av[c],"repeat")) { if (c==optind) { fprintf(stderr,"No durations before repeat\n"); continue; } c=optind; } if (interpret_duration(av[c],&startframe,&endframe)==-1) { fprintf(stderr,"Bad duration specificitation: %s\n",av[c]); continue; } mutex_lock(position); offset=startframe-readp; startframe-=offset; endframe-=offset; while(!done && readp<endframe) { while ((playp+BUFBLOCK<=readp) && !done) condition_wait(sync_threads,position); rp=readp; pp=playp; ep=rp+READBLOCK; if (ep>endframe) ep=endframe; if (rp%BUFBLOCK+(ep-rp)>BUFBLOCK) ep=rp+BUFBLOCK-(rp%BUFBLOCK); if (pp+BUFBLOCK<ep) ep=pp+BUFBLOCK; if (ep>rp) { mutex_unlock(position); if (scsiread10(buf+(rp%BUFBLOCK)*BLOCKSIZE,(ep-rp)*BLOCKSIZE,OPCODE,0,0,0,0,0,LBA,0,ep-rp,CONTROL)) goto end; mutex_lock(position); rp=readp=ep; condition_broadcast(sync_threads); } } mutex_unlock(position); } end: done=1; condition_broadcast(sync_threads); cthread_join(play_t); #ifdef TOSHIBA if (scsiwrite6s(&opage,sizeof(opage),0x15,0,0,0,sizeof(opage),0)) { fprintf(stderr,"Can't reset mode page.\n"); } #endif if (scsiclose(!dontejectflg)) { fprintf(stderr,"Can't eject CD.\n"); } exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.