;*********************************
;*                               *
;*              MUS1             *
;*                               *
;*        BY JOHN SIMONTON       *
;*(C) 1978 - PAIA ELECTRONICS,INC*
;*     ALL RIGHTS RESERVED       *
;*                               *
;*                               *
;*    SYNTHESIZER SUBROUTINES    *
;*          ++ AND ++            *
;*   MULTIPLE OPTION POLYPHONIC  *
;*    ALLOCATION PROGRAM WITH    *
;*      SOFTWARE TRANSIENT       *
;*          GENERATION           *
;*                               *
;*********************************
;           OPTN
;POLYPHONIC SYNTHESIZER / OPTION
;        SELECTION
;*********************************
;
;
;INIT 	=$0D21
;POLY	=$0D71
;TRGN	=$0DC3
;NOTE	=$0D2B
DECD	=$0F00
;FILL	=$0D52
DISP	=$0820
CLCK	=$00BF
;
;OPTION TIES MUS1 FIRMWARE
;TOGETHER INTO A POLYPHONIC SYNTH
;WITH OR WITHOUT TRANSIENT GENER-
;TION, W/WO DYNAMIC QUASH DRIVERS
;
;ALSO USES PIEBUG DECODE AND
;ASSIGNS KEY #0 AS SYSTEM CLEAR
;AND #1 AS TUNE - EQUIVALENT TO
;ALL CHANNELS 2ND "C" on KBD DOWN
;

	org	$0D00
OPTN:
	jsr	INIT	;ZERO ALL BUFFS
LOOP:
	jsr	POLY	;ALLOCATE CHANS
	jsr	TRGN	;NEW TRANSIENTS
	jsr	NOTE	;OUTPUT-READ AGO
	lda	CLCK	;GET CLOCK VALUE
	sta	DISP	;RAZZ-MA-TAZZ
	jsr	DECD	;CHECK COMMANDS
	cmp	#$01	;0? 1? >1?
	bmi	OPTN	;0 CLEAR ALL
	bne	LOOP	;>1 KEEP ON
	ldy	#$5C	;1 TUNE 2ND C
	jsr	FILL	;KEYS ALL DOWN
	beq	LOOP	;BRANCH ALWAYS
;
;         INIT
;  INITIALIZATION ROUTINE
;******************************
;
CTRL	=$00E8
TBEG	=$00BF
;INIT CLEARS INPUT BUFFER (KTBL)
;OUTPUT BUFFER (NTBL) AND TRANS-
;POSE BUFFER/CONTROL WORDS (TTBL)
;HEXADECIMAN MODE IS SELECTED
;
;ENTER AT INT0 TO FILL TABLES
;WITH CHARACTER FROM ACCUMULATOR
;
INIT:
	lda	#$00	;PREPARE TO ZERO
INT0:
	ldx	#$28	;SET POINT/COUNT
	cld			;SET HEX MODE
INT1:
	sta	TBEG,x	;ZERO BUFFER
	dex			;POINT TO NEXT
	bne	INT1	;SOME LEFT -LOOP
;
;       NOTEOUT/LOOK
;16 CHANNEL QUASH DRIVERS AND AGO
;   KEYBOARD READING ROUTINE
;
;********************************
;
;CTRL	=$00E8
ODLY	=$00E9
KTBL	=$00DF
NTBL	=$00CF
TTBL	=$00BF	;ALSO CLCK
LAST	=$00A9
SH		=$09EF
DA		=$0900
KBD		=$0810

;       *** NOTEOUT ***
;    DYNAMIC QUASH DRIVER
;GETS NOTES TO BE PLAYED FROM THE
;OUTPUT BUFFER (NTBL) AND ADDS
;TRANSPOSING VALUE FROM TRANSPOSE
;BUFFER (TTBL) OUTPUTS RESULT
;
NOTE:
	ldx	#$10	;SET POINTER
NO0:
	lda	NTBL,x	;GET NOTE
	clc			;PREPARE AND
	adc	TTBL,x	;ADD TRANSPOSE
	sta	DA		;LET D/A SETTLE
	sta	SH,x	;WRITE TO S/H
;
;NOW THE DYNAMIC PART, IF GLIDE
;IS ON, DELAY IS SKIPPED. IF NOTE
;IS SAME AS LAST PLAYED (IGNORING
;CONTROL BITS D6 D7) DELAY IS
;SKIPPED.  IF NOT IN DYNAMIC MODE
;AND NO GLIDE, DELAY ALWAYS TAKEN
;
	bmi	NO2		;GLIDE? NO DELAY
	ora	#$80	;IGNORE FLAGS
	bit	CTRL	;DYNAMIC MODE ?
	bvc	DLAY	;NO, JMP TO DELAY
	cmp	LAST,x	;COMPARE TO LAST
	beq	NO2		;SAME:SKIP DELAY
