home *** CD-ROM | disk | FTP | other *** search
- ;-----------------------------------------------------------------------------
- ;GAME GEAR MUSIC DRIVER - (c) Martin Walker 1993/1994
- ;-----------------------------------------------------------------------------
-
- ;example to produce a final customer driver file
- ;DEMO equ 0 ;0=driver only/ 1=demo & driver
- ;MUSICROM equ 08000h ;Music Driver start address
- ;MUSICRAM equ 0C500h ;Ram variables start address
-
- ;default settings to use with the music editor
- DEMO equ 1 ;0=driver only/ 1=demo & driver
- MUSICROM equ 01000h ;Driver start address
- MUSICRAM equ 0C000h ;Ram variables start address
-
-
- MASTER equ 0 ;0=GAMEGEAR/ 1=MASTER SYSTEM
-
-
- ;CURRENT STATISTICS
- ;CODESIZE (ROM) = 3368 bytes (approx 3 Kbytes)
- ;VARSIZE (RAM) = 214 bytes
- ;Typical compressed music file 2-10 Kbytes
-
- GAMEGEAR equ 1-MASTER ;GAME GEAR
- HOLDTIME equ 200 ;number of frames to hold effect
-
-
- ;VERSION DETAILS
- ;3.0 - Tiny format adopted/drumbend special added/ Get_info added
- ; drumbend added
- ;1.7 - SFX specials moved/fixed special added/music channel 0 first
- ;1.6 - SFX routine implemented
- ;1.5 - noise allocation/superbug
- ;1.4 - simplified loop code/envlevel to byte/PAL or NTSC options
- ;1.3 - updated envelope routines/voicenum default to 0/rest & fade added
- ;1.2 - new format notes/extended parameters/32 byte effects & voices
- ;1.1 - CLOCK/updated TEMPO routine
- ;1.0 - First working prototype
-
-
-
-
- ;REGISTER EQUATES
-
- VCOUNT EQU 7Eh
- PSG EQU 7Fh ;both models
- VDPD EQU 0BEh
- VDPA EQU 0BFh
- VCHR EQU 0000h
- VSCHR EQU 2000h
- VMAP EQU 3800h
- VSMAP EQU 3F00h
- JOY1 EQU 0DCh
- JOY2 EQU 0DDh
- RKV EQU 08h
- LKV EQU 04h
- UKV EQU 01h
- DKV EQU 02h
- FAKV EQU 10h
- FBKV EQU 20h
- BNKAD equ 0FFFFh ;Rom bank select register
-
-
- COMAD EQU 7FF8h ;The address of the comms interface in the GAMEGEAR
- HDLEN EQU 16 ;Header buffer length (don't change)
- RESTRT EQU 0 ;Main program start address
-
- ;-----------------------------------------------------------------------------
- IF DEMO
- ORG 0000H ;Start of program
- JP START
-
- ORG 0030h ;RST 30h is used for breakpoint
-
- PUSH BC
- PUSH AF
- LD BC,4170h
- JP ASM10
-
- JP VBLINT ;38h VERTICAL BLANK
-
- ;-----------------------------------------------------------------------------
- STBNK: ;This routine selects the rom bank in the A reg
- PUSH BC ;and returns the previous bank in the A reg
- LD B,A
- LD A,(BANKVAL) ;Get current bank from ram
- LD C,A
- LD A,B
- AND 1Fh
- LD (BANKVAL),A ;Save new bank
- LD (BNKAD),A ;Set bank
- LD A,C
- POP BC
- RET ;A is previous bank
-
- ;-----------------------------------------------------------------------------
- ORG 0066h
- NMI: RETN ;NMI #66
-
-
-
-
-
- VIDREG: DB 06,0A0h,0FFh,0FFh,0FFh,0FFh,0FFh,0Fh+(MASTER*0F0h),00,00,01 ;VIDEO REGS INIT
- PALTAB: DB 0,0,4,8,16,1,6,11 ;PALLETE
- DB 15,16,36,57,43,55,42,63
- DB 2Ah,15h,00h,3Fh,00h,00h,00h,00h
- DB 00h,00h,00h,00h,00h,00h,00h,00h
-
- CHRS: DB 0F0h,0F0h,0F0h,0F0h ;PATTERN
- DB 0F0h,0F0h,0F0h,0F0h
- DB 0F0h,0F0h,0F0h,0F0h
- DB 0F0h,0F0h,0F0h,0F0h
- DB 0FFh,0FFh,0FFh,0FFh
- DB 0FFh,0FFh,0FFh,0FFh
- DB 000h,000h,000h,000h
- DB 000h,000h,000h,000h
-
- ;-----------------------------------------------------------------------------
- START:
- DI
-
- ; IF GAMEGEAR
- PR20: IN A,(VCOUNT) ;Wait for end of reset sequence
- CP 0B0h
- JR NZ,PR20
- ; ENDIF
-
- IM 1
- XOR A ;Reset unused ROM bank registers
- LD (0FFFCh),A ;bank register 0
- LD (0FFFDh),A ;bank register 0 (unused, always set to 0)
- INC A
- LD (0FFFEh),A ;bank register 1
- LD SP,0DFEFh
- LD HL,0C000h ;fill C000-DFF0 with zero
- PR40: LD (HL),0
- INC HL
- LD A,L
- SUB 0F0h
- LD A,H
- SBC A,0DFh
- JR C,PR40
-
- LD A,2 ;Set default ROM bank
- CALL STBNK ;(Banks switched in at 8000h)
-
- XOR A
- LD DE,0
- LD BC,4000h
- CALL FILVID ;Reset video ram
- LD A,0E0h
- LD DE,VSMAP
- LD BC,0040h
- CALL FILVID ;Turn off sprites
- CALL INVREG ;Init video regs
- LD HL,PALTAB
- CALL SETPALETTE ;Set palette
- LD HL,CHRS
- LD DE,VCHR
- LD BC,32
- CALL STVID ;Draw pattern in first char
- LD A,(VIDREG+1) ;Display on
- SET 6,A
-
- DI
- OUT (VDPA),A
- LD A,81h
- OUT (VDPA),A
-
- CALL JUMPTABLE+0 ;Initialise driver
- LD A,0FFH
- LD (sfxno),A
- LD (tuneno),A
- LD (PCnewdata),A
- XOR A
- LD (editnum),A
- EI
-
-
- ;-----------------------------------------------------------------------------
- MAIN: CALL COMMS
-
- NEWchk: ld a,(PCnewdata)
- cp 0ffh
- jr z,JOYchk
- call JUMPTABLE+6 ;re-initialise after compression
- LD A,0FFH
- LD (PCnewdata),A ;cancel flag
-
-
- JOYchk: IN A,(JOY1)
- BIT 0,A
- JR Z,UPKEY
- BIT 1,A
- JR Z,DNKEY
- BIT 2,A
- JR Z,STOPKEY
- BIT 3,A
- JR Z,STOPKEY
- BIT 4,A
- JR Z,ONEKEY
- BIT 5,A
- JR Z,TWOKEY
- JR VBLK_WT
-
- UPKEY: LD A,(editnum) ;inc call number
- INC A
- LD (editnum),A
- JR KEYEND
- DNKEY: LD A,(editnum) ;dec call number
- DEC A
- LD (editnum),A
- JR KEYEND
- ONEKEY: ld a,(editnum)
- LD (tuneno),A
- JR KEYEND
- TWOKEY: LD A,(editnum)
- LD (sfxno),A
- JR keyend
- STOPKEY:
- call INVEC ;re-initialise after compression
- ld a,07Dh
- ld (TEMPOVAL),a ;default tempo = 7Dh = 125bpm
- ld a,080h
- ld (tuneno),A ;kill music
- xor a
- ld (sfxno),A ;effect 0
-
-
- KEYEND: IN A,(JOY1)
- CP 0FFh
- JR NZ,KEYEND ;wait for key release
-
- VBLK_WT:
- LD A,(vbi_flag)
- AND A ;VBLANK interrupt ?
- JR Z,VBLK_WT
- XOR A
- LD (vbi_flag),A ;clear flag (set at end of VBLANK)
- JP MAIN
-
-
- ;-----------------------------------------------------------------------------
- VBLINT: ;VERTICAL BLANK INTERRUPT
- PUSH AF
- PUSH BC
- PUSH DE
- PUSH HL
-
- IN A,(VDPA)
- RLA ;move interrupt bit to carry
- JR NC,VB90 ;Not vertical blank
- LD A,(SCRLCOUNT) ;Scroll screen
- DEC A
- LD (SCRLCOUNT),A
- NEG
- OUT (VDPA),A
- LD A,88h
- OUT (VDPA),A
-
- CALL JUMPTABLE+3 ;60Hz SOUND INTERRUPT ROUTINE
- CALL Get_Info
- LD A,1
- LD (vbi_flag),A ;VBLANK INTERRUPT END FLAG
-
- VB90: POP HL
- POP DE
- POP BC
- POP AF
- EI
- RET
-
-
- ;-----------------------------------------------------------------------------
- INVREG: ;SET UP VIDEO REGS
- IN A,(VDPA)
- LD HL,VIDREG
- LD B,11
- LD C,80h
- ST5: LD A,(HL)
- INC HL
- OUT (VDPA),A
- LD A,C
- INC C
- OUT (VDPA),A
- DJNZ ST5
- ; LD A,(VIDREG+1) ;Used for display on/off
- ; LD (BLFLG),A
- RET
-
- ;-----------------------------------------------------------------------------
- SETPALETTE: ;SET PALETTE
- IF GAMEGEAR
- LD IX,PALLETTE ;GAMEGEAR DIFFERENT FORMAT
- LD B,32
- SP10: LD A,(HL)
- RLCA
- RLCA
- EXX
- LD HL,0
- LD D,H
- LD B,3
- LD C,A
- SP20: ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- RLC C
- RLC C
- LD A,C
- AND 03h
- LD E,A
- ADD A,A
- ADD A,A
- ADD A,E
- LD E,A
- ADD HL,DE
- DJNZ SP20
- LD (IX+0),L
- LD (IX+1),H
- INC IX
- INC IX
- EXX
- INC HL
- DJNZ SP10
- LD HL,PALLETTE
- ENDIF
- LD BC,32*(GAMEGEAR+1)
- XOR A
- DI
- OUT (VDPA),A
- LD A,0C0h
- JR ST8
-
- ;-----------------------------------------------------------------------------
- STVID: ;WRITE TO VIDEO RAM
- LD A,E
- DI
- OUT (VDPA),A
- LD A,D
- AND 03Fh
- OR 040h
- ST8: JR ST9
- ST9: OUT (VDPA),A
- JR ST10
- ST10: LD A,(HL)
- INC HL
- DEC BC
- OUT (VDPD),A
- LD A,B
- OR C
- JR NZ,ST10
- EI
- RET
-
- ;-----------------------------------------------------------------------------
- FILVID: ;FILL VIDEO RAM
- PUSH AF
- LD A,E
- DI
- OUT (VDPA),A
- LD A,D
- AND 03Fh
- OR 040h
- JR ST15
- ST15: OUT (VDPA),A
- POP AF
- NOP
- DEC BC
- ST20: DEC BC
- NOP
- OUT (VDPD),A
- BIT 7,B
- JR Z,ST20
- EI
- RET
-
-
- ;-----------------------------------------------------------------------------
- ;Start of Debugger routines
- ;-----------------------------------------------------------------------------
- COMMS: ;Enter debugger if host waiting to transfer
- ; DI ;Interrupts should be off
- PUSH BC
- PUSH AF
- LD BC,0C0F0h
- ASM10: LD A,(COMAD) ;'Read' port of comms link
- XOR B ;Bits 4-6 are used to determine if the comms is
- AND C ;enabled. Bit 7 set indicates that the host is
- JR NZ,ASM20 ;waiting to transfer
- CALL COMRT ;Enter debugger if host waiting
- ASM20: POP AF
- POP BC
- RET ;Return to main program (interrupts off)
- ;All regs preserved unless changed by host
- ;command
-
-
- ;-----------------------------------------------------------------------------
- ;This is the debugger.
- ;If a new bank was paged in, the previous value should be in the A
- ;reg. This can be read by the 'transfer registers' command.
- ;The B reg holds the breakpoint type (041h-BRKPNT, 042h-TRACE AND 0C0h-COMMS).
- ;-----------------------------------------------------------------------------
- COMRT: PUSH DE
- PUSH HL
- LD HL,12
- ADD HL,SP
- PUSH HL ;Stack value
- LD C,A
- PUSH BC ;Bank and type
- LD HL,-HDLEN AND 0FFFFH
- ADD HL,SP
- LD SP,HL ;Buffer for header
- COM20: LD A,(COMAD)
- AND 0F0h
- CP 040h
- JR Z,COM20 ;Wait for host (for DEBUG entry)
- LD A,(COMAD+6) ;Reset port
- LD A,(COMAD+4)
- COM30: LD A,(COMAD+3)
- COM40: CALL COMRX ;Read first byte of header
- JR C,COM70 ;Enter ram or exit
- AND A
- JR Z,COM80 ;This command not used
- LD HL,0
- ADD HL,SP
- CALL COMCMD ;Execute command
- JR NC,COM30 ;If no error loop back for next command
- LD A,(COMAD+2) ;Signal error to host
- LD A,(COMAD+4)
- LD A,(COMAD+7)
- COM60: LD A,(COMAD) ;Wait for host to disable comms with COMOFF
- AND 0F0h
- CP 0C0h
- JR Z,COM60
- JR COM90 ;Exit
- COM70: JR NZ,COM80 ;Jump if exit
- LD A,(COMAD+6)
- DI ;Prepare to enter ram (for ESYS access)
- LD HL,(HDLEN-CWTLN) AND 0FFFFH
- ADD HL,SP
- LD SP,HL ;Make space for ram routine
- PUSH HL
- LD D,H
- LD E,L
- LD HL,COMWT ;Copy routine into stack buffer
- LD BC,CWTLN ;LD BC,/LDIR (for Z80)
- COM75: LDIR
- RET ;Enter ram
-
- ;-----------------------------------------------------------------------------
- COMCT: LD A,(COMAD+2) ;Continue here after exiting ram
- LD HL,CWTLN-HDLEN
- ADD HL,SP
- LD SP,HL ;Reclaim space
- EI
- COM78: LD A,(COMAD) ;Wait for acknowledgement from host
- AND 0F2h
- CP 0C0h
- JR Z,COM78
- JR COM30
- COM80: LD A,(COMAD+6) ;Prepare for exit
- LD A,(COMAD+2)
- COM90: LD HL,HDLEN ;Exit after error
- ADD HL,SP
- LD SP,HL ;Reclaim header buffer
- POP BC
- LD A,C
- POP HL
- POP HL
- POP DE
- RET
-
-
- ;-----------------------------------------------------------------------------
- ;Execute command, A is command number
- ;-----------------------------------------------------------------------------
- COMCMD:
- CP 10h ;This command not used
- JR NZ,CMD10
- LD DE,HDLEN+1
- ADD HL,DE
- LD A,(HL)
- CALL COMTX
- RET C
-
- TXACK: LD A,(COMAD) ;Wait for acknowledgement from host
- AND 0F2h
- CP 0C0h
- JR Z,TXACK
- LD A,(COMAD+2)
- CMD5: LD A,(COMAD)
- AND 0F1h
- XOR 0C0h
- JR Z,CMD5
- RET
-
- CMD10: LD E,A
- AND 0Fh
- RET Z ;Single byte command
- LD C,A
- LD B,0
- PUSH DE
- PUSH HL
- CALL CRXLP ;Load rest of header
- POP HL
- POP DE
- RET C ;Error
- LD A,E
- AND 0EFh
- CP 02h
- JR NZ,CMD20 ;Jump if not transfer regs command
- LD C,(HL)
- INC HL
- LD A,(HL)
- LD B,0
- ADD HL,BC
- LD C,HDLEN-1
- ADD HL,BC ;Point to regs list on stack
- LD C,A
- LD D,B
- JR CMD30
- CMD20: XOR 05h
- RET NZ ;Return if not transfer memory command
- LD A,(HL)
- INC HL
- LD D,(HL)
- INC HL
- INC HL
- LD C,(HL)
- INC HL
- LD B,(HL)
- LD H,D
- LD L,A
- LD D,0
- ;CALL CKDOFF ;Turn GBOY display off if required
- CMD30: PUSH DE
- BIT 4,E
- JR Z,CMD40
- CALL CTXBUF ;Send data
- CALL NC,TXACK ;Wait for acknowledgement
- JR CMD50
- CMD40: CALL CRXBUF ;Load data
- CMD50: POP DE
- ret
-
-
-
- ;-----------------------------------------------------------------------------
- ;This routine is copied into ram to allow the host access
- ;to the ESYS
- ;-----------------------------------------------------------------------------
- COMWT:
- LD A,(COMAD+2)
- CWT10: XOR A ;Wait for command
- CWT20: ADD HL,HL
- DEC A
- JR NZ,CWT20
- LD A,(COMAD)
- AND 0F0h
- CP 0C0h
- JR Z,CWT30 ;Jump if host waiting to send command
- CP 040h
- JR Z,CWT10
- JR CWT50 ;Jump if comms disabled
- CWT30: LD A,(COMAD+3) ;Send acknowledgement
- CWT40: LD A,(COMAD)
- AND 0F2h
- CP 0C0h
- JP Z,COMCT ;Jump back to debugger
- CP 0C2h
- JR Z,CWT40
- LD A,(COMAD+2)
- CWT50: JP RESTRT ;Jump to start if comms disabled or ENDTRN called
- CWTLN EQU $-COMWT
-
-
- ;-----------------------------------------------------------------------------
- ;Transmit data to host
- ;HL points to data, BC is the length
- ;-----------------------------------------------------------------------------
- CTXBUF:
- LD E,0
- CTX10: LD A,(HL)
- LD D,A
- INC HL
- CALL COMTX ;Send byte
- RET C ;Error
- LD A,D ;Checksum
- ADD A,E
- LD E,A
- DEC BC
- LD A,B
- OR C
- JR NZ,CTX10
- LD A,E ;Send checksum
- ;Send a byte (in A)
- COMTX: PUSH BC
- PUSH DE
- PUSH HL
- LD C,A
- LD B,0C2h
- LD DE,COMAD+2
- LD HL,COMAD+4
- SCF
- RL C
- CTX20: RR E
- RLC E
- CTX30: LD A,(COMAD) ;Wait for handshake
- XOR B
- AND 0F2h
- JR Z,CTX40
- XOR 02h
- JR Z,CTX30
- AND 070h
- SCF
- JR NZ,CTX50 ;Exit if comms disabled
- BIT 3,B
- JR NZ,CTX30
- CTX40: SET 3,B ;Send first bit even if host is not ready
- LD A,(DE)
- LD A,L
- XOR 01h
- LD L,A
- LD A,B
- XOR 02h
- LD B,A
- LD A,(HL)
- SLA C
- JR NZ,CTX20
- AND A
- CTX50: POP HL
- POP DE
- POP BC
- RET
- ;On exit NC=send OK, C=comms disabled
-
-
- ;-----------------------------------------------------------------------------
- ;Receive data from host
- ;HL points to data, BC is the length
- ;-----------------------------------------------------------------------------
- CRXBUF:
- LD E,0
- CRXLP: CALL COMRX ;Load byte
- RET C ;Error
- LD (HL),A
- INC HL
- ADD A,E ;Checksum
- LD E,A
- DEC BC
- LD A,B
- OR C
- JR NZ,CRXLP
- CALL COMRX ;Load checksum
- RET C ;Error
- XOR E
- ADD A,0FFh ;Signal error if checksums do not match
- RET
- ;On exit NC=load OK, C=comms disabled or error
-
-
- ;-----------------------------------------------------------------------------
- ;Receive a byte from host
- ;-----------------------------------------------------------------------------
- COMRX:
- PUSH BC
- PUSH HL
- LD BC,0C001h
- LD HL,COMAD+6
- CRX10: LD A,(COMAD) ;Wait for handshake
- AND 0F2h
- XOR B
- JR Z,CRX20
- XOR 02h
- JR Z,CRX10
- XOR B
- XOR 042h
- JR NZ,CRX30 ;Jump if comms disabled
- LD A,C ;Check for 'enter ram' command
- XOR 3
- JR CRX30
- CRX20: LD A,L
- XOR 01h
- LD L,A
- LD A,B
- XOR 02h
- LD B,A
- LD A,(COMAD)
- CP (HL)
- RRA
- RL C
- JR NC,CRX10
- LD A,C
- CRX30: POP HL
- POP BC
- CCF
- RET
- ;On exit NC=load OK, value in A
- ; C and A=0 - Enter ram command
- ; C and A<>0 - Comms transfer ended
-
-
-
- ;-------------------------------------------------------------------------------
- ;Get_Info
- ;-------------------------------------------------------------------------------
- Get_Info:
- LD BC,PCbuffer
- LD A,(TUNENO)
- LD (BC),A
- INC BC
- LD A,(STATUS)
- LD (BC),A
- INC BC
- LD A,(TEMPOVAL)
- LD (BC),A
- INC BC
- LD A,(CLOCK_L)
- LD (BC),A
- INC BC
- LD A,(CLOCK_H)
- LD (BC),A
- INC BC
- LD A,(globoffset)
- LD (BC),A
- INC BC
-
- XOR A
- LD D,A
- LD E,A
- LD (chan_num),A
- LD IX,ENV_VARS
- LD IY,MUS_VARS
-
- Gilup1: LD A,(IY+24) ;notelength
- LD (BC),A
- INC BC
- ld A,(IY+75) ;threshold
- LD (BC),A
- INC BC
- LD A,(IY+39) ;voicenum
- LD (BC),A
- INC BC
- LD A,(IY+15) ;notevalue
- LD (BC),A
- INC BC
- LD A,(IY+12) ;seqnumber
- LD (BC),A
- INC BC
- LD A,(IX+9) ;envlevel
- LD (BC),A
- INC BC
-
- INC IY
- INC IX
- LD HL,chan_num
- INC (HL)
- LD A,(HL)
- CP 3
- JP C,Gilup1
- RET
-
-
-
-
- ENDIF
-
-
- ;*****************************************************************************
- ; ****** START OF DRIVER CODE ******
- ;*****************************************************************************
- ORG MUSICROM
-
- JUMPTABLE:
- JP INITSND ;Initialise sound routine
- JP INTSND ;Game Gear 60Hz Interrupt routine
- JP INVEC ;New load routine
-
- INITSND:
- LD HL,RAM_VARS ;clear variable RAM
- LD BC,VARSIZE
- CLRVAR: LD (HL),0
- INC HL
- DJNZ CLRVAR
-
- CALL INVEC ;calc. addresses from vector table
-
- LD A,0ffh
- LD (sfx_channel),A ;cancel any current calls
- LD (sfx_channel+SDLN),A
- LD (sfx_channel+SDLN+SDLN),A
- LD (sfx_priority),A ;set lowest priority
- LD (sfx_priority+SDLN),A
- LD (sfx_priority+SDLN+SDLN),A
- LD (vce_mute),A ;force music muted for effects
- LD (vce_mute+1),A
- LD (vce_mute+2),A
- LD (NCHAN),A ;noise channel free
-
- ld a,0FFh
- ld (TEMPOVAL),A ;default tempo = 296
- LD A,0Dh
- LD (musicvol),A
- LD A,0Fh
- LD (effectvol),A ;default to maximum volume
- CALL PSG_off ;silence all channels
- ret
-
-
- ;-----------------------------------------------------------------------------
- ;Calculate new pointers from Musicdata chunk sizes
- ;-----------------------------------------------------------------------------
- INVEC: LD HL,GAMEDATA ;chunk table start address
- LD DE,GAMEDATA+14 ;music data start address
- IN50: LD A,E
- LD (FXBANK),A
- LD A,D
- LD (FXBANK+1),A ;save start address of envelopes
-
- ld bc,FXTABLE
- call stvar ;calculate FXBANK address
- CALL STVAR ;calculate VCEBANK address
- CALL STVAR ;calc. SEQOFF address
- CALL STVAR ;calc. SEQDATA address
- CALL STVAR ;calc. TRKOFF address
- ;calc. TRKDATA address
- STVAR: LD A,(HL) ;get low byte from vector table
- INC HL
- ADD A,E ;add GAMEDATA low byte address
- LD E,A ;and save in E
- LD (BC),A ;and save in final offset low byte
- INC BC ;now move to high byte
- LD A,(HL) ;get high byte from vector table
- INC HL
- ADC A,D ;add GAMEDATA high byte address
- LD D,A ;DE now holds address of this block
- LD (BC),A ;save to final offset high byte
- INC BC ;now move to next dest. entry
-
- RET
-
- ;-------------------------------------------------------------------------------
- ;INTERRUPT ROUTINE
- ;-------------------------------------------------------------------------------
- INTSND: LD A,(sfxno)
- CP 0FFH
- JR Z,INTSND2
- CALL SENDFX
- LD A,0FFH
- LD (sfxno),A
- INTSND2:
- LD A,(tuneno)
- CP 0FFH
- JR Z,INTSND3
- CALL SENDMUS
- LD A,0FFH
- LD (tuneno),A
- INTSND3:
- CALL INTSFX
- CALL INTMUSIC
- ret
-
-
- ;-------------------------------------------------------------------------------
- SENDFX: ld hl,0
- ld l,a ;enter with A=FXTABLE call number
- add hl,hl
- add hl,hl ;4 bytes for each entry
- ld a,(FXTABLE)
- add a,l
- ld c,a
- ld a,(FXTABLE+1)
- adc a,h
- ld h,a ;final high byte of address
- ld l,c ;final low byte of address
-
- ld c,(hl) ;get priority
- inc hl
- ld a,(hl) ;get chan0 call
- inc hl
- cp 0ffh
- jr z,sendfx1
- ld (sfx_channel),a
- ld a,c
- ld (sfx_priortest),a
- sendfx1:
- ld a,(hl) ;get chan1 call
- inc hl
- cp 0ffh
- jr z,sendfx2
- ld (sfx_channel+SDLN),a
- ld a,c
- ld (sfx_priortest+SDLN),a
- sendfx2:
- ld a,(hl) ;get chan2 call
- inc hl
- cp 0ffh
- jr z,sendfx3
- ld (sfx_channel+SDLN+SDLN),a
- ld a,c
- ld (sfx_priortest+SDLN+SDLN),a
- sendfx3:
- ret
-
-
- ;-----------------------------------------------------------------------------
- INTSFX:
- LD A,2 ;3 channels
- LD (chan_num),A
-
- SFXLOOP:
- XOR A
- LD (freqoffset),A ;reset waver to 0
- LD IX,ENV_VARS
- LD IY,SFX_VARS
- LD BC,(chan_num)
- ADD IX,BC
- LD A,C
- AND A
- JR Z,SF5 ;channel 1
- LD C,SDLN
- ADD IY,BC
- DEC A
- JR Z,SF5 ;channel 2
- ADD IY,BC ;channel 3
-
- SF5: LD A,(IY+0) ;new sound effect needed? (sfx_channel)
- INC A
- JR Z,TESTMUSIC ;sfx_channel=0FFh is no effect required
- DEC A ;return to previous value
- LD B,A ;new effect number saved to B
- LD A,(IY+2)
- LD C,A ;C=sfx_priortest
-
- LD A,(IY+1) ;get current sfx_priority
- CP C
- JR NC,loadfx ;higher or equal, so accept
- LD A,(IY+3) ;sfx_hold
- AND A
- JR Z,loadfx ;past critical portion
- LD (IY+0),0FFH ;else cancel this try (sfx_channel)
-
- TESTMUSIC:
- LD HL,MUS_VARS
- LD BC,(chan_num)
- ADD HL,BC
- LD A,(HL) ;get vce_mute
- AND A ;0 = not muted i.e.
- JR Z,TESTABORT ;new note of music taken over
- LD A,(IY+4) ;else continue until SFX end (sfx_framechop)
- AND A
- JP NZ,timefx ;carry on with existing SFX
-
-
- TESTABORT:
- LD (IY+3),0 ;force sfx_hold = 0 if snd < hold length
- LD (IY+4),0 ;sfx_framechop (just in case)
- JP NEXT_SFX
-
- ;-----------------------------------------------------------------------------
- loadfx: LD A,C ;get new priority
- LD (IY+1),A ;& save new sfx_priority
- LD L,(IY+0) ;accept new sound (sfx_channel)
- LD H,0
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL ;32 bytes per effect
- LD DE,(FXBANK)
- ADD HL,DE
- LD (IY+7),L
- LD (IY+8),H ;save new sfx_address (word)
-
- PUSH HL
- EX (SP),IX
- LD A,(IX+0) ;byte0 = s_atkwve
- LD (IY+5),A ;sfx_waveform
- LD A,(IX+2) ;byte2 = s_atkcnt
- LD (IY+11),A ;sfx_atkcnt
- LD A,(IX+3) ;byte3 = s_endcnt
- LD (IY+4),A ;sfx_framechop
- LD A,(IX+4) ;byte4 = s_freqhi
- LD (IY+10),A ;sfx_period (high)
- LD A,(IX+5) ;byte5 = s_freqlo
- LD (IY+9),A ;sfx_period (low)
- LD A,(IX+6) ;byte6 = nsefrq
- LD (IY+6),A ;sfx_noisetype
- LD A,(IX+13) ;byte13= s_count2
- LD (IY+12),A ;sfx_count2
- LD (IY+13),0FFH ;sfx_dirflag
-
- LD L,(IY+7) ;sfx_address (word)
- LD H,(IY+8)
- POP IX ;IX=1st byte of effect
- LD BC,16
- ADD HL,BC ;envelope start @ byte 16 of voicedata
- EX DE,HL ;DE = start address of this envelope
-
- LD HL,sfx_envaddress
- LD BC,(chan_num)
- SLA C ;convert to word offset
- ADD HL,BC
- LD (HL),E
- INC HL
- LD (HL),D ;save env address to sfx_envaddress
-
- LD IX,ENV_VARS
- LD BC,(chan_num)
- ADD IX,BC
-
- INC DE
- INC DE ;envbyte2 = repeat number
- LD A,(DE)
- LD (IX+6),A ;new envrepeats
- LD (IX+0),B ;envstage to 0
- LD (IX+3),1 ;envframecnt
- LD (IX+9),B ;envlevel to 0
- LD (IY+3),HOLDTIME ;sfx_hold
- LD (IY+0),0FFH ;reset test byte (sfx_channel)
- JP sfxenvelope
-
- ;-----------------------------------------------------------------------------
- timefx: LD A,(IY+3) ;sfx_hold
- AND A
- JR Z,timing1
- DEC (IY+3) ;sfx_hold
- timing1: DEC (IY+12) ;sfx_count2
- JP P,timing2
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address (word)
- LD BC,13 ;byte13= s_count2
- ADD HL,BC
- LD A,(HL) ;get s_count2
- LD (IY+12),A ;to sfx_count2
- LD A,(IY+13) ;sfx_dirflag
- CPL
- LD (IY+13),A ;sfx_dirflag
- timing2:
- LD A,(IY+11) ;sfx_atkcnt
- AND A
- JR NZ,timing4
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- INC HL
- LD A,(HL) ;byte1 = s_endwve
- LD (IY+5),A ;sfx_waveform
-
- LD A,(IY+4) ;sfx_framechop
- INC A
- JR Z,sfxbending ;continuous SFX
- DEC (IY+4) ;sfx_framechop
- JR NZ,sfxbending
-
- LD A,0 ;force 0 volume at end of sound
- LD HL,(chan_num) ;0,1,2,3
- CALL PSG_volume
- LD A,(NCHAN)
- CP L ;was this the noise channel?
- JP NZ,NEXT_SFX ;no
- LD A,0FFh ;yes, so release noise channel
- LD (NCHAN),A
- XOR A
- LD HL,3 ;force channel 3 (noise)
- CALL PSG_volume ;& set noise volume to 0
- JP NEXT_SFX
-
- timing4:
- DEC (IY+11) ;sfx_atkcnt
-
- ;-----------------------------------------------------------------------------
- sfxbending:
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address (word)
- LD BC,8 ;byte8 = bend type
- ADD HL,BC
- LD A,(HL)
- AND A
- JP Z,sfxspec
-
- sfxbend1:
- CP 1
- JR NZ,sfxbend2
- sfxbend1a:
- LD L,(IY+7)
- LD H,(IY+8)
- LD BC,9 ;byte9 = bendhi
- ADD HL,BC
- LD D,(HL)
- INC HL ;byte10= bendlo
- LD E,(HL)
- LD L,(IY+9)
- LD H,(IY+10) ;sfx_period
- AND A
- SBC HL,DE
- JR sfxbend2b
-
- sfxbend2:
- CP 2
- JR NZ,sfxbend3
- sfxbend2a:
- LD L,(IY+7)
- LD H,(IY+8)
- LD BC,9 ;byte9 = bendhi
- ADD HL,BC
- LD D,(HL)
- INC HL ;byte10= bendlo
- LD E,(HL)
- LD L,(IY+9)
- LD H,(IY+10)
- ADD HL,DE
- sfxbend2b:
- LD (IY+9),L
- LD (IY+10),H
- JR sfxspec
-
- sfxbend3:
- CP 3
- LD C,(IY+11) ;sfx_atkcnt
- JR NZ,sfxbend4
- LD A,C
- AND A
- JR NZ,sfxbend1a
- JR sfxspec
-
- sfxbend4:
- CP 4
- JR NZ,sfxbend5
- LD A,C
- AND A
- JR NZ,sfxbend2a
- JR sfxspec
-
- sfxbend5:
- CP 5
- JR NZ,sfxbend6
- LD A,C
- AND A
- JR NZ,sfxbend1a
- JR sfxbend2a
-
- sfxbend6:
- CP 6
- JR NZ,sfxbend7
- LD A,C
- AND A
- JR NZ,sfxbend2a
- JR sfxbend1a
-
- sfxbend7:
- CP 7
- JR NZ,sfxbend8
- LD A,C
- AND A
- JR Z,sfxbend1a
- JR sfxspec
-
- sfxbend8:
- CP 8
- JR NZ,sfxbend9
- LD A,C
- AND A
- JR Z,sfxbend2a
- JR sfxspec
-
- sfxbend9:
- CP 9
- JR NZ,sfxspec
- BIT 7,(IY+13) ;sfx_dirflag
- JP NZ,sfxbend1a
- JR sfxbend2a
-
- ;-----------------------------------------------------------------------------
- sfxspec:
- LD L,(IY+7)
- LD H,(IY+8)
- LD BC,12 ;byte12= specls
- ADD HL,BC
- LD A,(HL) ;s_specls
- AND A
- JP Z,sfxenvelope
-
- sfxspec01:
- LD L,(IY+7)
- LD H,(IY+8)
- LD BC,12 ;byte12= specls
- ADD HL,BC
- BIT 0,(HL) ;swap freqhi/lo @ 50Hz
- JR Z,sfxspec02
- LD A,(IY+9)
- LD C,(IY+10)
- LD (IY+10),A
- LD (IY+9),C
-
- sfxspec02:
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- LD BC,12 ;byte12= s_specls
- ADD HL,BC
- BIT 1,(HL) ;Complex Hi (freqhi-bendhi/eor with newfhi)
- JR Z,sfxspec04
- LD A,(IY+10) ;sfx_period (high)
- DEC HL
- DEC HL
- DEC HL ;12-3
- SUB (HL) ;byte9 = bendhi
- LD BC,5
- ADD HL,BC ;byte14= newfhi
- LD C,(HL)
- XOR C
- LD (IY+10),A
-
- sfxspec04:
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- LD BC,12 ;byte12= s_specls
- ADD HL,BC
- BIT 2,(HL) ;;waver F lo + (random and 0Fh)
- JR Z,sfxspec08
- CALL RANDOM
- AND 0Fh
- LD (freqoffset),A
-
- sfxspec08: ;RELOAD
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- LD BC,12 ;byte12= s_specls
- ADD HL,BC
- BIT 3,(HL) ;freqhi reloaded with newfhi after each newcnt)
- JR Z,sfxspec10
- LD A,(IY+12) ;sfx_count2
- AND A
- JR NZ,sfxspec10
- LD C,2 ;byte14 = newfhi (12+2)
- ADD HL,BC
- LD A,(HL)
- LD (IY+10),A ;sfx_period (high)
-
- sfxspec10: ;Swap low frequency nibbles @ 50Hz
- LD L,(IY+7)
- LD H,(IY+8)
- LD BC,12 ;byte12= specls
- ADD HL,BC
- BIT 4,(HL)
- JR Z,sfxspec20
- LD A,(IY+9)
- RRCA
- RRCA
- RRCA
- RRCA
- LD (IY+9),A
-
- sfxspec20:
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- LD BC,12 ;byte12= s_specls
- ADD HL,BC
- BIT 5,(HL) ;Complex Lo (freqlo-bendlo/eor with newflo)
- JR Z,sfxspec40
- LD A,(IY+9) ;sfx_period (low)
- DEC HL
- DEC HL ;12-2
- SUB (HL) ;byte10= bendlo
- LD BC,5
- ADD HL,BC ;byte15= newfhi
- LD C,(HL)
- XOR C
- LD (IY+9),A
-
- sfxspec40:
- LD L,(IY+7)
- LD H,(IY+8) ;sfx_address
- LD BC,12 ;byte12= s_specls
- ADD HL,BC
- BIT 6,(HL) ;;waver F lo + (random and 03h)
- JR Z,sfxenvelope
- CALL RANDOM
- AND 03H
- LD (freqoffset),A
-
- ;-----------------------------------------------------------------------------
- sfxenvelope:
- LD HL,sfx_envaddress ;address only
- LD BC,(chan_num)
- SLA C
- ADD HL,BC
- LD E,(HL)
- INC HL
- LD D,(HL) ;DE = addr of 1st byte of effect envelope
-
- BIT 7,(IX+3) ;envframecnt
- JR NZ,sfxfinalvalues ;80h = end of envelope
- DEC (IX+3) ;frame countdown (envframecnt)
- JR NZ,sfxfinalvalues ;more frames till next step
-
- LD A,(IX+9) ;A = current envlevel
- LD L,(IX+0) ;envstage
- LD H,B ;HL = 0,3,6,9,12,or 15 (word)
- ADD HL,DE ;HL = address of current env stage byte
- INC HL ;envbyte1 = step size
- ADD A,(HL) ;+ env step value
- DEC HL ;envbyte0 = frames
- LD (IX+9),A ;save new envlevel
-
- DEC (IX+6) ;envrepeats
- JR Z,sfxnew_stage
- LD A,(HL) ;number of frames till next
- LD (IX+3),A ;& store it in envframecnt
- JR sfxfinalvalues
-
-
- sfxnew_stage:
- LD A,(IX+0) ;envstage
- ADD A,3 ;0-3-6-9-12-15
- LD (IX+0),A ;update pointer (envstage)
-
- LD HL,sfx_envaddress ;update pointer
- LD BC,(chan_num)
- SLA C
- ADD HL,BC
- LD E,(HL)
- INC HL
- LD D,(HL) ;DE = sfx_envaddress
-
- LD L,A
- LD H,B
- ADD HL,DE
-
- LD A,(HL) ;envbyte0 = frames
- CP 0C0H ;any loops ?
- JR C,sfxenv_noloops
-
- AND 3FH ;loop point found
- LD (IX+0),A ;so store it (envstage)
- LD L,A
- LD H,B
- ADD HL,DE
- LD A,(HL) ;new envframecnt at loop point
-
- sfxenv_noloops:
- LD (IX+3),A ;store new envframecnt
- LD A,(IX+0) ;envstage
- CP 15 ;end stage offset ?
- JR Z,sfxfinalvalues
- INC HL
- INC HL ;envbyte 2
- LD A,(HL) ;no, so new envrepeats
- LD (IX+6),A ;& store it
-
- ;-----------------------------------------------------------------------------
- ;sfxfinalvalues are mapped in for 'sounding' voice only
- ;-----------------------------------------------------------------------------
- sfxfinalvalues:
- LD A,(IX+9) ;A = current envlevel
- CP 10H
- JR C,sfx_newvolume ;0Fh or less = within limits
- CP 80H
- JR C,sfx_highclip ;10h to 7Fh = 0Fh (high clip)
- LD A,0 ;80h to FFh = wrapround ( <0 )
- JR sfx_newvolume
- sfx_highclip:
- LD A,0FH
- sfx_newvolume:
- LD E,A
-
- LD A,(effectvol)
- LD D,B
- AND A
- JR Z,sfx_novol
- LD B,A ;loop effectvol times
- SF344: LD A,E
- ADD A,D
- LD D,A
- DJNZ SF344
-
- sfx_novol:
- LD L,D
- LD H,B
- LD E,L
- LD D,H
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,DE
- LD A,H
- RL L
- ADC A,0
- LD (tempbyte),A ;save envelope level
-
- LD A,(IY+5) ;get sfx_waveform
- AND 01H ;tone needed ?
- JR Z,sfxtonevol ;no, so leave A=0
- LD A,(tempbyte) ;yes, so retreive envelope level
- sfxtonevol:
- LD HL,(chan_num) ;0,1,2,3
- CALL PSG_volume
-
- ;-----------------------------------------------------------------------------
- LD A,(tempbyte)
- AND A
- JR Z,sfxnonoise ;release noise if env level = 0
- LD A,(IY+5) ;get sfx_waveform
- AND 02H ;noise needed ?
- JR NZ,sfxfinalnoise ;yes
-
- sfxnonoise:
- LD A,(NCHAN) ;no noise needed in this channel
- CP L ;was this the noise channel?
- JP NZ,sfxfinalfreq ;no
- LD A,0FFh ;yes, so release noise channel
- LD (NCHAN),A
- XOR A ;& set noise volume to 0
- JR sfxnoisevol
-
- sfxfinalnoise:
- LD BC,(chan_num)
- LD A,(NCHAN)
- CP 0FFH ;any noise already?
- JR NZ,sfxfinalnoise2 ;yes, so check for this channel
- LD A,C ;no noise used so far
- LD (NCHAN),A ;so this channel will use noise
-
- sfxfinalnoise2:
- CP C ;noise in this channel?
- JR NZ,sfxfinalfreq ;no
- LD A,(IY+6) ;sfx_noisetype
- and 07h ;mask out any rubbish
- or 0E0h ;select Noise Generator control
- OUT (PSG),A ;and send value
- LD A,(tempbyte) ;retreive final envelope level
-
- sfxnoisevol:
- LD HL,3 ;force channel 3 (noise)
- CALL PSG_volume ;& set noise volume
-
-
- ;-----------------------------------------------------------------------------
- sfxfinalfreq:
- LD A,(freqoffset) ;any random offset (special 04)
- ADD A,(IY+9) ;sfx_period
- LD C,A
- LD B,(IY+10)
- LD HL,(chan_num) ;0,1,2,3
- CALL PSG_freq
-
-
- NEXT_SFX:
- LD HL,chan_num
- DEC (HL)
- BIT 7,(HL)
- JP Z,SFXLOOP
- RET
-
-
- ;-----------------------------------------------------------------------------
- RANDOM:
- LD A,(randseed) ;random number generator
- LD B,A
- ADD A,A
- ADD A,A
- ADD A,A
- ADD A,A
- ADD A,B
- ADD A,11
- LD (randseed),A
- SRL A
- SRL A
- SRL A
- SRL A
- RET
-
- ;-------------------------------------------------------------------------------
- ;START OF MUSIC CODE
- ;-------------------------------------------------------------------------------
-
- SENDMUS:
- BIT 7,A ;Enter with A = tracknum or (80H+fader count)
- JR Z,SMUSIC2
- AND 07FH ;negative value = fade value
- LD (FADER),A
- RET ;nothing this time
-
- SMUSIC2: ;positive value = new track
- DI ;just in case interrupt strikes
- LD HL,(TRKOFF)
- EX DE,HL
- LD L,A
- LD H,0
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,DE ;+ address of 1st byte
- LD BC,6 ;3 words per track
- LD DE,trackbuffer
- LDIR
-
- LD A,2 ;3 channels
- LD (chan_num),A
- LD IY,MUS_VARS+2
- IMLP: LD (IY+0),0 ;vce_mute
- LD (IY+6),0 ;seqstep
- LD (IY+18),0 ;loopcntr
- LD (IY+27),1 ;duration
- LD (IY+39),0 ;voicenum
- LD (IY+75),0FFh ;threshold
- ; LD A,(IY+78) ;marker
- ; LD (IY+3),A ;trkstep
- LD (IY+3),0FFh ;trkstep
-
- CALL readtrack
-
- LD HL,(VCEBANK) ;init envelope (in case of rest at start)
- LD BC,16
- ADD HL,BC ;envelope start @ byte 16 of voicedata
- EX DE,HL ;DE = start address of this envelope
- LD HL,vce_envaddress
- LD BC,(chan_num)
- SLA C ;convert to word offset
- ADD HL,BC
- LD (HL),E
- INC HL
- LD (HL),D ;save env address to vce_envaddress
-
- DEC IY
- LD HL,chan_num
- DEC (HL)
- JP P,IMLP
-
- XOR A
- LD (fadecnt),A
- LD (globoffset),A
- DEC A
- LD (fader),A
- LD (status),A
- LD (TEMPOCNTR),A
- ld (CLOCK_L),a ;starts @ 0FFFFh 1st inc to 0000h
- ld (CLOCK_H),a
- LD A,(musicvol)
- LD (fadevol),A ;reset music volume
- CALL PSG_off
- EI ;re-enable after changes
- RET
-
-
- ;-----------------------------------------------------------------------------
- INTMUSIC:
- LD A,(status)
- BIT 7,A
- RET Z
-
- fadetest:
- LD A,(fader)
- BIT 7,A
- JR NZ,tempotest
-
- OR A ;set flags
- JR Z,TRKSTOP ;080H fader value = stop immediately
- LD HL,fadecnt
- DEC (HL)
- JP P,TEMPOTEST
- LD (HL),A
- LD A,(fadevol)
- DEC A
- LD (fadevol),A
- JR Z,trkstop
-
- TEMPOTEST:
- LD A,(TEMPOCNTR) ;init to 0FFh
- LD HL,TEMPOVAL
- ADD A,(HL)
- LD (TEMPOCNTR),A
- JR NC,TEMPO2
- ld hl,CLOCK_L ;now update tempo clock
- inc (hl)
- jp nz,TEMPO1
- inc hl
- inc (hl)
- TEMPO1: XOR A
- JR TEMPO3
- TEMPO2: LD A,0FFH
- TEMPO3: LD (TEMPOFLAG),A
-
- music1: LD A,0 ;start with channel 0
- LD (chan_num),A
- musicloop:
- LD BC,(chan_num)
- LD A,C
- AND A ;set flags only
- LD HL,0
- JR Z,MS20 ;chan0
- LD L,SDLN
- DEC A
- JR Z,MS20 ;chan1
- SLA L
- MS20: LD (SVPTR),HL ;SVPTR = 0,SDLN,SDLN*2 (offset for SFX)
- LD IY,MUS_VARS
- ADD IY,BC ;+ channel
- LD B,H
- LD C,L
-
- ;-----------------------------------------------------------------------------
- LD IX,SFX_VARS
- ADD IX,BC
- LD A,(IX+3) ;sfx_hold
- AND A
- JR Z,music1b
- LD (IY+0),0FFH ;vce_mute
- ;-----------------------------------------------------------------------------
-
- music1b:
- LD A,(TEMPOFLAG)
- AND A
- JP NZ,treatment
-
- INC (IY+24) ;notelength
- DEC (IY+27) ;duration
- JP NZ,treatment
-
- LD A,(IY+12) ;trkread (seqnumber)
- CP 0FEH
- JR C,seqread
- JR NZ,trkloop
-
- trkstop:
- XOR A
- LD (status),A
- LD A,0FFh
- LD (vce_mute),A ;mute for effects
- LD (vce_mute+1),A
- LD (vce_mute+2),A
- JP PSG_off
- trkloop:
- LD (IY+6),0 ;seqstep
- CALL readtrack
-
-
- seqread:
- LD L,(IY+12) ;seqnumber
- LD H,0
- ADD HL,HL ;2 bytes per address
- LD BC,(SEQOFF)
- ADD HL,BC
- LD C,(HL) ;low byte 1st
- INC HL
- LD B,(HL) ;high byte 2nd
- LD HL,(SEQDATA)
- ADD HL,BC
- LD B,H
- LD C,L
-
- LD A,0FFH
- LD (tempbyte),A ;check later for new voice
- LD L,(IY+6) ;seqstep
- LD A,l
- AND A
- JR NZ,seqread2
- LD (IY+75),0FFh ;reset threshold at start of new sequence
-
- seqread2:
- LD H,0
- LD (IY+42),H ;bendbyte=0
- LD (IY+36),H ;attkend=0
- ld (IY+60),H ;tied_note=0
- add HL,BC
-
- newpair:
- LD A,(HL) ;get new sequence byte
- BIT 7,A
- JR Z,noteread ;bpl
- inc hl ;ready for 2nd byte in pair
-
- parm80: cp 080h ;voice change
- jr nz,parm81
- ld A,(HL)
- LD (tempbyte),A
- jp parmexit
-
- parm81: cp 081h ;rest
- jr nz,parm82
- LD (IY+60),0FFh ;force tied_note (continue with same env)
- CALL VOICEFADE ;set envelope to fade portion
- jp duraread
-
-
- parm82: cp 082h ;bend
- jr nz,parm83
- ld a,(hl)
- LD (IY+42),A ;bendbyte
- jp parmexit
-
- parm83: cp 083h ;tempo
- jr nz,parm84
- ld a,(hl)
- LD (TEMPOVAL),A
- jp parmexit
-
- parm84: cp 084h ;tied
- jr nz,parm85
- ld a,0FFh
- LD (IY+60),A ;tied_note
- jp parmexit
-
- parm85: cp 085h ;gate
- jr nz,parm86
- ld a,(hl)
- ld (IY+75),A ;threshold
- jp parmexit
-
- parm86: cp 086h ;global offset
- jr nz,parmexit
- ld a,(hl)
- ld (globoffset),A
-
-
- parmexit:
- INC HL ;ready for note
- INC (IY+6) ;add 2 to seqstep
- INC (IY+6)
- jp newpair
-
-
- noteread:
- LD A,(HL)
- LD (IY+15),A ;notevalue
- INC HL
- duraread:
- LD A,(HL) ;get next sequence byte
- LD (IY+27),A ;duration
- LD (IY+24),0 ;notelength to 0
- inc hl
- inc (IY+6)
- inc (IY+6) ;add 2 to seqstep
-
- ;-----------------------------------------------------------------------------
- LD A,(IY+0) ;vce_mute
- AND A
- JR Z,newstart ;no SFX
- LD IX,SFX_VARS
- LD BC,(SVPTR) ;0,SDLN,2*SDLN
- ADD IX,BC
- LD A,(IX+3) ;sfx_hold
- AND A
- JR NZ,newstart ;SFX still in initial part
- LD (IY+60),0 ;ended, so force new note
- ;-----------------------------------------------------------------------------
-
- newstart:
- LD A,(tempbyte) ;set to 0FFh before read
- BIT 7,A
- JR NZ,modread ;00h to 3Fh = new voice
- CP (IY+39) ;voicenum = existing voice
- JR Z,modread ;ignore if same voice
- LD (IY+39),A ;or else save new voice (voicenum)
- LD (IY+60),0 ;and force envelope restart (tied_note)
-
- modread:
- BIT 7,(IY+60) ;0 forced for new voice/sfx (tied_note)
- JR NZ,readend ;continue same env.
- PUSH HL
- LD L,(IY+39) ;voicenum
- LD H,0
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL ;32 bytes in each voice
- EX DE,HL
- LD HL,vce_offset
- LD BC,(chan_num)
- SLA C
- ADD HL,BC
- LD (HL),E
- INC HL
- LD (HL),D ;save new vce_offset (00h,20h,40h,60h etc.)
- LD HL,(VCEBANK)
- ADD HL,DE
- EX (SP),HL ;HL restored to SEQDATA
- POP IX ;IX = 1st byte of voice(VCEBANK+vce_offset)
- LD A,(IX+0) ;byte0 = wvefrm
- LD (IY+30),A ;mus_waveform
- LD A,(IX+1) ;byte1 = nsefrq
- LD (IY+78),A ;mus_noisetype
- LD A,(IX+3) ;byte3 = specls
- LD (IY+63),A ;special
- LD A,(IX+5) ;byte5 = offset
- LD (IY+72),A ;transpose
- LD A,(IX+7) ;byte7 = atkcntr
- LD (IY+66),A ;specntdn
- LD A,(IX+15) ;byte15= vdelay
- LD (IY+48),A ;vibdelay
-
- ;-----------------------------------------------------------------------------
- LD IX,SFX_VARS
- LD BC,(SVPTR) ;0,SDLN,2*SDLN
- ADD IX,BC
- LD A,(IX+3) ;sfx_hold
- AND A
- JR NZ,readend
- LD (IY+0),0 ;force vce_mute to 0
- ;-----------------------------------------------------------------------------
- readend:
- LD A,(IY+15) ;notevalue
- add A,(IY+72) ;transpose
- BIT 7,(IY+63) ;special (fixed)
- JR NZ,rdend2
- ld BC,(globoffset)
- add A,C
- rdend2: ld (IY+33),A ;finalnote
-
- ADD A,A
- ADD A,NOTETABLE AND 255
- LD E,A
- ADC A,NOTETABLE/256
- SUB E
- LD D,A
- LD IX,vce_period
- LD BC,(chan_num)
- SLA C ;times 2 for word
- ADD IX,BC
- LD A,(DE)
- LD (IX+0),A ;new vce_period (low)
- INC DE
- LD A,(DE)
- LD (IX+1),A ;new vce_period (high)
-
- LD A,(HL)
- CP 0FFH
- JR NZ,readexit
-
- LD (IY+6),0 ;0FFh=end of sequence
- DEC (IY+9) ;seqrepeat
- JR NZ,readexit
- CALL readtrack
-
- readexit:
- BIT 7,(IY+0) ;vce_mute
- JP NZ,next_channel
- LD IX,vce_offset ;address only
- LD BC,(chan_num)
- SLA C ;* 2 for words
- ADD IX,BC
- LD (IX+18),B ;vibfraction (word)
- LD (IX+19),B ;ensures vibrato calculation
- LD (IY+69),B ;specntup
- JP spec10
-
- treatment:
- BIT 7,(IY+0) ;vce_mute
- JP NZ,next_channel
-
- LD IX,vce_offset ;address only
- LD BC,(chan_num)
- SLA C
- ADD IX,BC
- LD A,(IY+42) ;bendbyte
- AND A
- JR Z,vibrato
- LD H,(IX+13)
- LD L,(IX+12) ;vce_period
- LD C,A
- CP 080H
- JR NC,bending2
-
- LD C,A ;bend up
- SBC HL,BC
- JR bending3
-
- bending2:
- AND 7FH
- LD C,A ;bend down
- ADD HL,BC
-
- bending3:
- LD (IX+12),L
- LD (IX+13),H ;save new vce_period
- JP specials
-
-
- vibrato:
- LD A,(IY+48) ;vibdelay
- AND A
- JR Z,vib1
- DEC (IY+48) ;vibdelay
- JP specials
-
- vib1: LD A,(IY+66) ;specntdn
- AND A
- JP NZ,specials
- LD E,(IX+0) ;vce_offset
- LD D,(IX+1)
- LD HL,(VCEBANK)
- ADD HL,DE ;1st byte of this voice data
- LD C,14 ;byte14 = vibrato
- ADD HL,BC
- LD A,(HL)
- AND A
- JP Z,specials ;vibrato = 0 (none)
-
- BIT 7,(IX+19) ;vibfraction
- JR NZ,vib4 ;values caclulated
- LD E,A ;1st frame of every new note
- LD D,0
- LD HL,vibtab1
- ADD HL,DE
- LD A,(HL)
- LD (IY+57),A ;viblimit
- LD HL,vibtab2
- ADD HL,DE
- LD A,(HL)
- LD (IX+18),A ;vibfraction
- LD (IY+51),D ;vibdir
- LD (IY+54),D ;vibstep
-
- LD L,(IY+33) ;finalnote
- LD H,D
- ADD HL,HL
- LD DE,NOTETABLE
- ADD HL,DE
- LD A,(HL)
- LD C,A
- LD (IX+12),A ;vce_period (low)
- INC HL
- LD A,(HL)
- LD B,A
- LD (IX+13),A ;vce_period (high)
- INC HL
- LD E,(HL) ;1 semitone higher vce_period (low)
- INC HL
- LD D,(HL) ;DE = vce_period 1 semitone higher
- LD H,B
- LD L,C
- AND A
- SBC HL,DE ;HL = semitone 'size'
-
- LD E,(IX+18) ;vibfraction
- LD D,(IX+19)
- CALL DIVHL
- LD A,H
- OR L
- JR NZ,vib2 ;0 = step too small
- LD HL,1 ;so default to 1
- vib2: LD (IX+6),L
- LD (IX+7),H ;vibstepsize
- LD (IX+19),0FFH ;finished = minus
- JR specials
-
- vib4: LD E,(IX+6) ;vibstepsize (word)
- LD D,(IX+7)
- LD L,(IX+12) ;vce_period (word)
- LD H,(IX+13)
- BIT 7,(IY+45) ;freqdir
- JR NZ,vib5
- ADD HL,DE
- JR vib6
-
- vib5: AND A
- SBC HL,DE
-
- vib6: LD (IX+12),L ;vce_period
- LD (IX+13),H
- BIT 7,(IY+51) ;vibdir
- JR NZ,vib7
- INC (IY+54)
- LD A,(IY+54) ;vibstep
- CP (IY+57) ;reached viblimit ?
- JR C,specials
- LD (IY+51),0FFH ;vibdir
- LD A,(IY+45)
- CPL
- LD (IY+45),A ;swap direction (freqdir)
- JR specials
-
- vib7: DEC (IY+54) ;vibstep
- JR NZ,specials
- LD (IY+51),0 ;vibdir
-
-
- ;-----------------------------------------------------------------------------
- specials:
- LD H,(IX+1) ;vce_offset (00h,20h,40h,60h etc.)
- LD L,(IX+0)
- BIT 0,(IY+63) ;ARPEGGIO
- JR Z,spec02
- LD A,(IY+69) ;specntup
- SRL A
- AND 3
- LD E,A
- LD D,0
- ADD HL,DE
- JP spec20a
-
-
- spec02: BIT 1,(IY+63) ;TRILL NOTE
- JR Z,spec04
- BIT 0,(IY+69) ;specntup
- JR NZ,spec02b
- LD L,(IY+33) ;finalnote
- LD H,0
- JR spec02c
- spec02b: LD BC,(VCEBANK)
- ADD HL,BC
- LD BC,13
- ADD HL,BC
- LD L,(HL)
- LD H,B
- BIT 7,L
- JR Z,spec02c
- LD A,L
- AND 7FH
- ADD A,(IY+33) ;finalnote
- LD L,A
- spec02c: ADD HL,HL ;change to alternate note
- LD DE,NOTETABLE
- EX DE,HL
- ADD HL,DE
- LD A,(HL)
- LD (IX+12),A ;vce_period
- INC HL
- LD A,(HL)
- LD (IX+13),A
-
-
- spec04: BIT 2,(IY+63) ;DRUM
- JR Z,spec08
- LD L,(IX+0) ;vce_offset (00h,20h,40h,60h etc.)
- LD H,(IX+1)
- BIT 0,(IY+69) ;specntup
- JR NZ,spec04b
- LD BC,(VCEBANK)
- ADD HL,BC
- LD A,(HL) ;byte0 = wvefrm (HL=VCEBANK+vce_offset)
- JR spec04c
- spec04b: LD A,2 ;noise alternate frames (2 = noise)
- spec04c: LD (IY+30),A ;mus_waveform
- LD BC,(VCEBANK)
- LD L,(IX+0)
- LD H,(IX+1)
- ADD HL,BC
- LD BC,4 ;byte4 = bendrate
- ADD HL,BC
- LD A,(IX+12) ;vce_period
- ADD A,(HL) ;(HL=VCEBANK+vce_offset+4)
- LD C,A
- LD A,(IX+13)
- ADC A,B
- LD B,A
- RLA
- JR C,spec08
- LD (IX+12),C
- LD (IX+13),B
-
-
- spec08: BIT 3,(IY+63) ;CHORD
- JR Z,spec10
- LD A,(IY+69) ;specntup
- AND 3
- ADD A,(IX+0)
- LD L,A
- ADC A,(IX+1)
- SUB L
- LD H,A
- JR spec20a
-
-
- spec10: BIT 4,(IY+63) ;ATKCTRL
- JR Z,spec20
- LD L,(IX+0)
- LD H,(IX+1)
- LD A,(IY+66)
- LD BC,(VCEBANK)
- AND A
- JR Z,spec10b
- ADD HL,BC
- LD BC,8 ;byte8 = atkctrl
- JR spec10c
- spec10b: BIT 7,(IY+36) ;attkend
- JR NZ,spec20
- spec10c: ADD HL,BC
- LD A,(HL)
- LD (IY+30),A ;mus_waveform
-
-
- spec20: BIT 5,(IY+63) ;ATKNOTE
- JR Z,spec40
- LD A,(IY+66) ;specntdn
- AND A
- JR Z,spec20c
- LD A,(IY+69) ;specntup
- ADD A,(IX+0) ;+ vce_offset
- LD L,A
- ADC A,(IX+1)
- SUB L
- LD H,A
- spec20a: LD BC,(VCEBANK)
- ADD HL,BC
- LD BC,9 ;byte9 = atknote1
- ADD HL,BC
- LD A,(HL)
- LD L,A
- LD H,B
- BIT 7,A
- JR Z,spec20d
- AND 7FH ;fixed interval
- LD L,A
- CP 40H
- JR NC,spec20b
- ADD A,(IY+33) ;finalnote
- LD L,A
- JR spec20d
- spec20b: AND 3FH
- LD L,A
- LD A,(IY+33) ;finalnote
- SUB L
- LD L,A
- JR spec20d
- spec20c: BIT 7,(IY+36) ;attkend 1 frame after attack
- JR NZ,spec40
- LD L,(IY+33) ;restore proper note (finalnote)
- spec20d: LD H,0
- ADD HL,HL
- LD BC,NOTETABLE
- ADD HL,BC
- LD A,(HL)
- INC HL
- LD (IX+12),A ;vce_period
- LD A,(HL)
- LD (IX+13),A
-
-
- spec40: BIT 6,(IY+63)
- JR Z,gatecheck
- LD BC,(VCEBANK)
- LD L,(IX+0)
- LD H,(IX+1)
- ADD HL,BC
- LD BC,9 ;byte9 = atknote1
- ADD HL,BC
- LD A,(HL)
- LD (IY+42),A ;bendbyte
-
-
- ;-----------------------------------------------------------------------------
- gatecheck:
- LD A,(IY+24) ;notelength
- CP (IY+75) ;threshold
- JR NZ,envelopes
- CALL VOICEFADE
- LD IX,vce_offset ;address only
- LD BC,(chan_num)
- SLA C
- ADD IX,BC
-
-
- envelopes:
- BIT 7,(IY+60) ;tied_note
- JR NZ,oldenvelope
- LD A,(IY+69) ;specntup
- AND A
- JR NZ,oldenvelope ;not 1st frame
-
- newenvelope:
- LD L,(IX+0) ;vce_offset
- LD H,(IX+1)
- LD BC,(VCEBANK)
- ADD HL,BC
- LD BC,16
- ADD HL,BC ;envelope start @ byte 16 of voicedata
- EX DE,HL ;DE = start address of this envelope
-
- LD HL,vce_envaddress
- LD BC,(chan_num)
- SLA C ;convert to word offset
- ADD HL,BC
- LD (HL),E
- INC HL
- LD (HL),D ;save env address to vce_envaddress
-
- LD IX,ENV_VARS ;address only
- LD BC,(chan_num)
- ADD IX,BC ;IX=address of ENV_VARS+channel
- INC DE
- INC DE ;envbyte2 = repeat number
- LD A,(DE)
- LD (IX+6),A ;read envrepeats
- LD (IX+0),B ;envstage to 0 (start at 1st env byte)
- LD (IX+3),1 ;envframecnt (dec to 0 this time)
- LD (IX+9),B ;envlevel to 0
-
- oldenvelope:
- LD BC,(chan_num)
- LD IX,ENV_VARS ;address only
- ADD IX,BC
- SLA C
-
- LD HL,vce_envaddress
- ADD HL,BC
- LD E,(HL)
- INC HL
- LD D,(HL) ;DE = address of 1st byte of voice envelope
- LD L,(IX+0) ;envstage
- LD H,B ;HL = 0,3,6,9,12,or 15 (word)
- ADD HL,DE
- EX DE,HL ;DE = address of current env stage byte
- BIT 7,(IX+3) ;envframecnt
- JR NZ,vcefinalvalues ;80h = end of envelope
- DEC (IX+3) ;frame countdown (envframecnt)
- JR NZ,vcefinalvalues ;more frames till next step
-
- LD C,(IX+9) ;C = current envlevel
- INC DE
- LD A,(DE) ;A = new env step value
- DEC DE
- ADD A,C
- LD (IX+9),A ;save new envlevel
-
- DEC (IX+6) ;envrepeats
- JR Z,new_stage
- LD A,(DE) ;number of frames till next
- LD (IX+3),A ;& store it in envframecnt
- JR vcefinalvalues
-
-
- new_stage:
- LD A,(IX+0) ;envstage
- ADD A,3 ;0-3-6-9-12-15
- LD (IX+0),A ;save new envstage
-
- LD HL,vce_envaddress ;update pointer
- LD BC,(chan_num)
- SLA C
- ADD HL,BC
- LD E,(HL)
- INC HL
- LD D,(HL) ;DE = vce_envaddress
- LD L,A
- LD H,B
- ADD HL,DE
-
- LD A,(HL) ;A = design framecnt
- CP 0C0H ;any loops ?
- JR C,env_noloops
- AND 3FH ;loop point found
- LD (IX+0),A ;envstage
- LD L,A
- LD H,B
- ADD HL,DE
- LD A,(HL) ;new envframecnt at loop point
-
- env_noloops:
- LD (IX+3),A ;store new envframecnt
- LD A,(IX+0) ;envstage
- CP 15 ;end stage offset ?
- JR Z,vcefinalvalues
- INC HL
- INC HL ;envbyte2
- LD A,(HL) ;no, so new envrepeats
- LD (IX+6),A ;and store it
-
-
- ;-----------------------------------------------------------------------------
- ;vcefinalvalues are mapped in for 'sounding' voices only
- ;tone/noise bits, frequency & volume overriden direct to PSG chip
- ;-----------------------------------------------------------------------------
- vcefinalvalues:
- LD A,(IX+9) ;A = current envlevel
- CP 10H
- JR C,vce_newvolume ;0Fh or less = within limits
- CP 80H
- JR C,vce_highclip ;10h to 7Fh = 0Fh (high clip)
- LD A,0 ;80h to FFh = wrapround ( <0 )
- JR vce_newvolume
- vce_highclip:
- LD A,0FH
- vce_newvolume:
- LD E,A
-
- LD A,(fadevol) ;A = master volume
- LD D,B ;D = 0
- AND A ;set flags only
- JR Z,vce_novol
- LD B,A
- MS421: LD A,E
- ADD A,D
- LD D,A
- DJNZ MS421
-
- vce_novol:
- LD L,D
- LD H,B
- LD E,L
- LD D,H
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,HL
- ADD HL,DE
- LD A,H
- RL L
- ADC A,0
- LD (tempbyte),A ;save envelope level
-
- LD A,(IY+30) ;get mus_waveform
- AND 01H ;tone needed ?
- JR Z,vcetonevol ;no, so leave A=0
- LD A,(tempbyte) ;yes, so retreive envelope level
- vcetonevol:
- LD HL,(chan_num) ;0,1,2,3
- CALL PSG_volume
-
- ;-----------------------------------------------------------------------------
- LD A,(tempbyte)
- AND A
- JR Z,nonoise ;release noise if envelope level = 0
- LD A,(IY+30) ;get mus_waveform
- AND 02H ;noise needed ?
- JR NZ,finalnoise ;yes
-
- nonoise:
- LD A,(NCHAN) ;no noise needed in this channel
- CP L ;was this the noise channel?
- JP NZ,finalfreq ;no
- LD A,0FFh ;yes, so release noise channel
- LD (NCHAN),A
- XOR A ;& set noise volume to 0
- JR vcenoisevol
-
- finalnoise:
- LD BC,(chan_num)
- LD A,(NCHAN)
- CP 0FFH ;any noise already?
- JR NZ,finalnoise2 ;yes, so check for this channel
- LD A,C ;no noise used so far
- LD (NCHAN),A ;so this channel will use noise
-
- finalnoise2:
- CP C ;noise in this channel?
- JR NZ,finalfreq ;no
- LD A,(IY+78) ;mus_noisetype
- and 07h ;just in case
- or 0E0h ;select Noise Generator control
- OUT (PSG),A ;and send value
- LD A,(tempbyte) ;retreive final envelope level
-
- vcenoisevol:
- LD HL,3 ;force channel 3 (noise)
- CALL PSG_volume ;& set noise volume
-
-
- ;-----------------------------------------------------------------------------
- finalfreq:
- LD HL,vce_period
- LD BC,(chan_num)
- SLA C
- ADD HL,BC
- EX DE,HL
- LD A,(DE) ;vce_period (low)
- INC DE
- LD L,A
- LD A,(DE)
- LD H,A ;HL = vce_period (word)
- LD A,(chan_num)
- AND A
- JR Z,finalfreq3 ;channel 1 always in tune
-
- LD D,0
- LD E,H
- CP 1
- JR NZ,finalfreq2
- ADD HL,DE ;channel 2 1/256th lower
- JR finalfreq3
- finalfreq2:
- AND A
- SBC HL,DE ;channel 3 1/256th higher
- finalfreq3:
- LD C,L
- LD B,H ;frequency in BC
- LD HL,(chan_num) ;0,1,2,3
- CALL PSG_freq
-
-
- ;-----------------------------------------------------------------------------
- LD A,(IY+66) ;specntdn
- AND A
- JR NZ,finalval1
- LD (IY+36),0FFH ;attkend
- JR finalval2
- finalval1:
- DEC (IY+66) ;specntdn
- finalval2:
- INC (IY+69) ;specntup
-
- next_channel:
- LD HL,chan_num
- inc (HL)
- LD A,(HL)
- CP 3
- JP C,MUSICLOOP
- RET
-
-
-
-
- ;-----------------------------------------------------------------------------
- readtrack:
- LD HL,trackbuffer
- LD BC,(chan_num)
- SLA C
- ADD HL,BC ;times 2 for word offset
- LD C,(HL) ;low byte 1st
- INC HL
- LD B,(HL) ;high byte 2nd
- LD HL,(TRKDATA)
- ADD HL,BC
- LD B,H
- LD C,L ;BC=address of 1st track byte
-
- readt0: INC (IY+3) ;trackstep
- LD L,(IY+3)
- LD H,0
- ADD HL,BC ;HL=address of this track byte
- LD A,(HL)
- CP 0FDH
- JR C,readt1
- JR Z,readfade
- LD (IY+12),A ;seqnumber
- INC HL
- LD A,(HL)
- DEC A
- LD (IY+3),A ;trackstep
- RET
-
- readfade:
- INC (IY+3) ;trackstep
- INC HL
- LD A,(HL)
- LD (fader),A
- JR readt0
-
- readt1: BIT 6,(HL) ;40h bit set means loop
- JR Z,readt2
-
- readl0: LD A,(IY+18) ;loopcntr
- AND A
- JR NZ,readl1 ;loopcntr <> 0 means already in loop
- LD A,(HL) ;get track byte
- AND 3FH
- LD (IY+18),A ;loopcntr
- INC (IY+3) ;trackstep
- INC HL
- PUSH HL
- AND A
- SBC HL,BC
- LD (IY+21),L ;return point (loopmem)
- POP HL
- JR readt2
-
- readl1: DEC (IY+18) ;already in loop (loopcntr)
- JR NZ,readl2
- JR readt0 ;move to next track byte
-
- readl2: LD A,(IY+21) ;loopmem
- LD (IY+3),A ;-> trackstep
- LD L,A
- LD H,0
- ADD HL,BC
-
- readt2: LD A,(HL)
- LD (IY+9),A ;seqrepeat
- INC (IY+3) ;trackstep
- INC HL
- LD A,(HL)
- LD (IY+12),A ;seqnumber
- RET
-
- ;-----------------------------------------------------------------------------
- ;Set all chip volumes to zero
- ;-----------------------------------------------------------------------------
- PSG_off:
- ld HL,CLRPSG
- ld C,PSG
- ld B,4 ;4 bytes in table
- OTIR
- ret
-
-
- ;-----------------------------------------------------------------------------
- ;Set PSG volume (Enter with A = 4 bit volume value/HL=chan_num)
- ;-----------------------------------------------------------------------------
- PSG_volume:
- PUSH AF
- cpl
- and 0Fh ;convert volume to attenuation
- ld B,A ;& save for later
- LD A,L ;get chan_num (0,1,2,3)
- SLA A ;0,2,4,6
- ADD A,9 ;9,B,D,F
- SLA A
- SLA A
- SLA A
- SLA A ;90,B0,D0,F0
- ADD A,B ;add in atten. value
- OUT (PSG),A
- POP AF
- RET
-
- ;-----------------------------------------------------------------------------
- ;Set PSG frequency (Enter with BC = 10 bit frequency value/HL=chan_num)
- ;-----------------------------------------------------------------------------
- PSG_freq:
- LD A,L ;get chan_num (0,1,2,3)
- SLA A ;0,2,4,6
- ADD A,8 ;8,A,C,E
- SLA A
- SLA A
- SLA A
- SLA A ;80,A0,C0,E0
- ld D,A ;save for later
- ld A,C ;get low byte of frequency
- AND 0Fh ;mask out high nibble
- OR D
- OUT (PSG),A ;set 1st byte
-
- LD A,C ;get low byte of frequency
-
- nop ;OK with this
-
- bug: SRL B
- RRA
- SRL B
- RRA
- SRL B
- RRA
- SRL B
- RRA
- AND 3Fh ;top 2 bits of 2nd byte always 0
- OUT (PSG),A ;set 2nd byte
- RET
-
- ;-----------------------------------------------------------------------------
- ;Sets envelope to fade portion (called by GATE and REST)
- ;-----------------------------------------------------------------------------
- VOICEFADE:
- LD IX,ENV_VARS ;address only
- LD DE,(chan_num)
- ADD IX,DE
- LD A,(IX+0) ;current envstage
- CP 15 ;already at fade ?
- JR Z,VCEXIT ;yes, so leave alone
- LD (IX+0),9 ;envstage to 12 (fade) this frame
- LD (IX+3),1 ;envframecnt to 0 this frame
- LD (IX+6),1 ;envrepeats to 0 this frame
- VCEXIT: RET
-
- ;-----------------------------------------------------------------------------
- ;DIVHL - unsigned divide HL/DE
- ;-----------------------------------------------------------------------------
- DIVHL:
- ADD HL,HL
- LD A,H
- LD C,L
- LD HL,0
- APDIV: LD B,16
- DI22: ADC HL,HL
- SBC HL,DE
- JR NC,DI32
- ADD HL,DE
- DI32: RL C
- RLA
- DJNZ DI22
- CPL
- LD H,A
- LD A,C
- CPL
- LD L,A
- RET
-
-
- ;-------------------------------------------------------------------------------
- ;START OF ROM DATA
- ;-------------------------------------------------------------------------------
- CLRPSG db 09Fh,0BFh,0DFh,0FFh
-
- vibtab1: DB 0,1,1,1,1,4,3,2
- DB 4,3,2,1,3,2,1,3,2,2,1
- vibtab2: DB 1,32,16,8,4,32,32,16
- DB 16,16,8,2,8,4,1,2,2,1,1
-
- NOTETABLE: dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh ;C-2 00h (too low)
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh ;C-1 0Ch (too low)
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh ;C0 18h (too low)
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh
- dw 3FFh,3FFh,3FFh,3FFh,3FFh,3FFh ;C1 24h (up 1 octave)
- dw 3FFh,3FFh,3FFH,3F0h,3B7h,382h ;A1 110Hz (lowest)
- dw 34Fh,320h,2F3h,2C9h,2A1h,27Bh ;C2 30h 130Hz
- dw 257h,236h,216h,1F8h,1DCh,1C1h
- dw 1A8h,190h,179h,164h,150h,13Dh ;C3 3Ch 262Hz(MID)
- dw 12Ch,11Bh,10Bh,0FCh,0EEh,0E0h
- dw 0D4h,0C8h,0BDh,0B2h,0A8h,09Fh ;C4 48h 523Hz
- dw 096h,08Dh,085h,07Eh,077h,070h
- dw 06Ah,064h,05Eh,059h,054h,04Fh ;C5 54h 1046Hz
- dw 04Bh,047h,043h,03Fh,03Bh,038h
- dw 035h,032h,02Fh,02Dh,02Ah,028h ;C6 60h 2093Hz
- dw 025h,023h,021h,01Fh,01Eh,01Ch
- dw 01Ah,019h,018h,016h,015h,014h ;C7 6Ch 4186Hz
- dw 013h,012h,011h,010h,00Fh,00Eh
- dw 00Dh,00Ch,00Ah,008h,006h,004h ;C8 78h 8372Hz
- dw 002h,000h ;G8 7Fh 12542Hz
- ; dw 00Dh,00Ch,00Ch,00Bh,00Ah,00Ah ;C8 78h 8372Hz
- ; dw 009h,009h ;G8 7Fh 12542Hz
-
- CODESIZE equ $-JUMPTABLE
-
- ;*****************************************************************************
- ORG 2000H ;comment this out for driver version
-
- GAMEDATA: INCLUDE BLANK-GG.SND (BIN) ;7 WORD VECTOR TABLE @ START
-
- MUSICEND:
- ;*****************************************************************************
-
- ; IF GAMEGEAR
- ; ORG $7FF8
- ; DB 0FFH DUP 8
- ; ENDIF
- ;On the Master system this area is occupied by the registration area.
- ;It is not used on the Game Gear so 7FF8H to 7FFFH should be filled
- ;with 0FFH to ensure valid values 'under' the comms.
-
- ;-------------------------------------------------------------------------------
- ;DRIVER RAM VARIABLES
- ;-------------------------------------------------------------------------------
- ORG MUSICRAM
-
- RAM_VARS:
- sfxno DS 1 ;00h-4Fh=effect/ 0FFh=no effect
- tuneno DS 1 ;00h-17h=music/ 80h=stop/ 81h-0FEh=fade
- status: DS 1 ;0FFh=music active/ 00h=music finished
- effectvol: DS 1 ;00h-0Fh=master volume setting for effects
- musicvol: DS 1 ;00h-0Fh=master volume setting for music
- fadevol: DS 1 ;00-0Fh=current music volume
-
- ;-----------------------------------------------------------------------------
- SFX_VARS:
- sfx_channel: DS 1 ;IY=0
- sfx_priority: DS 1 ;+1
- sfx_priortest: DS 1 ;+2
- sfx_hold: DS 1 ;+3
- sfx_framechop: DS 1 ;+4
- sfx_waveform: DS 1 ;+5
- sfx_noisetype DS 1 ;+6
- sfx_address: DS 2 ;+7/8 (word)
- sfx_period: DS 2 ;+9/10 (word)
- sfx_atkcnt: DS 1 ;+11
- sfx_count2: DS 1 ;+12
- sfx_dirflag: DS 1 ;+13
-
- SDLN equ $-SFX_VARS
- SVARSB: DS SDLN
- SVARSC: DS SDLN
-
- ;-----------------------------------------------------------------------------
- MUS_VARS:
- vce_mute: DS 3 ;IY=0 0=music sounds/FFh=voice muted
- trackstep: DS 3 ;3
- seqstep: DS 3 ;6
- seqrepeat: DS 3 ;9
- seqnumber: DS 3 ;12
- notevalue DS 3 ;15
- loopcntr: DS 3 ;18
- loopmem: DS 3 ;21
- notelength: DS 3 ;24
- duration: DS 3 ;27
- mus_waveform: DS 3 ;30 0=none/1=tone/2=noise/3=tone & noise
- finalnote: DS 3 ;33
- attkend: DS 3 ;36
- voicenum: DS 3 ;39
- bendbyte: DS 3 ;42
-
- freqdir: DS 3 ;45
- vibdelay: DS 3 ;48
- vibdir: DS 3 ;51
- vibstep: DS 3 ;54
- viblimit: DS 3 ;57
-
- tied_note: DS 3 ;60
- special: DS 3 ;63
- specntdn: DS 3 ;66
- specntup: DS 3 ;69
-
- transpose DS 3 ;+72
- threshold DS 3 ;+75 length before gate off (init to $FF)
- mus_noisetype DS 3 ;+78
-
- ;marker: DS 3 ;+78 (DEFB 0FFH,0FFH,0FFH)
-
-
- vce_offset: DS 6 ;IX=0 (+75) 00h,20h,40h,60h etc.
- vibstepsize: DS 6 ;+6/7 (+81)
- vce_period: DS 6 ;+12/13 (+87)
- vibfraction: DS 6 ;+18/19 (+93)
- trackbuffer: DS 6
-
- ;-----------------------------------------------------------------------------
- ENV_VARS:
- envstage: DS 3 ;+0 0,3,6,9,12, or 15
- envframecnt: DS 3 ;+3
- envrepeats: DS 3 ;+6
- envlevel DS 3 ;+9
-
- sfx_envaddress: DS 6 ;address of 1st byte of current envelope
- vce_envaddress: DS 6 ;address of 1st byte of current envelope
-
-
- ;-----------------------------------------------------------------------------
- chan_num: DS 2 ;words
- SVPTR: DS 2 ;SVPTR = 0,SDLN,SDLN*2 (offset for SFX)
- NCHAN: DS 1 ;current noise channel 0,1,2 (FF=no noise)
- randseed DS 1 ;for random number
- freqoffset DS 1 ;random frequency offset
-
- fader: DS 1
- fadecnt: DS 1
- tempbyte: DS 1
- TEMPOVAL: DS 1
- TEMPOFLAG: DS 1
- TEMPOCNTR: DS 1
- CLOCK_L DS 1
- CLOCK_H DS 1
- globoffset DS 1
-
- FXBANK: DS 2 ;address of 1st byte of effects
- FXTABLE: DS 2
- VCEBANK: DS 2
- SEQOFF: DS 2
- SEQDATA: DS 2
- TRKOFF: DS 2
- TRKDATA: DS 2
-
- VARSIZE equ $-RAM_VARS
-
-
-
-
- ;-------------------------------------------------------------------------------
- ;DEMO RAM VARIABLES
- ;-------------------------------------------------------------------------------
- IF DEMO
- BANKVAL: DS 1 ;Current bank value (in ram)
- IF GAMEGEAR
- PALLETTE: DS 64 ;Temp Game Gear pallette
- ENDIF
- SCRLCOUNT: DS 1 ;Counter for scroll
- editnum DS 1
- vbi_flag DS 1
- PCnewdata ds 1
- PCbuffer ds 24 ;6 + (6 * 3)
- ENDIF
-
- END
-