;Universal PT2'n'PT3 Turbo Sound player for ZX Spectrum
;(c)2004-2007 S.V.Bulba <vorobey@mail.khstu.ru>
;Specially for AlCo
;http://bulba.untergrund.net/ (http://bulba.at.kz/)
;Release number
Release EQU "0"
;Conditional assembly
;1) Current position counters at (Vars1+0) and (Vars2+0)
CurPosCounter=1
;2) Allow channels allocation bits at (START+10)
ACBBAC=0
;3) Allow loop checking and disabling
LoopChecker=1
;4) Insert official identificator
Id=1
;5) Set IY for correct return to ZX Basic
Basic=0
;Features
;--------
;-Can be compiled at any address (i.e. no need rounding ORG
; address).
;-Variables (VARS) can be located at any address (not only after
; code block).
;-INIT subprogram checks PT3-module version and rightly
; generates both note and volume tables outside of code block
; (in VARS).
;-Two portamento (spc. command 3xxx) algorithms (depending of
; PT3 module version).
;-New 1.XX and 2.XX special command behaviour (only for PT v3.7
; and higher).
;-Any Tempo value are accepted (including Tempo=1 and Tempo=2).
;-TS modes: 2xPT3, 2xPT2 and PT v3.7 TS standard.
;-Fully compatible with Ay_Emul PT3 and PT2 players codes.
;-See also notes at the end of this source code.
;Limitations
;-----------
;-Can run in RAM only (self-modified code is used).
;-PT2 position list must be end by #FF marker only.
;Warning!!! PLAY subprogram can crash if no module are loaded
;into RAM or INIT subprogram was not called before.
;Call MUTE or INIT one more time to mute sound after stopping
;playing
;ORG #C000
;Test codes (commented)
; LD A,32 ;SinglePT3(TS if TSPT3.7),ABC,Looped
; LD (START+10),A
; LD HL,#8000 ;Mod1
; LD DE,#A000 ;Mod2 (optional)
; CALL START+3
; EI
;_LP HALT
; CALL START+5
; XOR A
; IN A,(#FE)
; CPL
; AND 15
; JR Z,_LP
; JR START+8
TonA EQU 0
TonB EQU 2
TonC EQU 4
Noise EQU 6
Mixer EQU 7
AmplA EQU 8
AmplB EQU 9
AmplC EQU 10
Env EQU 11
EnvTp EQU 13
;Entry and other points
;START initialize playing of modules at MDLADDR (single module)
;START+3 initialization with module address in HL and DE (TS)
;START+5 play one quark
;START+8 mute
;START+10 setup and status flags
START
LD HL,MDLADDR ;DE - address of 2nd module for TS
JR INIT
JP PLAY
JR MUTE
SETUP DB %00100001 ;set bit0, if you want to play without looping
;(optional);
;set bit1 for PT2 and reset for PT3 before
;calling INIT;
;bits2-3: %00-ABC, %01-ACB, %10-BAC (optional);
;bits4-5: %00-no TS, %01-2 modules TS, %10-
;autodetect PT3 TS-format by AlCo (PT 3.7+);
;Remark: old PT3 TS-format by AlCo (PT 3.6) is not
;documented and must be converted to new standard.
;bit6 is set each time, when loop point of 2nd TS
;module is passed (optional).
;bit7 is set each time, when loop point of 1st TS
;or of single module is passed (optional).
;Identifier
IF Id
DB "=UniPT2/PT3/TS-Player r.",Release,"="
ENDIF
IF LoopChecker
CHECKLP LD HL,SETUP
BIT 0,(IY-100+VRS.ModNum)
JR Z,CHL1
SET 6,(HL)
JR CHL2
CHL1 SET 7,(HL)
CHL2 BIT 0,(HL)
RET Z
POP HL
INC (IY-100+VRS.DelyCnt)
INC (IY-100+VRS.ChanA+CHP.NtSkCn)
XOR A
LD (IY-100+VRS.AYREGS+AmplA),A
LD (IY-100+VRS.AYREGS+AmplB),A
LD (IY-100+VRS.AYREGS+AmplC),A
RET
ENDIF
MUTE XOR A
LD H,A
LD L,A
LD (VARS1+VRS.AYREGS+AmplA),A
LD (VARS1+VRS.AYREGS+AmplB),HL
LD (VARS2+VRS.AYREGS+AmplA),A
LD (VARS2+VRS.AYREGS+AmplB),HL
JP ROUT
INIT
;HL - AddressOfModule
;DE - AddresOf2ndModule
PUSH DE
PUSH HL
LD HL,VARS
LD (HL),0
LD DE,VARS+1
LD BC,VAR0END-VARS-1
LDIR
INC HL
LD (VARS1+VRS.AdInPtA),HL ;ptr to zero
LD (VARS2+VRS.AdInPtA),HL
POP HL
LD IY,VARS1+100
LD A,(START+10)
AND 2
JP NZ,I_PT2
CALL INITPT3
LD HL,(e_-SamCnv-2)*256+#18
LD (SamCnv),HL
LD A,#BA
LD (OrnCP),A
LD (SamCP),A
LD A,#7B
LD (OrnLD),A
LD (SamLD),A
LD A,#87
LD (SamClc2),A
POP HL
;Use version and ton table of 1st module
LD A,(IX+13-100) ;EXTRACT VERSION NUMBER
SUB #30
JR C,L20
CP 10
JR C,L21
L20 LD A,6
L21 LD (Version),A
PUSH AF ;VolTable version
CP 4
LD A,(IX+99-100) ;TONE TABLE NUMBER
RLA
AND 7
PUSH AF ;NoteTable number
LD IY,VARS2+100
LD A,(START+10)
AND 48
JR Z,NOTS
CP 16
JR Z,TwoPT3s
LD A,(Version)
CP 7
JR C,NOTS
LD A,(IX+98-100) ;ALCO TS MARKER
CP #20
JR Z,NOTS
LD HL,VARS1
LD DE,VARS2
LD BC,VRS
LDIR
SET 1,(IY-100+VRS.ModNum)
LD C,A
ADD A,A
ADD A,C
SUB 2
LD (TSSub),A
JR AlCoTS_
TwoPT3s CALL INITPT3
AlCoTS_ LD A,1
LD (is_ts),A
SET 0,(IY-100+VRS.ModNum)
NOTS LD BC,PT3PD
LD HL,0
LD DE,PT3EMPTYORN
JR INITCOMMON
I_PT2 CALL INITPT2
LD HL,#51CB
LD (SamCnv),HL
LD A,#BB
LD (OrnCP),A
LD (SamCP),A
LD A,#7A
LD (OrnLD),A
LD (SamLD),A
LD A,#80
LD (SamClc2),A
POP HL
LD A,5
LD (Version),A
PUSH AF
LD A,2
PUSH AF
LD A,(START+10)
AND 48
JR Z,NOTS2
LD IY,VARS2+100
LD A,1
LD (is_ts),A
SET 0,(IY-100+VRS.ModNum)
CALL INITPT2
NOTS2 LD BC,PT2PD
LD HL,#8687
LD DE,PT2EMPTYORN
INITCOMMON
IF Basic
LD IY,#5C3A
ENDIF
LD (PTDEC),BC
LD (PsCalc),HL
PUSH DE
;note table data depacker
;(c) Ivan Roshin
LD DE,T_PACK
LD BC,T1_+(2*49)-1
TP_0 LD A,(DE)
INC DE
CP 15*2
JR NC,TP_1
LD H,A
LD A,(DE)
LD L,A
INC DE
JR TP_2
TP_1 PUSH DE
LD D,0
LD E,A
ADD HL,DE
ADD HL,DE
POP DE
TP_2 LD A,H
LD (BC),A
DEC BC
LD A,L
LD (BC),A
DEC BC
SUB (#F8*2)&#ff
JR NZ,TP_0
INC A
LD (VARS1+VRS.DelyCnt),A
LD (VARS2+VRS.DelyCnt),A
LD HL,#F001 ;H - CHP.Volume, L - CHP.NtSkCn
LD (VARS1+VRS.ChanA+CHP.NtSkCn),HL
LD (VARS1+VRS.ChanB+CHP.NtSkCn),HL
LD (VARS1+VRS.ChanC+CHP.NtSkCn),HL
LD (VARS2+VRS.ChanA+CHP.NtSkCn),HL
LD (VARS2+VRS.ChanB+CHP.NtSkCn),HL
LD (VARS2+VRS.ChanC+CHP.NtSkCn),HL
POP HL
LD (VARS1+VRS.ChanA+CHP.OrnPtr),HL
LD (VARS1+VRS.ChanB+CHP.OrnPtr),HL
LD (VARS1+VRS.ChanC+CHP.OrnPtr),HL
LD (VARS2+VRS.ChanA+CHP.OrnPtr),HL
LD (VARS2+VRS.ChanB+CHP.OrnPtr),HL
LD (VARS2+VRS.ChanC+CHP.OrnPtr),HL
POP AF
;NoteTableCreator (c) Ivan Roshin
;A - NoteTableNumber*2+VersionForNoteTable
;(xx1b - 3.xx..3.4r, xx0b - 3.4x..3.6x..VTII1.0)
LD HL,NT_DATA
LD D,0
ADD A,A
LD E,A
ADD HL,DE
LD E,(HL)
INC HL
SRL E
SBC A,A
AND #A7 ;#00 (NOP) or #A7 (AND A)
LD (L3),A
EX DE,HL
LD BC,T1_
ADD HL,BC
LD A,(DE)
ADD A,T_&#ff
LD C,A
ADC A,T_/256
SUB C
LD B,A
PUSH BC
LD DE,NT_
PUSH DE
LD B,12
L1 PUSH BC
LD C,(HL)
INC HL
PUSH HL
LD B,(HL)
PUSH DE
EX DE,HL
LD DE,23
LD IXH,8
L2 SRL B
RR C
L3 DB #19 ;AND A or NOP
LD A,C
ADC A,D ;=ADC 0
LD (HL),A
INC HL
LD A,B
ADC A,D
LD (HL),A
ADD HL,DE
DEC IXH
JR NZ,L2
POP DE
INC DE
INC DE
POP HL
INC HL
POP BC
DJNZ L1
POP HL
POP DE
LD A,E
CP TCOLD_1&#ff
JR NZ,CORR_1
LD A,#FD
LD (NT_+#2E),A
CORR_1 LD A,(DE)
AND A
JR Z,TC_EXIT
RRA
PUSH AF
ADD A,A
LD C,A
ADD HL,BC
POP AF
JR NC,CORR_2
DEC (HL)
DEC (HL)
CORR_2 INC (HL)
AND A
SBC HL,BC
INC DE
JR CORR_1
TC_EXIT
POP AF
;VolTableCreator (c) Ivan Roshin
;A - VersionForVolumeTable (0..4 - 3.xx..3.4x;
;5.. - 2.x,3.5x..3.6x..VTII1.0)
CP 5
LD HL,#11
LD D,H
LD E,H
LD A,#17
JR NC,M1
DEC L
LD E,L
XOR A
M1 LD (M2),A
LD IX,VT_+16
LD C,#F
INITV2 PUSH HL
ADD HL,DE
EX DE,HL
SBC HL,HL
LD B,#10
INITV1 LD A,L
M2 DB #7D
LD A,H
ADC A,0
LD (IX),A
INC IX
ADD HL,DE
DJNZ INITV1
POP HL
LD A,E
CP #77
JR NZ,M3
INC E
M3 DEC C
JR NZ,INITV2
JP ROUT
INITPT3 CALL SETMDAD
PUSH HL
LD DE,100
ADD HL,DE
LD A,(HL)
LD (IY-100+VRS.Delay),A
PUSH HL
POP IX
ADD HL,DE
CALL SETCPPT
LD E,(IX+102-100)
INC HL
IF CurPosCounter
LD (IY-100+VRS.PosSub),L
ENDIF
ADD HL,DE
CALL SETLPPT
POP DE
LD L,(IX+103-100)
LD H,(IX+104-100)
ADD HL,DE
CALL SETPTPT
LD HL,169
ADD HL,DE
CALL SETORPT
LD HL,105
ADD HL,DE
SETSMPT LD (IY-100+VRS.SamPtrs),L
LD (IY-100+VRS.SamPtrs+1),H
RET
INITPT2 LD A,(HL)
LD (IY-100+VRS.Delay),A
PUSH HL
PUSH HL
PUSH HL
INC HL
INC HL
LD A,(HL)
INC HL
CALL SETSMPT
LD E,(HL)
INC HL
LD D,(HL)
POP HL
AND A
SBC HL,DE
CALL SETMDAD
POP HL
LD DE,67
ADD HL,DE
CALL SETORPT
LD E,32
ADD HL,DE
LD C,(HL)
INC HL
LD B,(HL)
LD E,30
ADD HL,DE
CALL SETCPPT
LD E,A
INC HL
IF CurPosCounter
LD (IY-100+VRS.PosSub),L
ENDIF
ADD HL,DE
CALL SETLPPT
POP HL
ADD HL,BC
SETPTPT LD (IY-100+VRS.PatsPtr),L
LD (IY-100+VRS.PatsPtr+1),H
RET
SETMDAD LD (IY-100+VRS.MODADDR),L
LD (IY-100+VRS.MODADDR+1),H
RET
SETORPT LD (IY-100+VRS.OrnPtrs),L
LD (IY-100+VRS.OrnPtrs+1),H
RET
SETCPPT LD (IY-100+VRS.CrPsPtr),L
LD (IY-100+VRS.CrPsPtr+1),H
RET
SETLPPT LD (IY-100+VRS.LPosPtr),L
LD (IY-100+VRS.LPosPtr+1),H
RET
SETENBS LD (IY-100+VRS.EnvBase),L
LD (IY-100+VRS.EnvBase+1),H
RET
SETESLD LD (IY-100+VRS.CurESld),L
LD (IY-100+VRS.CurESld+1),H
RET
GETIX PUSH IY
POP IX
ADD IX,DE
RET
PTDECOD CALL GETIX
PTDEC EQU $+1
JP #C3C3
;PT2 pattern decoder
PD2_SAM CALL SETSAM
JR PD2_LOOP
PD2_EOff LD (IX-12+CHP.Env_En),A
JR PD2_LOOP
PD2_ENV LD (IX-12+CHP.Env_En),16
LD (IY-100+VRS.AYREGS+EnvTp),A
LD A,(BC)
INC BC
LD L,A
LD A,(BC)
INC BC
LD H,A
CALL SETENBS
JR PD2_LOOP
PD2_ORN CALL SETORN
JR PD2_LOOP
PD2_SKIP INC A
LD (IX-12+CHP.NNtSkp),A
JR PD2_LOOP
PD2_VOL RRCA
RRCA
RRCA
RRCA
LD (IX-12+CHP.Volume),A
JR PD2_LOOP
PD2_DEL CALL C_DELAY
JR PD2_LOOP
PD2_GLIS SET 2,(IX-12+CHP.Flags)
INC A
LD (IX-12+CHP.TnSlDl),A
LD (IX-12+CHP.TSlCnt),A
LD A,(BC)
INC BC
LD (IX-12+CHP.TSlStp),A
ADD A,A
SBC A,A
LD (IX-12+CHP.TSlStp+1),A
SCF
JR PD2_LP2
PT2PD AND A
PD2_LP2 EX AF,AF'
PD2_LOOP LD A,(BC)
INC BC
ADD A,#20
JR Z,PD2_REL
JR C,PD2_SAM
ADD A,96
JR C,PD2_NOTE
INC A
JR Z,PD2_EOff
ADD A,15
JP Z,PD_FIN
JR C,PD2_ENV
ADD A,#10
JR C,PD2_ORN
ADD A,#40
JR C,PD2_SKIP
ADD A,#10
JR C,PD2_VOL
INC A
JR Z,PD2_DEL
INC A
JR Z,PD2_GLIS
INC A
JR Z,PD2_PORT
INC A
JR Z,PD2_STOP
LD A,(BC)
INC BC
LD (IX-12+CHP.CrNsSl),A
JR PD2_LOOP
PD2_PORT RES 2,(IX-12+CHP.Flags)
LD A,(BC)
INC BC
INC BC ;ignoring precalc delta to right sound
INC BC
SCF
JR PD2_LP2
PD2_STOP LD (IX-12+CHP.TSlCnt),A
JR PD2_LOOP
PD2_REL LD (IX-12+CHP.Flags),A
JR PD2_EXIT
PD2_NOTE LD L,A
LD A,(IX-12+CHP.Note)
LD (PrNote+1),A
LD (IX-12+CHP.Note),L
XOR A
LD (IX-12+CHP.TSlCnt),A
SET 0,(IX-12+CHP.Flags)
EX AF,AF'
JR NC,NOGLIS2
BIT 2,(IX-12+CHP.Flags)
JR NZ,NOPORT2
LD (LoStep),A
ADD A,A
SBC A,A
EX AF,AF'
LD H,A
LD L,A
INC A
CALL SETPORT
NOPORT2 LD (IX-12+CHP.TSlCnt),1
NOGLIS2 XOR A
PD2_EXIT LD (IX-12+CHP.PsInSm),A
LD (IX-12+CHP.PsInOr),A
LD (IX-12+CHP.CrTnSl),A
LD (IX-12+CHP.CrTnSl+1),A
JP PD_FIN
;PT3 pattern decoder
PD_OrSm LD (IX-12+CHP.Env_En),0
CALL SETORN
PD_SAM_ LD A,(BC)
INC BC
RRCA
PD_SAM CALL SETSAM
JR PD_LOOP
PD_VOL RRCA
RRCA
RRCA
RRCA
LD (IX-12+CHP.Volume),A
JR PD_LP2
PD_EOff LD (IX-12+CHP.Env_En),A
LD (IX-12+CHP.PsInOr),A
JR PD_LP2
PD_SorE DEC A
JR NZ,PD_ENV
LD A,(BC)
INC BC
LD (IX-12+CHP.NNtSkp),A
JR PD_LP2
PD_ENV CALL SETENV
JR PD_LP2
PD_ORN CALL SETORN
JR PD_LOOP
PD_ESAM LD (IX-12+CHP.Env_En),A
LD (IX-12+CHP.PsInOr),A
CALL NZ,SETENV
JR PD_SAM_
PT3PD LD A,(IX-12+CHP.Note)
LD (PrNote+1),A
LD L,(IX-12+CHP.CrTnSl)
LD H,(IX-12+CHP.CrTnSl+1)
LD (PrSlide+1),HL
PD_LOOP LD DE,#2010
PD_LP2 LD A,(BC)
INC BC
ADD A,E
JR C,PD_OrSm
ADD A,D
JR Z,PD_FIN
JR C,PD_SAM
ADD A,E
JR Z,PD_REL
JR C,PD_VOL
ADD A,E
JR Z,PD_EOff
JR C,PD_SorE
ADD A,96
JR C,PD_NOTE
ADD A,E
JR C,PD_ORN
ADD A,D
JR C,PD_NOIS
ADD A,E
JR C,PD_ESAM
ADD A,A
LD E,A
LD HL,#ffff&(SPCCOMS+#FF20-#2000)
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
PUSH DE
JR PD_LOOP
PD_NOIS LD (IY-100+VRS.Ns_Base),A
JR PD_LP2
PD_REL RES 0,(IX-12+CHP.Flags)
JR PD_RES
PD_NOTE LD (IX-12+CHP.Note),A
SET 0,(IX-12+CHP.Flags)
XOR A
PD_RES LD (PDSP_+1),SP
LD SP,IX
LD H,A
LD L,A
PUSH HL
PUSH HL
PUSH HL
PUSH HL
PUSH HL
PUSH HL
PDSP_ LD SP,#3131
PD_FIN LD A,(IX-12+CHP.NNtSkp)
LD (IX-12+CHP.NtSkCn),A
RET
C_PORTM LD A,(BC)
INC BC
;SKIP PRECALCULATED TONE DELTA (BECAUSE
;CANNOT BE RIGHT AFTER PT3 COMPILATION)
INC BC
INC BC
EX AF,AF'
LD A,(BC) ;SIGNED TONE STEP
INC BC
LD (LoStep),A
LD A,(BC)
INC BC
AND A
EX AF,AF'
LD L,(IX-12+CHP.CrTnSl)
LD H,(IX-12+CHP.CrTnSl+1)
;Set portamento variables
;A - Delay; A' - Hi(Step); ZF' - (A'=0); HL - CrTnSl
SETPORT RES 2,(IX-12+CHP.Flags)
LD (IX-12+CHP.TnSlDl),A
LD (IX-12+CHP.TSlCnt),A
PUSH HL
LD DE,NT_
LD A,(IX-12+CHP.Note)
LD (IX-12+CHP.SlToNt),A
ADD A,A
LD L,A
LD H,0
ADD HL,DE
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
PUSH HL
PrNote LD A,#3E
LD (IX-12+CHP.Note),A
ADD A,A
LD L,A
LD H,0
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
POP HL
SBC HL,DE
LD (IX-12+CHP.TnDelt),L
LD (IX-12+CHP.TnDelt+1),H
POP DE
Version EQU $+1
LD A,#3E
CP 6
JR C,OLDPRTM ;Old 3xxx for PT v3.5-
PrSlide LD DE,#1111
LD (IX-12+CHP.CrTnSl),E
LD (IX-12+CHP.CrTnSl+1),D
LoStep EQU $+1
OLDPRTM LD A,#3E
EX AF,AF'
JR Z,NOSIG
EX DE,HL
NOSIG SBC HL,DE
JP P,SET_STP
CPL
EX AF,AF'
NEG
EX AF,AF'
SET_STP LD (IX-12+CHP.TSlStp+1),A
EX AF,AF'
LD (IX-12+CHP.TSlStp),A
LD (IX-12+CHP.COnOff),0
RET
C_GLISS SET 2,(IX-12+CHP.Flags)
LD A,(BC)
INC BC
LD (IX-12+CHP.TnSlDl),A
AND A
JR NZ,GL36
LD A,(Version) ;AlCo PT3.7+
CP 7
SBC A,A
INC A
GL36 LD (IX-12+CHP.TSlCnt),A
LD A,(BC)
INC BC
EX AF,AF'
LD A,(BC)
INC BC
JR SET_STP
C_SMPOS LD A,(BC)
INC BC
LD (IX-12+CHP.PsInSm),A
RET
C_ORPOS LD A,(BC)
INC BC
LD (IX-12+CHP.PsInOr),A
RET
C_VIBRT LD A,(BC)
INC BC
LD (IX-12+CHP.OnOffD),A
LD (IX-12+CHP.COnOff),A
LD A,(BC)
INC BC
LD (IX-12+CHP.OffOnD),A
XOR A
LD (IX-12+CHP.TSlCnt),A
LD (IX-12+CHP.CrTnSl),A
LD (IX-12+CHP.CrTnSl+1),A
RET
C_ENGLS LD A,(BC)
INC BC
LD (IY-100+VRS.Env_Del),A
LD (IY-100+VRS.CurEDel),A
LD A,(BC)
INC BC
LD L,A
LD A,(BC)
INC BC
LD H,A
LD (IY-100+VRS.ESldAdd),L
LD (IY-100+VRS.ESldAdd+1),H
RET
C_DELAY LD A,(BC)
INC BC
LD (IY-100+VRS.Delay),A
LD HL,VARS2+VRS.ModNum ;if AlCo_TS
BIT 1,(HL)
RET Z
LD (VARS1+VRS.Delay),A
LD (VARS1+VRS.DelyCnt),A
LD (VARS2+VRS.Delay),A
RET
SETENV LD (IX-12+CHP.Env_En),E
LD (IY-100+VRS.AYREGS+EnvTp),A
LD A,(BC)
INC BC
LD H,A
LD A,(BC)
INC BC
LD L,A
CALL SETENBS
XOR A
LD (IX-12+CHP.PsInOr),A
LD (IY-100+VRS.CurEDel),A
LD H,A
LD L,A
JP SETESLD
SETORN ADD A,A
LD E,A
LD D,0
LD (IX-12+CHP.PsInOr),D
LD L,(IY-100+VRS.OrnPtrs)
LD H,(IY-100+VRS.OrnPtrs+1)
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
LD L,(IY-100+VRS.MODADDR)
LD H,(IY-100+VRS.MODADDR+1)
ADD HL,DE
LD (IX-12+CHP.OrnPtr),L
LD (IX-12+CHP.OrnPtr+1),H
C_NOP RET
SETSAM ADD A,A
LD E,A
LD D,0
LD L,(IY-100+VRS.SamPtrs);
LD H,(IY-100+VRS.SamPtrs+1);
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
LD L,(IY-100+VRS.MODADDR)
LD H,(IY-100+VRS.MODADDR+1)
ADD HL,DE
LD (IX-12+CHP.SamPtr),L
LD (IX-12+CHP.SamPtr+1),H
RET
;ALL 16 ADDRESSES TO PROTECT FROM BROKEN PT3 MODULES
SPCCOMS DW C_NOP
DW C_GLISS
DW C_PORTM
DW C_SMPOS
DW C_ORPOS
DW C_VIBRT
DW C_NOP
DW C_NOP
DW C_ENGLS
DW C_DELAY
DW C_NOP
DW C_NOP
DW C_NOP
DW C_NOP
DW C_NOP
DW C_NOP
CHREGS CALL GETIX
XOR A
LD (Ampl),A
BIT 0,(IX+CHP.Flags)
PUSH HL
JP Z,CH_EXIT
LD (CSP_+1),SP
LD L,(IX+CHP.OrnPtr)
LD H,(IX+CHP.OrnPtr+1)
LD SP,HL
POP DE
LD H,A
LD A,(IX+CHP.PsInOr)
LD L,A
ADD HL,SP
INC A
;PT2 PT3
OrnCP INC A ;CP E CP D
JR C,CH_ORPS
OrnLD DB 1 ;LD A,D LD A,E
CH_ORPS LD (IX+CHP.PsInOr),A
LD A,(IX+CHP.Note)
ADD A,(HL)
JP P,CH_NTP
XOR A
CH_NTP CP 96
JR C,CH_NOK
LD A,95
CH_NOK ADD A,A
EX AF,AF'
LD L,(IX+CHP.SamPtr)
LD H,(IX+CHP.SamPtr+1)
LD SP,HL
POP DE
LD H,0
LD A,(IX+CHP.PsInSm)
LD B,A
ADD A,A
SamClc2 ADD A,A ;or ADD A,B for PT2
LD L,A
ADD HL,SP
LD SP,HL
LD A,B
INC A
;PT2 PT3
SamCP INC A ;CP E CP D
JR C,CH_SMPS
SamLD DB 1 ;LD A,D LD A,E
CH_SMPS LD (IX+CHP.PsInSm),A
POP BC
POP HL
;Convert PT2 sample to PT3
;PT2 PT3
SamCnv POP HL ;BIT 2,C JR e_
POP HL
LD H,B
JR NZ,$+8
EX DE,HL
AND A
SBC HL,HL
SBC HL,DE
LD D,C
RR C
SBC A,A
CPL
AND #3E
RR C
RR B
AND C
LD C,A
LD A,B
RRA
RRA
RR D
RRA
AND #9F
LD B,A
e_ LD E,(IX+CHP.TnAcc)
LD D,(IX+CHP.TnAcc+1)
ADD HL,DE
BIT 6,B
JR Z,CH_NOAC
LD (IX+CHP.TnAcc),L
LD (IX+CHP.TnAcc+1),H
CH_NOAC EX DE,HL
EX AF,AF'
ADD A,NT_&#ff
LD L,A
ADC A,NT_/256
SUB L
LD H,A
LD SP,HL
POP HL
ADD HL,DE
LD E,(IX+CHP.CrTnSl)
LD D,(IX+CHP.CrTnSl+1)
ADD HL,DE
CSP_ LD SP,#3131
EX (SP),HL
XOR A
OR (IX+CHP.TSlCnt)
JR Z,CH_AMP
DEC (IX+CHP.TSlCnt)
JR NZ,CH_AMP
LD A,(IX+CHP.TnSlDl)
LD (IX+CHP.TSlCnt),A
LD L,(IX+CHP.TSlStp)
LD H,(IX+CHP.TSlStp+1)
LD A,H
ADD HL,DE
LD (IX+CHP.CrTnSl),L
LD (IX+CHP.CrTnSl+1),H
BIT 2,(IX+CHP.Flags)
JR NZ,CH_AMP
LD E,(IX+CHP.TnDelt)
LD D,(IX+CHP.TnDelt+1)
AND A
JR Z,CH_STPP
EX DE,HL
CH_STPP SBC HL,DE
JP M,CH_AMP
LD A,(IX+CHP.SlToNt)
LD (IX+CHP.Note),A
XOR A
LD (IX+CHP.TSlCnt),A
LD (IX+CHP.CrTnSl),A
LD (IX+CHP.CrTnSl+1),A
CH_AMP LD A,(IX+CHP.CrAmSl)
BIT 7,C
JR Z,CH_NOAM
BIT 6,C
JR Z,CH_AMIN
CP 15
JR Z,CH_NOAM
INC A
JR CH_SVAM
CH_AMIN CP -15
JR Z,CH_NOAM
DEC A
CH_SVAM LD (IX+CHP.CrAmSl),A
CH_NOAM LD L,A
LD A,B
AND 15
ADD A,L
JP P,CH_APOS
XOR A
CH_APOS CP 16
JR C,CH_VOL
LD A,15
CH_VOL OR (IX+CHP.Volume)
ADD A,VT_&#ff
LD L,A
ADC A,VT_/256
SUB L
LD H,A
LD A,(HL)
CH_ENV BIT 0,C
JR NZ,CH_NOEN
OR (IX+CHP.Env_En)
CH_NOEN LD (Ampl),A
BIT 7,B
LD A,C
JR Z,NO_ENSL
RLA
RLA
SRA A
SRA A
SRA A
ADD A,(IX+CHP.CrEnSl) ;SEE COMMENT BELOW
BIT 5,B
JR Z,NO_ENAC
LD (IX+CHP.CrEnSl),A
NO_ENAC ADD A,(IY-100+VRS.AddToEn) ;BUG IN PT3 - NEED WORD HERE
LD (IY-100+VRS.AddToEn),A
JR CH_MIX
NO_ENSL RRA
ADD A,(IX+CHP.CrNsSl)
LD (IY-100+VRS.AddToNs),A
BIT 5,B
JR Z,CH_MIX
LD (IX+CHP.CrNsSl),A
CH_MIX LD A,B
RRA
AND #48
CH_EXIT OR (IY-100+VRS.AYREGS+Mixer)
RRCA
LD (IY-100+VRS.AYREGS+Mixer),A
POP HL
XOR A
OR (IX+CHP.COnOff)
RET Z
DEC (IX+CHP.COnOff)
RET NZ
XOR (IX+CHP.Flags)
LD (IX+CHP.Flags),A
RRA
LD A,(IX+CHP.OnOffD)
JR C,CH_ONDL
LD A,(IX+CHP.OffOnD)
CH_ONDL LD (IX+CHP.COnOff),A
RET
PLAY_ XOR A
LD (IY-100+VRS.AddToEn),A
LD (IY-100+VRS.AYREGS+Mixer),A
DEC A
LD (IY-100+VRS.AYREGS+EnvTp),A
DEC (IY-100+VRS.DelyCnt)
JP NZ,PL2
DEC (IY-100+VRS.ChanA+CHP.NtSkCn)
JR NZ,PL1B
LD C,(IY-100+VRS.AdInPtA)
LD B,(IY-100+VRS.AdInPtA+1)
LD A,(BC)
AND A
JR NZ,PL1A
LD D,A
LD (IY-100+VRS.Ns_Base),A
LD L,(IY-100+VRS.CrPsPtr)
LD H,(IY-100+VRS.CrPsPtr+1)
INC HL
LD A,(HL)
INC A
JR NZ,PLNLP
IF LoopChecker
CALL CHECKLP
ENDIF
LD L,(IY-100+VRS.LPosPtr)
LD H,(IY-100+VRS.LPosPtr+1)
LD A,(HL)
INC A
PLNLP CALL SETCPPT
DEC A
BIT 1,(IY-100+VRS.ModNum)
JR Z,NoAlCo
TSSub EQU $+1
SUB #D6
CPL
NoAlCo
;PT2 PT3
PsCalc DEC A ;ADD A,A NOP
DEC A ;ADD A,(HL) NOP
ADD A,A
LD E,A
RL D
IF CurPosCounter
LD A,L
SUB (IY-100+VRS.PosSub)
LD (IY-100+VRS.CurPos),A
ENDIF
LD L,(IY-100+VRS.PatsPtr)
LD H,(IY-100+VRS.PatsPtr+1)
ADD HL,DE
LD E,(IY-100+VRS.MODADDR)
LD D,(IY-100+VRS.MODADDR+1)
LD (PSP_+1),SP
LD SP,HL
POP HL
ADD HL,DE
LD B,H
LD C,L
POP HL
ADD HL,DE
LD (IY-100+VRS.AdInPtB),L
LD (IY-100+VRS.AdInPtB+1),H
POP HL
ADD HL,DE
LD (IY-100+VRS.AdInPtC),L
LD (IY-100+VRS.AdInPtC+1),H
PSP_ LD SP,#3131
PL1A LD DE,VRS.ChanA+12-100
CALL PTDECOD
LD (IY-100+VRS.AdInPtA),C
LD (IY-100+VRS.AdInPtA+1),B
PL1B DEC (IY-100+VRS.ChanB+CHP.NtSkCn)
JR NZ,PL1C
LD DE,VRS.ChanB+12-100
LD C,(IY-100+VRS.AdInPtB)
LD B,(IY-100+VRS.AdInPtB+1)
CALL PTDECOD
LD (IY-100+VRS.AdInPtB),C
LD (IY-100+VRS.AdInPtB+1),B
PL1C DEC (IY-100+VRS.ChanC+CHP.NtSkCn)
JR NZ,PL1D
LD DE,VRS.ChanC+12-100
LD C,(IY-100+VRS.AdInPtC)
LD B,(IY-100+VRS.AdInPtC+1)
CALL PTDECOD
LD (IY-100+VRS.AdInPtC),C
LD (IY-100+VRS.AdInPtC+1),B
PL1D LD A,(IY-100+VRS.Delay)
LD (IY-100+VRS.DelyCnt),A
PL2 LD DE,VRS.ChanA-100
LD L,(IY-100+VRS.AYREGS+TonA)
LD H,(IY-100+VRS.AYREGS+TonA+1)
CALL CHREGS
LD (IY-100+VRS.AYREGS+TonA),L
LD (IY-100+VRS.AYREGS+TonA+1),H
Ampl EQU $+1
LD A,#3E
LD (IY-100+VRS.AYREGS+AmplA),A
LD DE,VRS.ChanB-100
LD L,(IY-100+VRS.AYREGS+TonB)
LD H,(IY-100+VRS.AYREGS+TonB+1)
CALL CHREGS
LD (IY-100+VRS.AYREGS+TonB),L
LD (IY-100+VRS.AYREGS+TonB+1),H
LD A,(Ampl)
LD (IY-100+VRS.AYREGS+AmplB),A
LD DE,VRS.ChanC-100
LD L,(IY-100+VRS.AYREGS+TonC)
LD H,(IY-100+VRS.AYREGS+TonC+1)
CALL CHREGS
LD (IY-100+VRS.AYREGS+TonC),L
LD (IY-100+VRS.AYREGS+TonC+1),H
LD A,(Ampl)
LD (IY-100+VRS.AYREGS+AmplC),A
LD A,(IY-100+VRS.Ns_Base)
ADD (IY-100+VRS.AddToNs)
LD (IY-100+VRS.AYREGS+Noise),A
LD A,(IY-100+VRS.AddToEn)
LD E,A
ADD A,A
SBC A,A
LD D,A
LD L,(IY-100+VRS.EnvBase)
LD H,(IY-100+VRS.EnvBase+1)
ADD HL,DE
LD E,(IY-100+VRS.CurESld)
LD D,(IY-100+VRS.CurESld+1)
ADD HL,DE
LD (IY-100+VRS.AYREGS+Env),L
LD (IY-100+VRS.AYREGS+Env+1),H
XOR A
OR (IY-100+VRS.CurEDel)
RET Z
DEC (IY-100+VRS.CurEDel)
RET NZ
LD A,(IY-100+VRS.Env_Del)
LD (IY-100+VRS.CurEDel),A
LD L,(IY-100+VRS.ESldAdd)
LD H,(IY-100+VRS.ESldAdd+1)
ADD HL,DE
JP SETESLD
PLAY LD IY,VARS1+100
CALL PLAY_
LD A,(is_ts)
AND A
JR Z,PL_nts
LD IY,VARS2+100
CALL PLAY_
PL_nts
IF Basic
LD IY,#5C3A
ENDIF
ROUT LD BC,#FFFD
LD A,(is_ts)
AND A
JR Z,r_nts ;keep old standard
OUT (C),B
r_nts EX AF,AF'
IF ACBBAC
LD IX,VARS1+VRS.AYREGS
ELSE
LD HL,VARS1+VRS.AYREGS
ENDIF
CALL ROUT_
EX AF,AF'
RET Z
LD B,D
CPL
OUT (C),A
IF ACBBAC
LD IX,VARS2+VRS.AYREGS
ELSE
LD HL,VARS2+VRS.AYREGS
ENDIF
ROUT_
IF ACBBAC
LD A,(SETUP)
AND 12
JR Z,ABC
ADD A,CHTABLE
LD E,A
ADC A,CHTABLE/256
SUB E
LD D,A
LD B,0
PUSH IX
POP HL
LD A,(DE)
INC DE
LD C,A
ADD HL,BC
LD A,(IX+TonB)
LD C,(HL)
LD (IX+TonB),C
LD (HL),A
INC HL
LD A,(IX+TonB+1)
LD C,(HL)
LD (IX+TonB+1),C
LD (HL),A
LD A,(DE)
INC DE
LD C,A
ADD HL,BC
LD A,(IX+AmplB)
LD C,(HL)
LD (IX+AmplB),C
LD (HL),A
LD A,(DE)
INC DE
LD (RxCA1),A
XOR 8
LD (RxCA2),A
LD A,(DE)
AND (IX+Mixer)
LD E,A
LD A,(IX+Mixer)
RxCA1 DB #E6
AND %010010
OR E
LD E,A
LD A,(IX+Mixer)
AND %010010
RxCA2 OR E
OR E
LD (IX+Mixer),A
ABC
ENDIF
XOR A
LD DE,#FFBF
IF ACBBAC
LD BC,#FFFD
PUSH IX
POP HL
ENDIF
LOUT OUT (C),A
LD B,E
OUTI
LD B,D
INC A
CP 13
JR NZ,LOUT
OUT (C),A
LD A,(HL)
AND A
RET M
LD B,E
OUT (C),A
RET
IF ACBBAC
CHTABLE EQU $-4
DB 4,5,15,%001001,0,7,7,%100100
ENDIF
NT_DATA DB (T_NEW_0-T1_)*2
DB TCNEW_0-T_
DB (T_OLD_0-T1_)*2+1
DB TCOLD_0-T_
DB (T_NEW_1-T1_)*2+1
DB TCNEW_1-T_
DB (T_OLD_1-T1_)*2+1
DB TCOLD_1-T_
DB (T_NEW_2-T1_)*2
DB TCNEW_2-T_
DB (T_OLD_2-T1_)*2
DB TCOLD_2-T_
DB (T_NEW_3-T1_)*2
DB TCNEW_3-T_
DB (T_OLD_3-T1_)*2
DB TCOLD_3-T_
T_
TCOLD_0 DB #00+1,#04+1,#08+1,#0A+1,#0C+1,#0E+1,#12+1,#14+1
DB #18+1,#24+1,#3C+1,0
TCOLD_1 DB #5C+1,0
TCOLD_2 DB #30+1,#36+1,#4C+1,#52+1,#5E+1,#70+1,#82,#8C,#9C
DB #9E,#A0,#A6,#A8,#AA,#AC,#AE,#AE,0
TCNEW_3 DB #56+1
TCOLD_3 DB #1E+1,#22+1,#24+1,#28+1,#2C+1,#2E+1,#32+1,#BE+1,0
TCNEW_0 DB #1C+1,#20+1,#22+1,#26+1,#2A+1,#2C+1,#30+1,#54+1
DB #BC+1,#BE+1,0
TCNEW_1 EQU TCOLD_1
TCNEW_2 DB #1A+1,#20+1,#24+1,#28+1,#2A+1,#3A+1,#4C+1,#5E+1
DB #BA+1,#BC+1,#BE+1,0
PT3EMPTYORN EQU $-1
DB 1,0
;first 12 values of tone tables (packed)
T_PACK DB #06EC*2/256,(#06EC*2)&#ff
DB #0755-#06EC
DB #07C5-#0755
DB #083B-#07C5
DB #08B8-#083B
DB #093D-#08B8
DB #09CA-#093D
DB #0A5F-#09CA
DB #0AFC-#0A5F
DB #0BA4-#0AFC
DB #0C55-#0BA4
DB #0D10-#0C55
DB #066D*2/256,(#066D*2)&#ff
DB #06CF-#066D
DB #0737-#06CF
DB #07A4-#0737
DB #0819-#07A4
DB #0894-#0819
DB #0917-#0894
DB #09A1-#0917
DB #0A33-#09A1
DB #0ACF-#0A33
DB #0B73-#0ACF
DB #0C22-#0B73
DB #0CDA-#0C22
DB #0704*2/256,(#0704*2)&#ff
DB #076E-#0704
DB #07E0-#076E
DB #0858-#07E0
DB #08D6-#0858
DB #095C-#08D6
DB #09EC-#095C
DB #0A82-#09EC
DB #0B22-#0A82
DB #0BCC-#0B22
DB #0C80-#0BCC
DB #0D3E-#0C80
DB #07E0*2/256,(#07E0*2)&#ff
DB #0858-#07E0
DB #08E0-#0858
DB #0960-#08E0
DB #09F0-#0960
DB #0A88-#09F0
DB #0B28-#0A88
DB #0BD8-#0B28
DB #0C80-#0BD8
DB #0D60-#0C80
DB #0E10-#0D60
DB #0EF8-#0E10
;vars from here can be stripped
;you can move VARS to any other address
VARS
is_ts DB 0
;ChannelsVars
STRUCT CHP
;reset group
PsInOr DB 0
PsInSm DB 0
CrAmSl DB 0
CrNsSl DB 0
CrEnSl DB 0
TSlCnt DB 0
CrTnSl DW 0
TnAcc DW 0
COnOff DB 0
;reset group
OnOffD DB 0
;IX for PTDECOD here (+12)
OffOnD DB 0
OrnPtr DW 0
SamPtr DW 0
NNtSkp DB 0
Note DB 0
SlToNt DB 0
Env_En DB 0
Flags DB 0
;Enabled - 0, SimpleGliss - 2
TnSlDl DB 0
TSlStp DW 0
TnDelt DW 0
NtSkCn DB 0
Volume DB 0
ENDS
STRUCT VRS
;IF not works in STRUCT in SjASM :(
; IF CurPosCounter
CurPos DB 0
PosSub DB 0
; ENDIF
ModNum DB 0 ;bit0: ChipNum
;bit1: 1-reversed patterns order (AlCo TS)
ChanA DS CHP
ChanB DS CHP
ChanC DS CHP
;GlobalVars
MODADDR DW 0
OrnPtrs DW 0
SamPtrs DW 0
PatsPtr DW 0
AdInPtA DW 0
AdInPtB DW 0
AdInPtC DW 0
CrPsPtr DW 0
LPosPtr DW 0
Delay DB 0
DelyCnt DB 0
ESldAdd DW 0
CurESld DW 0
Env_Del DB 0
CurEDel DB 0
Ns_Base DB 0
AddToNs DB 0
AddToEn DB 0
EnvBase DW 0
AYREGS DS 14
ENDS
VARS1 DS VRS
VARS2 DS VRS
VT_ EQU $-16
DS 256-16 ;CreatedVolumeTableAddress
T1_ EQU VT_+16 ;Tone tables data depacked here
T_OLD_1 EQU T1_
T_OLD_2 EQU T_OLD_1+24
T_OLD_3 EQU T_OLD_2+24
T_OLD_0 EQU T_OLD_3+2
T_NEW_0 EQU T_OLD_0
T_NEW_1 EQU T_OLD_1
T_NEW_2 EQU T_NEW_0+24
T_NEW_3 EQU T_OLD_3
PT2EMPTYORN EQU VT_+31 ;1,0,0 sequence
NT_ DS 192 ;CreatedNoteTableAddress
VAR0END EQU VT_+16 ;INIT zeroes from VARS to VAR0END-1
VARSEND EQU $
;MDLADDR EQU $
;Release 0 steps:
;04/21/2007
;Works start (PTxPlay adaptation); first beta.
;04/22/2007
;Job finished; beta-testing.
;04/23/2007
;PT v3.7 TS mode corrected (after AlCo remarks).
;04/29/2007
;Added 1.XX and 2.XX special commands interpretation for PT3
;modules of v3.7+.
;Size (minimal build for ZX Spectrum):
;Code block #908 bytes
;Variables #2BF bytes (can be stripped)
;Total size #908+#2BF=#BC7 (3015) bytes