DLAY:
	ldy	ODLY	;GET DELAY VALUE
NO1:
	dey			;DECREMENT DELAY
	bne	NO1		;LOOP TIL DONE
NO2:
	sta	LAST,x	;FOR NEXT TIME
	dex			;POINT TO NEXT
	bne	NO0		;SOME LEFT -LOOP
;
;LOOK WAITS FOR THE BEGINNING OF
;AN "ACTIVE" SCAN-BEGINS PUTTING
;THE NUMBERS OF KEYS DOWN IN SE-
;QUENTIAL IN-BUFF WORDS.  WHEN
;SCAN DONE REMAINING IN-BUFF IS
;ZERO'D
;
LOOK:
	inc	TTBL	;INCREMENT CLOCK
	ldy	#$00	;PREPARE FOR CLR
FILL:
	ldx	#$08	;SET UP POINTER
LK2:
	lda	KBD		;WAIT FOR
	bmi	LK2		;"ACTIVE" SCAN
LK3:
	lda	KBD		;GET KEY
	bmi	DONE	;END SCAN? -CLR
	rol	a		;STROBE TO D7
	bpl	LK3		;D7=0, NO STROBE
	ror	a		;RESTORE DATA
	sta	KTBL,x	;TO IN BUFFER
LK4:
	cmp	KBD		;NOW WAIT FOR
	beq	LK4		;NEXT KEY
LK0:
	dex			;PNT TO NEXT BUF
	bne	LK3		;SOME LEFT -LOOP
	rts			;LEAVE
	;
DONE:
	sty	KTBL,x	;ZERO IN-BUFFER
	bmi	LK0		;BRANCH ALWAYS
;
;          POLY
; A LIMITED RESOURCE ALLOCATION
;        ALGORYTHM
;********************************
;
OUTT	=$00EB
OUTS	=$00EA
;CTRL	=$00E8
;KTBL	=$00DF
;NTBL	=$00CF
;
;POLY-FIRST HALF OF ALGORHYTHM
;IN THIS BLOCK DE-ACTIVATED CHANS
;ARE REACTIVATED IF THE DATA THEY
;CONTAIN APPEARS IN THE IN BUFFER
;
;D7 IN CTRL SET - ALTERNATE MODE
;D7 "   "   CLR - SEQUENTIAL MODE
;
POLY:
	lda	OUTS	;# OD OUT CHANS
	sta	OUTT	;USE AS COUNTER
	ldx	#$10	;PREPARE PNT/CNT
POL0:
	lda	NTBL,x	;GET NOTE
	beq	NWKY	;0-OLD KEYS DONE
	and	#$7F	;CLEAR D7
	ora	#$40	;SET D6
	ldy	#$09	;PREPARE PNT/CNT
LP0:
	dey			;POINT NEXT KEY
	beq	NEXT1	;DONE -NEXT NOTE
	cmp	KTBL,y	;SAME AS KEY?
	bne	LP0		;NO -NEXT KEY
	sta	NTBL,x	;SAVE NOTE D6=1
	dec	OUTT	;ONE LESS OUTPUT
	beq	OUT		;NONE LEFT-LEAVE
	lda	#$00	;OR PREPARE AND
 	sta	KTBL,y	;ELIMINATE KEY
	beq	LP1		;& BRANCH ALWAYS
NEXT1:
	and	#$BF	;CLEAR TRIG (DG6)
	sta	NTBL,x	;& RESTORE NOTE
LP1:
	bit	CTRL	;ALTERNATE MODE?
	bpl	SKP1	;NO -DEC ONCE
	dex			;YES-DEC TWICE
SKP1:
	dex			;POINT NEXT NOTE
	bne	POL0	;SOME LEFT -LOOP
;
;NEWKEY - SECOND HALF. KEYS DOWN
;ARE ASSIGNED TO OUTPUT BUFFER
;LOCATIONS WICH ARE STILL DE-
;ACTIVATED
;
NWKY:
	ldx	#$10	;NTABLE PNT/CNT
	ldy	#$09	;KTABLE PNT/CNT
NK1:
	lda	#$40	;PREPARE MASK
	and	NTBL,x	;NOTE TRIGGERED?
	bne	NK3		;YES -GO TO NEXT
