/* -- cd.c -- support for the audio Apple CD Rom drive -- */ #include #include #include "ext.h" #include "ext_common.h" #include "ext_strings.h" #include "syscd.h" //#define SYNC_AT_SYSTASK //#define DTS_TEST /* additions to support ATAPI drives: default argument is 0, which specifies the ATAPI drive /* (belated) change history (what year, I wonder?) 6/6/95 added compatibility with universal headers low mem (UTableBase) 3/15 DDZ: added support for multiple-disk changers, set drive number to 0 otherwise note: "eject" does physically eject mechanism current track number outlet toc should do "init" otherwise times are inaccurate pause = 0 8/7 DDZ: added optional "first"-"sixth" arguments for finding CD players 8/9 DDZ: made CD take #1-#9 args again dolist: add ability for fast-forward and rewind to "go from here" w/ no arguments AudioControl The purpose of this call is to set the output volume for the drive's audio channels. Each channel can be given a value from zero to 255, zero indicating that the channel output is muted, 255 indicating maximum volume. Notes: ¥ This call can be used even if no disc is mounted. ¥ Beginning with driver version 4.0.5, the last volume setting used before powering down a drive will be restored when the drive is reinitialized. ¥ This command is not available on the AppleCD SC. Input Parameters: csCode 109 csParam[0]:15-8 Left channel volume (0-FFh). csParam[0]:7-0 Right Channel volume (0-FFh). csParam[1-10] Reserved. Status Return Codes: noErr Audio volume successfully set. */ #define MAX_CD_ARG 16 #define CD_MIN_INTERVAL 80 #define CD_REQ_COUNT 64 #define ReadTOC 100 #define ReadQ 101 #define ReadHead 102 #define ATrkSearch 103 #define APlay 104 #define APause 105 #define AStop 106 #define AStatus 107 #define AScan 108 #define AVolume 109 #define AEject 7 #define WhoIsThere 97 #define DiskStatus 8 #define DriverGestalt 43 #define SearchVerb 0 #define PlayVerb 1 #define StopVerb 2 #define PlayModeStereo 9 typedef struct cd { struct object c_ob; t_syscd *c_dev; short c_curdrive; short c_valid; t_atom c_cur[3]; short c_shake,c_play; CDCntrlParam c_cpb; CDSrchPlayParam c_spb[CD_REQ_COUNT]; Boolean c_sbusy[CD_REQ_COUNT]; CDPauseParam c_ppb; CDTrackParam c_tpb; CDStatusParam c_apb; CDDiskParam c_dpb; CDVolumeParam c_vpb; void *c_clock; void *c_rclock; long c_interval; t_cdtoc *c_toc; void *c_tocout; short c_argc; t_atom c_argv[MAX_CD_ARG]; short c_reporting; } t_cd; typedef struct _ej { VolumeParam a_pb; t_cd *a_x; } t_eject; t_eject cd_ejectbuf; void *cd_class; long cd_refcount = 0; Boolean cd_driveropen = false; t_symbol *ps_ord[6]; t_symbol *ps_dsp, *ps_driver, *ps_playthrough, *ps_ff, *ps_rew, *ps_nothing, *ps_list, *ps_cd; IOCompletionUPP cd_compupp, cd_tickupp, cd_ejecupp, cd_stopupp; void cd_opendriver(); void cd_select(t_cd *x, t_symbol *s, short argc, t_atom *argv); void cd_doselect(t_cd *x, t_symbol *s, short argc, t_atom *argv); void cd_init(t_cd *x); void cd_add(short refNum); void cd_bang(t_cd *x); void cd_dobang(t_cd *x); void cd_trackdurs(t_cd *x); void cd_resume(t_cd *x); void cd_int(t_cd *x, long n); void tconv(double n, long *m, long *s, long *b); void cd_float(t_cd *x, double n); void cd_list(t_cd *x, t_symbol *s, short ac, t_atom *av); void cd_volume(t_cd *x, t_symbol *s, short argc, t_atom *argv); short cd_vrefnum(t_cd *x, long n); void cd_unmount(t_cd *x, t_symbol *s, short argc, t_atom *argv); pascal void cd_ejectcompletion(ParmBlkPtr *pb); void cd_eject(t_cd *x, long n); void cd_scan(t_cd *x, t_symbol *dir, short ac, t_atom *av); void cd_readq(t_cd *x); void cd_drive(t_cd *x, long n); void cd_ff(t_cd *x, t_symbol *s, short ac, t_atom *av); void cd_rewind(t_cd *x, t_symbol *s, short ac, t_atom *av); void cd_tick(t_cd *x); void cd_rtick(t_cd *x); void cd_report(t_cd *x, short dolock, short requirePlay); void cd_search(t_cd *x, t_symbol *s, short ac, t_atom *av); void cd_stop(t_cd *x, long min, long sec, long block); void cd_fstop(t_cd *x, double f); void cd_searchto(t_cd *x, long min, long sec, long block, short verb); void cd_arginit(t_cd *x, Boolean dotoc); void *cd_new(t_symbol *s, short ac, t_atom *av); void cd_free(t_cd *x); void cd_endstop(t_cd *x); void cd_gettoc(t_cd *x, short outlet); void cd_toc(t_cd *x); void cd_dotoc(t_cd *x, void *arg); void cd_outlettoc(t_cd *x); long ConstrainL(long v, long lo, long hi); void cd_assist(t_cd *x, void *b, long m, long a, char *s); //short strncmp(char *a, char *b, short n); void cd_find(void); short cd_findnext(void); pascal void cd_stopcallback(ParmBlkPtr pb); pascal void cd_searchcallback(ParmBlkPtr pb); pascal void cd_tickcompletion(ParmBlkPtr pb); void cd_dosearchcallback(t_cd *x, t_symbol *s, short argc, t_atom *argv); ParmBlkPtr cd_getblock(t_cd *x, IOCompletionUPP proc); void cd_releaseblock(t_cd *x, ParmBlkPtr pb); void cd_noplaythrough(t_cd *x); void cd_playthrough(t_cd *x, long n); void cd_syncplay(t_cd *x, t_symbol *s, short argc, t_atom *argv); void cd_syncpause(t_cd *x, t_symbol *s, short argc, t_atom *argv); void cd_accrun(t_cd *x, short refNum); void cd_clearblock(ParamBlockRec *inPB); void main(fptr *f) { setup((t_messlist **)&cd_class, (method)cd_new ,(method)cd_free, (short)sizeof(t_cd), 0L, A_GIMME, 0); addint((method)cd_int); addfloat((method)cd_float); addbang((method)cd_bang); addmess((method)cd_list, "list", A_GIMME, 0); addmess((method)cd_search, "search", A_GIMME, 0); addmess((method)cd_stop, "stop", A_DEFLONG, A_DEFLONG, A_DEFLONG, 0); addmess((method)cd_fstop, "fstop", A_DEFFLOAT, 0); addmess((method)cd_init, "init", 0); addmess((method)cd_endstop, "endstop", 0); addmess((method)cd_eject, "eject", A_DEFLONG,0); addmess((method)cd_drive, "drive", A_LONG,0); addmess((method)cd_assist, "assist", A_CANT,0); addmess((method)cd_ff, "ff", A_GIMME,0); addmess((method)cd_rewind, "rewind", A_GIMME,0); addmess((method)cd_resume, "resume", 0); addmess((method)cd_toc, "toc", 0); addmess((method)cd_volume, "volume", A_GIMME, 0); addmess((method)cd_select, "select", A_GIMME, 0); addmess((method)cd_trackdurs,"trackdurs",0); //addmess((method)cd_playthrough, "playthrough", A_LONG, 0); finder_addclass("Devices","cd"); rescopy('STR#',3003); ps_ord[0] = gensym("first"); ps_ord[1] = gensym("second"); ps_ord[2] = gensym("third"); ps_ord[3] = gensym("fourth"); ps_ord[4] = gensym("fifth"); ps_ord[5] = gensym("sixth"); ps_dsp = gensym("dsp"); ps_driver = gensym("driver"); ps_playthrough = gensym("playthrough"); ps_ff = gensym("ff"); ps_rew = gensym("rew"); ps_nothing = gensym(""); ps_list = gensym("list"); ps_cd = gensym("cd"); cd_compupp = NewIOCompletionProc(cd_searchcallback); cd_tickupp = NewIOCompletionProc(cd_tickcompletion); cd_ejecupp = NewIOCompletionProc(cd_ejectcompletion); cd_stopupp = NewIOCompletionProc(cd_stopcallback); } void cd_opendriver() { if (cd_driveropen) return; syscd_open(ps_cd); cd_driveropen = syscd_devcount? true : false; } void cd_select(t_cd *x, t_symbol *s, short argc, t_atom *argv) { if (argc) defer(x,(method)cd_doselect,s,argc,argv); } void cd_doselect(t_cd *x, t_symbol *s, short argc, t_atom *argv) { t_syscd *old; if (!cd_driveropen) syscd_open(ps_cd); if (!cd_driveropen) return; old = x->c_dev; x->c_dev = syscd_select(ps_cd,argc,argv); #ifdef NEEDTOSTOP if (x->c_dev != old) { if (x->c_dev) syscd_stopplay(x->c_dev,x->c_curdrive); } #endif } void cd_init(t_cd *x) { defer(x,(method)cd_dotoc,0,0,0); #ifdef OLD if (!cd_devcount) { syscd_open(ps_cd); if (syscd_devcount) cd_arginit(x,false); } if (x->c_dev) { cd_gettoc(x,false); } #endif } void cd_toc(t_cd *x) { defer(x,(method)cd_dotoc,ps_nothing,0,0); } void cd_dotoc(t_cd *x, void *arg) { short err; if (!x->c_dev) { x->c_dev = syscd_select(ps_cd,x->c_argc,x->c_argv); if (!x->c_dev) return; } err = syscd_gettoc(x->c_dev,x->c_curdrive,&x->c_toc,arg? true : false); if (err) error("cd: unable to get table of contents, error %d",err); x->c_valid = !err; if (arg && x->c_valid) cd_outlettoc(x); } void cd_outlettoc(t_cd *x) { t_atom ap[4]; short i; INDEX *p; double start,end,dur; t_cdtoc *toc = x->c_toc; if (!toc) return; SETLONG(ap,0); SETLONG(ap+1,0); SETLONG(ap+2,0); SETLONG(ap+3,0); for (i = 1, p = toc->c_toc; i <= toc->c_ntracks; i++,p++) { ap->a_w.w_long = i; (ap+1)->a_w.w_long = bcd2x(p->min); (ap+2)->a_w.w_long = bcd2x(p->sec); (ap+3)->a_w.w_long = bcd2x(p->blk); outlet_list(x->c_tocout,ps_list,4,ap); } } void cd_trackdurs(t_cd *x) { t_atom ap[4]; short i; INDEX *p; double start,end,dur; t_cdtoc *toc = x->c_toc; if (!x->c_valid) return; if (!toc) return; SETLONG(ap,0); SETFLOAT(ap+1,0.0); for (i = 1, p = toc->c_toc; i <= toc->c_ntracks; i++) { ap->a_w.w_long = i; // calc dur start = (bcd2x(p->min) * 60000.) + (bcd2x(p->sec) * 1000.) + ((1000./75.) * bcd2x(p->blk)); p++; end = (bcd2x(p->min) * 60000.) + (bcd2x(p->sec) * 1000.) + ((1000./75.) * bcd2x(p->blk)); dur = end - start; (ap+1)->a_w.w_float = dur; outlet_list(x->c_tocout,ps_list,2,ap); } } void cd_bang(t_cd *x) { if (!x->c_dev) return; defer(x,(method)cd_dobang,0L,0,0L); } void cd_dobang(t_cd *x) { cd_report(x,false,false); } void cd_resume(t_cd *x) { OSErr err; short savelock; if (!x->c_dev) return; if (syscd_devcount) { err = syscd_control(x->c_dev,(CDCntrlParam *)&x->c_apb,x->c_curdrive,AStatus,false); if (!err) { cd_searchto(x,(long)bcd2x(x->c_apb.absMin), (long)bcd2x(x->c_apb.absSec), (long)bcd2x(x->c_apb.absBlock),PlayVerb); } } } /* play a track if non-zero, otherwise stop a playing track */ void cd_int(t_cd *x, long n) { OSErr res; short in; ParmBlkPtr pb; CDTrackParam *tpb; CDPauseParam *ppb; t_atom a; if (!x->c_dev) return; if (n) { if (n <= 0 || n > x->c_toc->c_ntracks) { error("cd: invalid track number %ld",n); return; } pb = cd_getblock(x,cd_compupp); tpb = (CDTrackParam *)pb; if (!pb) return; in = (short)n; tpb->trackFormat = 0x02; tpb->isZero[0] = 0; tpb->isZero[1] = 0; tpb->isZero[2] = 0; tpb->trackNum = x2bcd(in); tpb->stopAddrFlag = 0; tpb->playMode = PlayModeStereo; res = syscd_control(x->c_dev,(CDCntrlParam *)tpb,x->c_curdrive,APlay,true); if (res) error("cd: PBControlAsync err %d",res); } else { pb = cd_getblock(x,cd_stopupp); if (!pb) return; ppb = (CDPauseParam *)pb; ppb->pauseState = 1; res = syscd_control(x->c_dev,(CDCntrlParam *)ppb,x->c_curdrive,APause,true); } } void cd_clearblock(ParamBlockRec *inPB) { short i; for (i = 0; i < sizeof (ParamBlockRec); i++) *((char *)inPB + i) = 0; } void tconv(double n, long *m, long *s, long *b) { *m = n/60.0; *s = n - *m*60; *b = (n-(*m*60+*s))*75.0; } void cd_float(t_cd *x, double n) { long m,s,b; short res; if (!x->c_dev) return; tconv(n, &m, &s, &b); //post("%ld %ld %ld",m,s,b); cd_searchto(x,m,s,b,PlayVerb); } void cd_list(t_cd *x, t_symbol *s, short ac, t_atom *av) { if (!x->c_dev) return; if (ac==3) { cd_searchto(x,av->a_w.w_long,(av+1)->a_w.w_long,(av+2)->a_w.w_long,PlayVerb); } } void cd_volume(t_cd *x, t_symbol *s, short argc, t_atom *argv) { long leftVol,rightVol; short res; if (!x->c_dev) return; if (!argc || argv->a_type != A_LONG) return; leftVol = argv->a_w.w_long; leftVol = ConstrainL(leftVol,0,255); if (argc < 2 || (argv + 1)->a_type != A_LONG) rightVol = leftVol; else rightVol = (argv + 1)->a_w.w_long; rightVol = ConstrainL(rightVol,0,255); x->c_vpb.leftVol = leftVol; x->c_vpb.rightVol = rightVol; res = syscd_control(x->c_dev,(CDCntrlParam *)&x->c_vpb,x->c_curdrive,AVolume,false); // this should be async if (res) error("cd: volume err %d",res); } short cd_vrefnum(t_cd *x, long n) { VCB *q; QHdrPtr qh; register short i; qh = GetVCBQHdr(); for (q = (VCB *)qh->qHead; q; q = (VCB *)q->qLink) { if (q->vcbDRefNum==x->c_dev->d_refNum) { if ((n==-1) || (n==q->vcbDrvNum)) return (q->vcbVRefNum); } } return (0); } void cd_unmount(t_cd *x, t_symbol *s, short argc, t_atom *argv) { short vol = argv->a_w.w_long; short err; err = Eject(0L,vol); if (err) error("cd: eject error %d",err); err = UnmountVol(0L,vol); if (err) error("cd: unmount error %d",err); } pascal void cd_ejectcompletion(ParmBlkPtr *pb) { CDCntrlParam *cpb = (CDCntrlParam *)pb; t_cd *x; t_atom a; BlockMove(cpb->unused,&x,sizeof(t_cd *)); if (!cpb->ioCompletion) { a.a_type = A_LONG; a.a_w.w_long = cpb->ioVRefNum; defer_low(x,(method)cd_unmount,0L,1,&a); } #ifdef USE_FILE_SYSTEM t_eject *ex = (t_eject *)pb; if (!ex->a_pb.ioResult) { ex->a_pb.ioCompletion = cd_unmoupp; ex->a_pb.ioResult = 1; PBUnmountVolAsync(ex); } #endif } void cd_eject(t_cd *x, long n) { OSErr err; Str255 name; short vol; if (!x->c_dev) return; syscd_eject(x->c_dev,x->c_curdrive); } #ifdef USE_FILE_SYSTEM x->c_cpb.ioCompletion = cd_ejecupp; BlockMove(x,&x->c_cpb.unused,sizeof(t_cd *)); syscd_control(x->c_dev,&x->c_cpb,x->c_curdrive,AEject,true); if (n != 0 && x->c_dev->d_numDrives > 1 && InRange(n,1,CD_MAX_DRIVES)) { n = x->c_dev->d_driveNums[n-1]; } else n = -1; vol = cd_vrefnum(x,n?n:-1L); if (!vol) goto err; cd_ejectbuf.a_pb.ioCompletion = cd_ejecupp; cd_ejectbuf.a_pb.ioResult = 1; cd_ejectbuf.a_pb.ioNamePtr = 0; cd_ejectbuf.a_pb.ioVRefNum = vol; cd_ejectbuf.a_x = x; err = PBEjectAsync(&cd_ejectbuf); } #endif void cd_scan(t_cd *x, t_symbol *dir, short ac, t_atom *av) { short in; OSErr res; long min,sec,block; ParmBlkPtr pb = cd_getblock(x,cd_compupp); CDSrchPlayParam *spb = (CDSrchPlayParam *)pb; CDTrackParam *tpb = (CDTrackParam *)pb; if (!x->c_dev) return; if (ac==1 && av->a_type==A_LONG) { /* track to start at */ in = av->a_w.w_long; tpb->trackFormat = 0x02; tpb->isZero[0] = 0; tpb->isZero[1] = 0; tpb->isZero[2] = 0; tpb->trackNum = x2bcd(in); tpb->stopAddrFlag = dir == ps_rew? 1 : 0; res = syscd_control(x->c_dev,(CDCntrlParam *)tpb,x->c_curdrive,AScan,false); cd_releaseblock(x,(ParmBlkPtr)tpb); if (res) error("cd: track scan %ld error %ld",av->a_w.w_long,(long)res); else if (x->c_interval) { x->c_shake = 3; x->c_play = 1; clock_delay(x->c_clock,0L); } } else if (ac==3 && av->a_type==A_LONG && (av+1)->a_type==A_LONG && (av+2)->a_type==A_LONG) { min = av->a_w.w_long; sec = (av+1)->a_w.w_long; block = (av+2)->a_w.w_long; spb->playAddrFormat = 0x01; spb->isZero = 0; min = ConstrainL(min,0L,75L); sec = ConstrainL(sec,0L,59L); block = ConstrainL(block,0L,74L); spb->absMin = x2bcd(min); spb->absSec = x2bcd(sec); spb->absBlock = x2bcd(block); spb->stopAddrFlag = dir == ps_rew? 1 : 0; res = syscd_control(x->c_dev,(CDCntrlParam *)spb,x->c_curdrive,AScan,false); if (res) error("cd: scan error %ld",(long)res); else if (x->c_interval) { x->c_shake = 3; x->c_play = 1; clock_delay(x->c_clock,0L); } } else if (!ac) { /* ff/rew from "where you are" */ res = syscd_control(x->c_dev,(CDCntrlParam *)&x->c_apb,x->c_curdrive,AStatus,false); if (!res) { spb->playAddrFormat = 0x01; spb->isZero = 0; spb->stopAddrFlag = dir == ps_rew? 1 : 0; spb->absMin = x->c_apb.absMin; spb->absSec = x->c_apb.absSec; spb->absBlock = x->c_apb.absBlock; res = syscd_control(x->c_dev,(CDCntrlParam *)spb,x->c_curdrive,AScan,false); if (res) error("cd: scan error %ld",(long)res); else if (x->c_interval) { x->c_shake = 3; x->c_play = 1; clock_delay(x->c_clock,0L); } } } else { error("cd: bad arguments to ff/rewind"); } } void cd_drive(t_cd *x, long n) { if (!x->c_dev) return; if (InRange(n,1,x->c_dev->d_numDrives)) x->c_curdrive = n; } void cd_ff(t_cd *x, t_symbol *s, short ac, t_atom *av) { defer(x,(method)cd_scan,ps_ff,ac,av); } void cd_rewind(t_cd *x, t_symbol *s, short ac, t_atom *av) { defer(x,(method)cd_scan,ps_rew,ac,av); } void cd_tick(t_cd *x) { short require; if (x->c_shake) require = x->c_shake--; else require = 0; if (!x->c_reporting) cd_report(x,true,require); if (x->c_interval && (x->c_play || x->c_shake)) { //debug_printf("delaying %d",x->c_play); clock_delay(x->c_clock,x->c_interval); } } void cd_report(t_cd *x, short dolock, short requirePlay) { OSErr err; short savelock; ParmBlkPtr pb; CDSrchPlayParam *spb; if (!x->c_dev) return; pb = cd_getblock(x,cd_tickupp); if (!pb) return; x->c_reporting = true; spb = (CDSrchPlayParam *)pb; spb->unused[4] = requirePlay; err = syscd_control(x->c_dev,(CDCntrlParam *)pb,x->c_curdrive,AStatus,true); } pascal void cd_tickcompletion(ParmBlkPtr pb) { t_atom a; CDSrchPlayParam *spb = (CDSrchPlayParam *)pb; CDStatusParam *apb = (CDStatusParam *)pb; t_cd *x; Boolean requirePlay; BlockMove(spb->unused,&x,sizeof(t_cd *)); x->c_reporting = false; x->c_play = !apb->audioStatus; requirePlay = spb->unused[4]; if (x->c_play || !requirePlay) { /* playing */ x->c_cur[0].a_w.w_long = bcd2x(apb->absMin); x->c_cur[1].a_w.w_long = bcd2x(apb->absSec); x->c_cur[2].a_w.w_long = bcd2x(apb->absBlock); clock_delay(x->c_rclock,0); // can't output directly from async callback } cd_releaseblock(x,pb); } void cd_rtick(t_cd *x) { outlet_list(x->c_ob.o_outlet,0L,3,x->c_cur); } void cd_search(t_cd *x, t_symbol *s, short ac, t_atom *av) { if (!x->c_dev) return; if (ac==3) cd_searchto(x,av->a_w.w_long,(av+1)->a_w.w_long,(av+2)->a_w.w_long,SearchVerb); } void cd_stop(t_cd *x, long min, long sec, long block) { if (!x->c_dev) return; if (min==0 && sec==0 && block==0) cd_int(x,0L); else cd_searchto(x,min,sec,block,StopVerb); } void cd_fstop(t_cd *x, double f) { long min,sec,block; if (!x->c_dev) return; tconv(f, &min, &sec, &block); cd_searchto(x,min,sec,block,StopVerb); } void cd_searchto(t_cd *x, long min, long sec, long block, short verb) { short sFlag; OSErr err; ParmBlkPtr pb = cd_getblock(x,cd_compupp); CDSrchPlayParam *spb = (CDSrchPlayParam *)pb; short command; if (!pb) return; switch (verb) { case SearchVerb: command = ATrkSearch; sFlag = 0; break; case PlayVerb: command = ATrkSearch; sFlag = 1; break; case StopVerb: command = AStop; sFlag = 0; break; } spb->playAddrFormat = 0x01; spb->isZero = 0; min = ConstrainL(min,0L,75L); sec = ConstrainL(sec,0L,59L); block = ConstrainL(block,0L,74L); spb->absMin = x2bcd(min); spb->absSec = x2bcd(sec); spb->absBlock = x2bcd(block); spb->stopAddrFlag = sFlag; spb->playMode = PlayModeStereo; err = syscd_control(x->c_dev,(CDCntrlParam *)spb,x->c_curdrive,command,true); if (err) error("cd: PBControlAsync err %d",err); } pascal void cd_searchcallback(ParmBlkPtr pb) { t_atom a; CDSrchPlayParam *spb = (CDSrchPlayParam *)pb; t_cd *x; BlockMove(spb->unused,&x,sizeof(t_cd *)); a.a_type = A_LONG; a.a_w.w_long = spb->ioResult; defer_low(x,(method)cd_dosearchcallback,0L,1,&a); if (!spb->ioResult) { x->c_play = 1; x->c_shake = 3; clock_delay(x->c_clock,0); } cd_releaseblock(x,pb); } // everything the search callback does, and less pascal void cd_stopcallback(ParmBlkPtr pb) { t_atom a; CDSrchPlayParam *spb = (CDSrchPlayParam *)pb; t_cd *x; BlockMove(spb->unused,&x,sizeof(t_cd *)); cd_releaseblock(x,pb); } void cd_dosearchcallback(t_cd *x, t_symbol *s, short argc, t_atom *argv) { short err; err = argv->a_w.w_long; if (err) { if (err == -50) post("cd: search out of range"); else post("search result %ld",(long)err); } else if (x->c_interval) { x->c_play = 1; x->c_shake = 3; clock_delay(x->c_clock,0L); } } ParmBlkPtr cd_getblock(t_cd *x, IOCompletionUPP proc) { long i; CDSrchPlayParam *spb; for (i = 0; i < CD_REQ_COUNT; i++) { if (!x->c_sbusy[i]) { x->c_sbusy[i] = true; spb = x->c_spb + i; spb->ioCompletion = proc; spb->ioResult = 1; BlockMove(&x,spb->unused,sizeof(t_cd *)); return (ParmBlkPtr)spb; } } error("cd: all blocks busy"); return 0; // all blocks are busy } void cd_releaseblock(t_cd *x, ParmBlkPtr pb) { long i; for (i = 0; i < CD_REQ_COUNT; i++) { if (pb == (ParmBlkPtr)(x->c_spb + i)) { x->c_sbusy[i] = false; return; } } } void *cd_new(t_symbol *s, short ac, t_atom *av) { t_cd *x; short i; if (!(cd_refcount++)) cd_opendriver(); x = (t_cd *)newobject(cd_class); x->c_curdrive = 1; x->c_dev = 0; x->c_valid = 0; cd_doselect(x,s,ac,av); x->c_toc = 0; x->c_interval = 0; x->c_reporting = false; /* parse arguments */ x->c_argc = ac; BlockMove(av,x->c_argv,ac * sizeof(t_atom)); if (ac >= 2 && (av+1)->a_type == A_LONG) x->c_interval = (av+1)->a_w.w_long; if (x->c_interval < 0) x->c_interval = 0; else if (x->c_interval > 0 && x->c_interval < CD_MIN_INTERVAL) x->c_interval = CD_MIN_INTERVAL; x->c_clock = clock_new(x,(method)cd_tick); x->c_rclock = clock_new(x,(method)cd_rtick); x->c_cur[0].a_type = A_LONG; x->c_cur[1].a_type = A_LONG; x->c_cur[2].a_type = A_LONG; for (i = 0; i < CD_REQ_COUNT; i++) x->c_sbusy[i] = false; x->c_tocout = outlet_new(x,0); outlet_new(x,"list"); cd_dotoc(x,0); return x; } void cd_free(t_cd *x) { if (x->c_toc) DisposePtr((Ptr)x->c_toc); if (x->c_clock) freeobject(x->c_clock); if (x->c_rclock) freeobject(x->c_rclock); } void cd_endstop(t_cd *x) { long m,s,b; if (!x->c_dev) return; if (!x->c_toc) return; m = bcd2x(x->c_toc->c_toc[x->c_toc->c_ntracks].min); s = bcd2x(x->c_toc->c_toc[x->c_toc->c_ntracks].sec); b = bcd2x(x->c_toc->c_toc[x->c_toc->c_ntracks].blk); /* subtract 1 from block */ --b; if(b<0) { b = 0; --s; if(s<0) { s= 0; --m; if(m<0) m = 0; } } cd_searchto(x,m,s,b,StopVerb); } long ConstrainL(long v, long lo, long hi) { if (v < lo) return (lo); if (v > hi) return (hi); return (v); } void cd_assist(t_cd *x, void *b, long m, long a, char *s) { assist_string(3003,m,a,1,2,s); }