;TechPop Wes Philp›; 160 Sand Pine Road›; Indialantic, FL 32903›;›DEFINE END="$FE", ;end of preset› T="$FD", ;timbre› W="$FC", ;wait› M="$FB", ;metronome› EOL="$FF", ;end-of-list› A="$A",B="$B",C="$C",D="$D",› E="$E",F="$F",› QUIET="0 0 0"›CARD ARRAY PRESETS(1)=[›INCLUDE "PRESETS"›EOL]›BYTE ARRAY TIMBRES(1)=[›INCLUDE "TIMBRES"›EOL]›;›; TRAP -------------------------------›BYTE BRKKEY=$11›PROC TRAP(BYTE N)›;stop on BREAK or any OS error›BRKKEY=0›RETURN›;›; ALERT ------------------------------›PROC ALERT(BYTE ARRAY STRING)›PRINTF("%E%S%E",STRING)›RETURN›;›; BUILD_DLI --------------------------›MODULE›CARD VDLI_OLD=[0],› CLOCK=[0];counts at 4*frame rate›PROC BUILD_DLI()›;delay list interrupt servicer›;increments 16-bit CLOCK›;›BYTE ARRAY DLISERVE(1)=[›$48 ;PHA›$18 ;CLC›$A9 $01 ;LDA 1›$6D] ;ADC LSB›BYTE POINTER D1=CLOCK›BYTE ARRAY D2(1)=[›$8D] ;STA LSB›BYTE POINTER D3=CLOCK›BYTE ARRAY D4(1)=[›$90 $03 ;BCC 3›$EE] ;INC MSB›BYTE POINTER D5=CLOCK+1›BYTE ARRAY D6(1)=[›$68 ;PLA›$40] ;RTI›;›BYTE ARRAY MOD_LIST(1)=[›0 8 16 24]›BYTE I,› NMIEN=$D40E›CARD VDLI=$200›BYTE POINTER BP›CARD POINTER SDLST=560›;›;install the DLI service routine›VDLI_OLD=VDLI›VDLI=DLISERVE›NMIEN=$C0 ;DLI and VBI›;modify the display list›FOR I=0 TO 3 DO› BP=2+MOD_LIST(I)+SDLST^› IF MOD_LIST(I)>=2 THEN› BP==+2› FI› BP^==%$80›OD ›BP=SDLST^›RETURN›; ›; UNBUILD_DLI ------------------------›PROC UNBUILD_DLI()›BYTE NMIEN=$D40E›CARD VDLI=$200 ›NMIEN=$40 ;VBI only›VDLI=VDLI_OLD›GRAPHICS(0)›RETURN›;›; KBD --------------------------------›BYTE FUNC KBD(BYTE KCHAN,SCHAN)›;KCHAN=K: channel #›;SCHAN=S: channel #›;RETURN:›; - operator-entered preset # (0-9)›; - $FF no entry›; - $FE BREAK›; - $FD invalid input›; - $FC >›; - $FB <›BYTE CH=$02FC, ;keyboard character› N,› CR=[155]›IF BRKKEY=0 THEN› ;BREAK key› N=$FE› BRKKEY=$FF›ELSEIF CH=$FF THEN› ;no entry› N=$FF›ELSE› ;read the character› N=GETD(KCHAN)› IF BRKKEY=0 THEN› N=$FE› BRKKEY=$FF› ELSEIF N='> THEN› PUTD(SCHAN,N)› N=$FC› ELSEIF N='< THEN› PUTD(SCHAN,N)› N=$FB› ELSEIF N>= '0 AND N<='9 THEN› PUTD(SCHAN,N)› PUTD(SCHAN,CR)› N==-'0› ELSEIF N=CR THEN › N=$FF ;ignore RETURN› ELSE› N=$FD ;invalid input› FI›FI›RETURN(N)›;›; FIND_PRESET ------------------------›CARD FUNC FIND_PRESET(BYTE N)›;N=preset # (0,1 ...)›;RETURN:›; - preset data address›; - $FFFF if not found›BYTE I,› PV›CARD POINTER P›P=PRESETS›I=0›DO› PV=P^ ;LSB only› IF I=N AND PV#EOL THEN› ;done› RETURN(P)› ELSEIF PV=EOL THEN› ;e.d-of-string found› RETURN($FFFF)› ELSEIF PV=END THEN› I==+1› FI› P==+2›OD›;›; PREP_TIMBRE ------------------------›BYTE FUNC PREP_TIMBRE()›;RETURN: number of timbres defined›BYTE NT,› I,› DIST,› L›BYTE POINTER BP›BP=TIMBRES›FOR NT=0 TO 254 DO› DIST=BP^› BP==+2› L=BP^› BP==+1› IF DIST=EOL THEN› NT==RSH 1› RETURN(NT)› ELSEIF L>0 THEN› ;fix shapes by ORing distortion› DIST==LSH 4› FOR I=1 TO L DO› BP^==%DIST› BP==+1› OD› FI›OD›RETURN(0) ;error return›;›; INIT_TIMBRE ------------------------›PROC INIT_TIMBRE(BYTE N,V,› CARD ARRAY ADDR)›;N=timbre # (0,1 ...)›;V=voice (0 or 1)›;ADDR=addresses of 4 shape strings›;›BYTE I,J,› L,› CHAN›BYTE POINTER BP,› AUDF›BP=TIMBRES›IF N#0 THEN› ;skip over 2*N timbre arrays› J=N+N› FOR I=1 TO J DO› BP==+2› L=BP^› BP==+L+1› OD›FI›;›FOR I=0 TO 1 DO› CHAN=V+V+I ;Atari voice # (0-3)› BP==+1› AUDF=CHAN+CHAN ;set AUDF› AUDF==+$D200› AUDF^=BP^› BP==+1› ADDR(CHAN)=BP ;timbre string address› L=BP^ ;timbre string length› BP==+L+1›OD›RETURN›;›; MODULATE ---------------------------›PROC MODULATE(CARD ARRAY ADDR,› BYTE ARRAY OFFSET)›;ADDR=addresses of 4 shape strings›;OFFSET=clock offset for voices 0 & 1›BYTE V,› IDX,› LSB,› I,J,› L,› CHAN›BYTE POINTER BP›BYTE ARRAY AUDC(1)=$D201›CHAN=0 ;0-3›FOR V=0 TO 1 DO› ;loop over the two voices› LSB=CLOCK ;compute the shape index› IDX=LSB-OFFSET(V)› IF IDX>127 THEN› IDX=127› OFFSET(V)=LSB+127› FI› FOR I=0 TO 1 DO› ;loop over two channels per voice› BP=ADDR(CHAN);timbre string addr› L=BP^ ;timbre string length› IF L>0 THEN› IF IDX273 THEN› N=273 ;overflow will occur›FI›DELTA=N*240›IF DELTA>32767 THEN› DELTA==RSH 1› R==RSH 1›FI›DELTA==/R›RETURN(DELTA+CLOCK)›;›; CONTINUE ---------------------------›BYTE FUNC CONTINUE(CARD ARRAY P,› INT SPEED,› BYTE N_TIMBRES)›;P=address of preset›;SPEED=operator modification to tempo›;N_TIMBRES=number of timbres defined›;RETURN:›; 0 - normal›; 1 - error›;›BYTE INIT=[1],› COM,› VOICE,› I,› STATUS›CARD R,› N,› NEXT›INT METRO›BYTE ARRAY AUD(1)=$D200,› OFFSET(2),› NULL(1)=[QUIET]›CARD ARRAY S_ADDR(4)›CARD POINTER OLD_P=[$FFFF]›;›IF INIT#0 THEN› ;initialize› INIT=0› STATUS=0› OLD_P=P› VOICE=0› ZERO(AUD,9)› FOR N=0 TO 3 DO› S_ADDR(N)=NULL› OD› CLOCK=0 › NEXT=CLOCK›FI›;›IF NEXT<=CLOCK THEN› ;process a command from P array› COM=OLD_P^› OLD_P==+2› IF COM=END THEN› ;end of preset› INIT=1› ELSEIF COM=T THEN› ;timbre› VOICE==!1 ;flip between 0 and 1› I=OLD_P^› OLD_P==+2› IF I32767 THEN ;negative› R=2› FI› N=OLD_P^› OLD_P==+2› NEXT=QUANTUM(R,N)› ELSEIF COM=M THEN› ;metronome› METRO=OLD_P^› OLD_P==+2› ELSE› STATUS=1 ;error› FI›FI›IF STATUS=0 THEN› ;continue playing› MODULATE(S_ADDR,OFFSET)›ELSE› ;error detected› INIT=1›FI›RETURN(STATUS)›;›; TECHPOP ----------------------------›PROC TECHPOP()›BYTE CLICK=731, ;XL keyclick switch› RATE=730, ;XL cursor rep rate› CRSINH=$02F0,;cursor inhibit› SKCTL=$D20F, ;serial port cntrl› SSKCTL=$0232,; ... shadow› KCHAN=[7], ;kbd channel #› N,› N_TIMBRES›CARD OLD_ERROR,› P=[$FFFF]›INT SPEED=[0]›;›GRAPHICS(0)›OLD_ERROR=ERROR›ERROR=TRAP›CLICK=$FF ;disable XL keyclick›SKCTL=3›SSKCTL=3›DEVICE=0›CLOSE(KCHAN)›OPEN(KCHAN,"K:",12,0)›BUILD_DLI()›CRSINH=$FF›PRINTF("%E TechPop ")›PRINTF("Synthesizer wp%E")›RATE=3 ;fast key auto-repeat›;›N_TIMBRES=PREP_TIMBRE();setup timbres›IF N_TIMBRES=0 THEN› ALERT("invalid timbre format")›FI›;›DO›; N=KBD(KCHAN,SCHAN)› N=KBD(KCHAN,0)› IF N=$FF THEN› ;no input› ELSEIF N=$FE THEN› ;BREAK key› EXIT› ELSEIF N=$FD THEN› ALERT("?")› ELSEIF N=$FC THEN› ;speed up› SPEED==+1› ELSEIF N=$FB THEN› ;slow down› SPEED==-1› ELSEIF N=$FF THEN› ;no entry› ELSE› ;startup a new preset› P=FIND_PRESET(N)› SPEED=0› IF P=$FFFF THEN› ALERT("invalid preset")› FI› FI› IF P#$FFFF THEN› ;continue playing the preset› N=CONTINUE(P,SPEED,N_TIMBRES)› IF N#0 THEN› ALERT("invalid preset")› P=$FFFF› FI› FI›OD›BRKKEY=$FF›;›ERROR=OLD_ERROR›CLICK=0 ;reenable XL keyclick›UNBUILD_DLI()›SNDRST()›RETURN››