NK2:
	dey			;POINT NEXT KEY
	beq	OUT		;NONE LEFT-LEAVE
 	lda	KTBL,y	;KEY NEEDS HOME?
	beq	NK2		;NO -GET NEXT
	sta	NTBL,x	;YES-PUT IN NOTE
	dec	OUTT	;ONE LESS OUTPUT
	beq	OUT		;NONE LEFT-LEAVE
NK3:
	bit	CTRL	;ALTERNATE MODE?
	bpl	SKP2	;NO -DEC ONCE
	dex			;YES-DEC TWICE
SKP2:
	dex			;POINT NEXT NOTE
	bne	NK1		;SOME LEFT -LOOP
OUT:
	rts			;RETURN

;       TRGN
;TRANSIENT GENERATOR PROGRAM

;********************************
;
;
;CTRL	=$00E8
ATCK	=$00BA
DCY		=$00BB
SUST	=$00BC
RLS		=$00BD
PEAK	=$00BE
;NTBL	=$00CF
PARM	=$00CE
;TTBL	=$00BF
CWRD	=$00BE
;
;       NTBL 00D0-00DF
;       TTBL 00C0-00CF
;			
TRGN:
	lda	CTRL	;DO TRANSIENTS?
	bpl	RTN1	;NO  -RETURN
	ldx	#$10	;NTABLE PNT/CNT
;   A/D/S/R DETERMINATION
;ROUTINE PREPARES Y TO USE AS
;CONTROL WORD. GETS NOTE AND
;SHIFTS TRIG.  TO CARRY.  GETS
;CURRENT STATE (CS) PARAMETER.
;IF NOTE TRIG.  NOT SET STATE IS
;RELEASE.  IF CS PARA IS POSI-
;TIVE STATE IS DECAY. SUSTAIN
;OTHERWISE, STATE IS ATTACK
ADSR:
	ldy	#$40	;PREPARE CWRD
	lda	NTBL,x	;GET NOTE AND
	rol	a		;ROTATE TRIGGER
	rol	a		;TO CARRY BIT
	lda	PARM,x	;NO TRIG? -RLS
	bcc	RELS	;CS>0? -DECAY/S
	bpl	DS
;   ATTACK ROUTINE
;ADDS ATTACK PARAMETER TO CS PARA
;AND IF GREATER THAN PEAK
;SUBSTITUTES $#F AND SETS CONTROL
;WORD TO $40 (D6 SET - NO GLIDE).
;NOTE THAT CS PARA WILL BE >0
;WHEN NEXT CHECKED.
;
ATTK:
	clc			;PREPARE
	adc	ATCK	;ADD ATTACK PARA
	cmp	#$BF	; >PEAK
	bcc	NEXT2	;NO -PLACE PARA.
	lda	PEAK	;YES-PEAK VALUE
	bne	NEXT2	;BRANCH ALWAYS
;
;   DECAY AND SUSTAIN ROUTINE
;NOTE THAT CARRY IS SET.  DECAY
;PARAMETER IS SUBTRACTED FROM
;CURRENT STAT PARAMETER.  IF
;RESULT IS LASS THAN SUSAIN
;PARAMERE THEN SUST.  PARA.
;BECOMES CURRENT STATE PARA.
;D6 & D7 OF CONTROL WORD SET
;
DS:
	ldy	#$C0	;PREPARE CWRD
	sbc	DCY		;SUBTRACT DCY
	cmp	SUST	;>SUSATIN?
	bpl	NEXT2	;PLACE PARA
	lda	SUST	;CS PARA=SUST
	bpl	NEXT2	;PLACE PARA
;
;   RELEASE ROUTINE
;MAKE SURE THAT CURRENT STATE
;GLIDE BIT IS SET (NOTE-MAKES
;CS NEGATIVE). SUBTRACTS RELEASE
;PARA. FROM CURRENT STATE.  IF
;RESULT >0. MAKES CS & CWRD =80
RELS:
	sec			;PREPARE
	ora	#$80	;SET CS GLIDE
	sbc	RLS		;SUBTRACT RLS
	bmi	NEXT2	;CS<0 -PLACE CS
	ldy	#$00	;CS>0 -DONE MAKE
	lda	#$80	;CS=80; CWRD=0
;
;   NEXT
;PLAVES CS PARA AND CWRD IN
;PROPER CONTROL CHANNEL OUTPUTS
;DECREMENTS POINTER (TWICE) AND
;IF NOT YET DONE LOOPS FOR MORE
;
NEXT2:
	sty	CWRD,x	;PLACE CONTROL
	sta	PARM,x	;PLACE CS PARA
	dex			;DECREMENT POINT
	dex			;AND AGAIN
	bne	ADSR	;SOME LEFT -LOOP
RTN1:
	rts			;RETURN
