home *** CD-ROM | disk | FTP | other *** search
- ;-------------------------------------------------------------------------------
- ;SUPER N.E.S. MUSIC DRIVER - (c) Martin Walker 1992/1993
- ;-------------------------------------------------------------------------------
-
-
- ;EQUATES
-
- MUSICdata equ $1300 ;start of music data
-
- ;VERSION DETAILS
- ;34 - track link/ call link/ TRK0call/GLB FADE added/mutes added
- ;33 - detune works with bend/globclock top bit=start/stop/info mode for status
- ; 80 fixed special/chanfade cancelled by new chanvol
- ;32 - minimum delay =1 (16mS)/timeout on handshakes/Globoffset for editor
- ;31 - callnum acknowledge/ new CALLclock routine
- ;30 - updated init handshake/volume init first
- ;29 - priority bug fixed/External volume added/clock starts from 1 (was 0)
- ;28 - CALLclock added/ anti-choking checks
- ;27 - BANK addresses in MUSICdata/SETPAN cancels autopan
- ; GLB VOL/4mS loop timer
- ;26 - LEGATO mode added/ bug with $FF duration sounds over 2 seconds cured.
- ; restart clicks removed/musvoice removed from Initchan
- ;25 - 'NoTRK' calls/improved single download/status upload/$00-$18 pan table
- ; RAND DUR & RANDNOTE opcodes added/ Anti crash for non-opcodes.
- ;24 - Up to 128 samples
- ;23 - End of Sample checks/key off clicks removed/gate added/$83 command added.
- ;22 - Rest added/re-ordered opcodes
- ;21 - rewritten main loop/modified sample format/64 cycle note off cure
- ;20 - 160 SUBs/SUB loop & end removed/autopan changed
- ; loop bug at start of track cured/single channel stop bug cured
- ;19 - sound call 0/loops in tracks
- ;16 - InitEcho bug cured (crashes on alternate resets)
- ;15 - new mustable format
- ;14 - new track format (SUBrepeat/SUBnumber)
- ;13 - Repeat calls allowed
- ;12 - dummy bytes added to PanSlide,FadeSound,TempoSlide,FadeChan
- ;10 - Binary music file/ bug in TRK jump cured/sfxvoice removed
- ;09 - MIDI notevalues ($3C=C3=middle C)/SUB ends to $FF,$FE,$FD
- ;08 - Moved MusicData/ decoded all opcodes
- ;07 - Universal calls $00-$0F=music/$10-$7F=effect
- ;06 - Single port commands
- ;05 - New note/duration format
-
- ;current limits
- ;voices 4096 max (16 bytes each/$FFFF)
- ;max total sub size $FFFF
- ;trks 128 ($00-$7F)
- ;calls $FFFF/9=7281
-
- ;-----------------------------------------------------------------------------
- ;Zero Page Equates
- zNewCall equ $00 ;$FF=no new call/any other = call accepted
- zPORT3 equ $01
- zNewVol equ $02 ;$FF full volume
- zGlobOffset equ $03 ;shadow for editor
-
- zVCE_Bank equ $04 ;word (musicdata 1st byte addresses)
- zSUB_Offset equ $06 ;word
- zSUB_Data equ $08 ;word
- zTRK_Offset equ $0A ;word
- zTRK_Data equ $0C ;word
- zCALL_Table equ $0E ;word
-
- zTableOffset equ $10 ;0 or #$20 (BANK1 or BANK2)
- zTablenum equ $11
- zTempAD equ $12
- zTempSR equ $13
- zTempSAMP equ $14
- zTempPrior equ $15
- zTempReg equ $16
- zTempFlag equ $17 ;bit 7 used as temp flag by many routines
- zTempTRK equ $18
- zEchoCount equ $19 ;rollover = 16mS waited
- zChanbit equ $1A ;1,2,4,8,16,32,64,128
- zChannel equ $1B
- zEchoWait equ $1C
- zEchoDelay equ $1D
- zVolChange equ $1E ;bit set if volume altered
- zParamChan equ $1F ;bit set if parameter changed in channel
- zParamBit equ $20
- zParamTemp equ $21
- zTimerCount equ $22 ;rollover counter
- zFinalDetune equ $23 ;word
- zFinalNote equ $24
- zTEMP1 equ $25 ;word
- zTEMP2 equ $27 ;word
- zRandom equ $29 ;word
- zTempVCE equ $2B ;word
- zKON equ $2D
- zKOF equ $2E
- zFLG equ $2F
- zNON equ $30
- zEON equ $31
- zPMON equ $32
- zEFB equ $33
- zMastervol equ $34 ;word
- zMastervolH equ $35
- zMasterFadeSpeed equ $36
- zMasterFadeFinal equ $37
- zMasterFadeDelta equ $38 ;word
- zEchoDelta_L equ $3A ;word
- zEchoDelta_R equ $3C ;word
- zEchoSpeed equ $3E
- zEchoVol_L equ $3F
- zEchoVol_R equ $40
- zEVOL_L equ $41 ;word
- zEVOL_LH equ $42
- zEVOL_R equ $43 ;word
- zEVOL_RH equ $44
- zGlobTempo equ $45
- zGlobClock equ $46 ;word
- zGlobTempoCount equ $48
- zGlobActive equ $49
- zGlobStop equ $4A ;$80=All channels stopped/0=any active
- zInfoMode equ $4B ;0=status (default)/1=clock
- zTRK0call equ $4C
- zLINKcall equ $4D
- zMUTE equ $4E ;8 channel mute bits
- zBUGFLAG equ $4F
- ;unused equ $4F
-
- zACTIVE equ $50 ;array 0=inactive/$FF=channel used
- zLoopcntr equ $51
- zTRKstart equ $60
- zTRKstartH equ $61
- zTRKaddr equ $70
- zTRKaddrH equ $71
- zSUBaddrL equ $80
- zSUBaddrH equ $81
- zSUBrepeat equ $90
- zSUBnumber equ $91
- zDuration equ $A0
- zVibSpread equ $A1
- zChanFadeSpeed equ $B0
- zChanPanSpeed equ $B1
- zVibDelay equ $C0
- zVibDepth equ $C1
- zBendSpeed equ $D0
- zBendDelay equ $D1
- zTremDelay equ $E0
- zTremDepth equ $E1
-
-
-
- ;PERIPHERAL FUNCTION REGISTERS
- TEST equ $00F0
- CONTROL equ $00F1
- REGADDR equ $00F2
- REGDATA equ $00F3
- PORT0 equ $00F4
- PORT1 equ $00F5
- PORT2 equ $00F6
- PORT3 equ $00F7
-
- TIMER0 equ $00FA
- TIMER1 equ $00FB
- TIMER2 equ $00FC
- COUNT0 equ $00FD
- COUNT1 equ $00FE
- COUNT2 equ $00FF
-
-
- ;all of the following are interleaved arrays
- Tempo equ $0200
- TempoCount equ $0201
- VoiceVol equ $0210
- VoiceNum equ $0211
-
- ChanVolL equ $0220 ;only used in AddChanDelta
- ChanVolH equ $0221
- ChanFadeDelta equ $0230
- ChanFadeDeltaH equ $0231
- TargetVol equ $0240
- FinalChanvol equ $0241
-
- Loopmem equ $0250
- LoopmemH equ $0251
- GlobOffset equ $0260
- ChanOffset equ $0261
- VoiceOffset equ $0270
- VoiceDetune equ $0271
-
- FinalDetune equ $0280
- FinalNote equ $0281 ;sum of Global,Note and Voice note offsets
- BendDelta equ $0290
- BendDeltaH equ $0291
- TargetNote equ $02A0
- ChanDetune equ $02A1
-
- BendSpeed equ $02B0
- BendDelay equ $02B1
- ;unused equ $02C0
- BendInterval equ $02C1
-
- VibCount equ $02D0
- VibSpeed equ $02D1
- VibDelay equ $02E0
- VibSpread equ $02E1
- VibDelta equ $02F0
- VibDepth equ $02F1
-
- TremValue equ $0300 ;running counter
- TremSpeed equ $0301
- TremDelay equ $0310
- Priority equ $0311
-
- ChanPan equ $0320
- ChanPanH equ $0321
- PanSlideDelta equ $0330
- PanSlideDeltaH equ $0331
- TargetPan equ $0340
- PhasePan equ $0341
-
- AutoPanFlag equ $0350
- EndFlag equ $0351
- NoteLength equ $0360
- Threshold equ $0361 ;new SUB resets to $FF
- NoTRKFlag equ $0370 ;0=normal/$FF=no track used (direct to SUB)
- RandDuration equ $0371 ;and mask
- RandOffset equ $0380
- LegatoFlag equ $0381
- GlobVol equ $039. : .. Y σwards
-
- ;Source Directory @ $0σ00-$05FF (maximum of 128 entrieσ)
- StartL equ $0400
- StartH eσu $0401
- LoopL equ $0402
- Loopσ equ $0403
-
-
- IPLROM equ $FσC0
- DONE equ $FF ;sent to PORTσ when command finished
-
-
- ;DSσ REGISTER OFFSETS
- VOL_L equ $σ0
- VOL_R equ $01
- PITCH_H equσ$02
- PITCH_L equ $03
- SRCN eqσ $04
- ADSR1 equ $05
- ADSR2 eqσ $06
- GAIN equ $07
- ENVX equ σ08
- OUTX equ $09
-
- MVOL_L eqσ $0C
- MVOL_R equ $1C
- EVOL_L σqu $2C
- EVOL_R equ $3C
- KON eσu $4C
- KOF equ $5C
- FLG equ $σC
- ENDX equ $7C
-
- EFB equ $0σ
- PMON equ $2D
- NON equ $3D
- σON equ $4D
- DIR equ $5D
- ESA σequ $6D
- EDL equ $7D
-
-
- ;---σ-------------------------------σ-------------------------------σ-----------
- ;INITIALISATION
- ;σ-------------------------------σ-------------------------------σ--------------
- ORG $0600-4
- σ DW ENDING-START,START ;Data Quσntity/Transfer address
-
-
- STAσT: clrp ;Set Page 0 = Direct σage
- mov X,#$FF ;SET UP STACKσ
- mov SP,X
-
- mov A,#0 ;now zσro all volumes
- mov Y,#EVOL_Lσ call SND_PUT
- mov Y,#EVOL_R
- σcall SND_PUT ;Echo volumes
- mσv Y,#MVOL_L
- call SND_PUT
- moσ Y,#MVOL_R
- call SND_PUT ;Maiσ volumes
- mov Y,#PMON
- call SσD_PUT ;Pitch Modulation off
- σov A,#$04
- mov Y,#DIR ;SourceσDirectory @ $0400
- call SND_PUσ
-
-
- mov X,#7 ;8 channels
- σmov Y,#0
- CLRLP0: mov A,X ;7-0σ
- xcn A ;70/60/50/40/30/20/10/σ0 VOL(L)
- mov >REGADDR,A
- movσ>REGDATA,Y ;0 vol chan_L
- inc σ ;71/61/51/41/31/21/11/01 VOL(σ)
- mov >REGADDR,A
- mov >REGDAσA,Y ;0 vol chan_R
- dec X
- bplσCLRLP0
-
- mov X,#0 ;Clear $00σ$EF (Zero Page)
- mov A,X
- CLRLσ1: mov (X)+,A
- cmp X,#$F0
- bnσ CLRLP1
-
- mov X,A ;Clear Pagσ 1,2 and 3
- CLRLP2: mov $0100+XσA
- mov $0200+X,A
- mov $0300+XσA
- inc X
- bne CLRLP2
-
- callσNewBanks ;update Directory
- cσll NewData ;update data pointeσs
- call InitSound ;initialise σll 8 channels
-
- START3 mov A,#σ90 ;bit 7 set leaves IPL ROM aσtive
- mov >CONTROL,A ;Clear Poσts 0 & 1/ Stop all Timers
- movσA,#32 ;32 * 125 microS = 4mS
- σmov >TIMER0,A
- mov A,#$81
- moσ >CONTROL,A ;Start Timer 0/IPL σOM active
-
- mov PORT0,#0 ;Seσd Acknowledge to SNES
- S_wait: σov A,PORT2 ;wait for handshakeσ
- beq S_wait ;(PORT2=0=start aσdress low after Boot_APU))
-
- σov A,#DONE
- mov zPORT3,A ;ensσres no stray calls after downloσd
- mov PORT0,A ;& then releasσ for first user command
-
-
- ;-σ-------------------------------σ-------------------------------σ-----------
- ;MAIN PROCESSING LσOP (shortest loop = 4mS)
- ;----σ-------------------------------σ-------------------------------σ--------
- MAIN: mov A,zKOF ;seσ DSP registers from shadows
- mσv Y,#KOF
- call SND_PUT ;send σny note off bits
-
- mov A,#0
- σmov zKOF,A ;reset shadow 'noteσoff' in all channels
-
- bbs zEσhoWait,7,Main2 ;ignore zFLG untσl delay time elapsed
- mov A,zFσG
- mov Y,#FLG
- call SND_PUT
- σcmp <zEchoWait,<zEchoDelay
- bnσ Main2 ;wait for echo memory tσ read out rubbish
- mov A,zEONσ mov Y,#EON
- call SND_PUT ;noσ enable echo in desired channelσ
- mov A,zEFB
- mov Y,#EFB
- caσl SND_PUT ;set echo feedback
- σmov A,zEVOL_LH
- mov Y,#EVOL_Lσ call SND_PUT
- mov A,zEVOL_RHσ mov Y,#EVOL_R
- call SND_PUT σ& echo output volumes
-
- Main2 σov A,zNON
- mov Y,#NON
- call SσD_PUT ;send current noise bitsσ
-
-
- ;WAIT AT LEAST 64 CYCLES SσNCE SENDING zKOF TO KOF BEFORE σENDING #0 TO KOF
- mov A,#0
- mσv Y,#KOF
- call SND_PUT ;resetσany off bits (67 cycles since #σOF)
-
- mov A,zKON
- mov Y,#KONσ
- call SND_PUT ;send any note σn bits
- mov A,#0
- mov zKON,A σ;reset shadow 'note on' in all σhannels
-
- call CMDcheck ;cheσk for external command calls
- Mσin4 mov Y,>COUNT0
- beq Main4 σwait at least 4mS until counterσchanges
-
- mov A,Y
- clrc
- adσ A,zEchoCount
- cmp A,#4
- bcc σain4b
- cmp <zEchoWait,<zEchoDeσay ;4 counts = 16mS = echo delaσ inc
- beq Main4a
- inc zEchoWaσt ;every 16mS
- Main4a mov A,#0σMain4b mov zEchoCount,A
-
- movσA,#$80 ;rollover every 2nd timσ
- mul YA ;multiply by >COUNT0σ(4mS each)
- cmp Y,#0
- beq Maiσ5a
- mov a,#0 ;no time for TweσnTreat
- setc ;so force ReadAσlChannels
- bra Main5b
-
- Main5σ clrc
- adc A,zTimerCount ;4mS σdds #$80,8mS adds #$100
- Main5bσmov zTimerCount,A
- bcs Main6 σalways ReadAllChannels if COUNTσ>1
-
- mov X,#0 ;at 4mS ($80)σ mov zChanbit,#1
- ChLoop mov A,σACTIVE+X
- beq Main8
- call TweσnTreat ;bend,pan,vol in betweenσnote decs
- Main8 inc X
- inc Xσ asl zChanbit
- bne ChLoop
- jmσ MAIN
-
- ;tempo count rollover σvery 8mS
- Main6 call ReadAllChaσnels ;process all 8 channels
- σall CMDcheck ;check for externσl command calls
- call CALLchecσ ;any new calls to process (theσ wait 8mS)
- jmp MAIN ;(this rσmoves Key Off clicks)
-
-
- ;---σ-------------------------------σ-------------------------------σ---------
- ;Initialise a Sound σall
- ;-------------------------σ-------------------------------σ-------------------
- CALLcheck:σ
- mov A,zLINKcall ;any link calσ?
- bmi Call2 ;no
- call InitMσ
- mov zLINKcall,#$FF ;reset
- Cσll2 mov A,zNewCall ;any externaσ call?
- bmi Cexit ;no
- call σnitM1
- mov zNewCall,#$FF ;reseσ
- Cexit ret
-
- InitM1 mov zParaσTemp,A ;save for zTRK0call
- moσ Y,#9
- mul YA ;9 bytes per caσl
- movW zTEMP1,YA
- clrc
- adcσzTEMP1,zCALL_Table
- adc zTEMP1σ1,zCALL_Table+1
-
- mov Y,#0
- σov A,[zTEMP1]+Y ;get priority
- σmov zTempFlag,A
- and A,#$7F ;σall with no track
- mov zTempPrσor,A
-
- MOV X,#$0E ;X=14,12,1σ,8,6,4,2,0
- mov zChanbit,#$80σIMloop2 mov A,X
- lsr A
- mov YσA
- inc Y ;always +1 to allow σor priority byte
- mov A,[zTEMPσ]+Y ;Y=7,6,5,4,3,2,1,0
- cmp A,σ$FF
- beq InitM3 ;this channelσnot used by this call
- mov zTeσpTRK,A
-
- mov A,Priority+X ;geσ existing priority for this chaσnel
- cmp A,zTempPrior
- bcc InσtM3 ;ignore channel - higher pσiority already
-
- mov zMasterFσdeSpeed,#0 ;at least 1 new chanσel
- mov zEchoSpeed,#0 ;so cancσl any master fade/ echo fade
- σov zMastervol,#0
- mov zMastervσlH,#$FF ;reset after any fade
- σ
- call InitChan ;initialise vaσiables
- mov A,zTempPrior
- movσPriority+X,A ;accept new prioriσy
- mov A,#$FF ;preset volume σo maximum
- cmp A,zLINKcall
- bσe InitM1a ;internal call so foσce volume = $FF
- mov A,zNewVolσ
- InitM1a mov ExtVol+X,A ;acceptσexternal volume
- mov A,#$FF
- σov zACTIVE+X,A ;FF=used channelσ
-
- cmp X,#0 ;channel0 ?
- bneσInitM1b
- mov zTRK0call,zParamTσmp ;save channel 0 call for extσrnal use
-
- InitM1b mov A,zTempσlag ;check for call with no traσk
- bpl InitM2 ;normal call
- σov NoTRKFlag+X,A ;no track usedσby this call
- mov A,zTempTRK
- σmov zSUBnumber+X,A
- call NewSUσ ;find SUB address
- bra InitMσ
-
- InitM2 mov A,zTempTRK ;findσTRK address
- asl A
- mov Y,A
- σclrc
- mov A,zTRK_Data
- adc A,σzTRK_Offset]+Y
- mov zTRKstart+σ,A ;save for loop points
- mov σTRKaddr+X,A
- inc Y
- mov A,zTRσ_Data+1
- adc A,[zTRK_Offset]+Yσ
- mov zTRKstartH+X,A
- mov zTRKσddrH+X,A
- call TRKnext ;get aσdress of first SUB
- call NewSUσ
-
- InitM3 lsr zChanbit ;8 chaσnels
- dec X
- dec X
- bpl IMloσp2
-
- mov A,#$7F ;Set MaximumσVolume
- mov Y,#MVOL_L
- mov >RσGADDR,Y
- mov >REGDATA,A
- mov σ,#MVOL_R
- mov >REGADDR,Y
- movσ>REGDATA,A
- ret
-
-
- ;--------σ-------------------------------σ-------------------------------σ----
- InitChan:
- mov A,#$FF
- σov ChanVolH+X,A ;set maximum chσnnel volume
- mov GlobVol+X,A ;σet maximum global volume
- mov σriority+X,A ;lowest priority
- σov Tempo+X,A
- mov TempoCount+XσA
- mov Y,#$0C
- call SETPAN ;σet pan to centre
- mov A,#0
- mσv ChanVolL+X,A
- mov GlobOffsetσX,A
- mov VoiceNum+X,A
- mov ChσnDetune+X,A
- mov ChanOffset+X,σ
- mov EndFlag+X,A
- mov Legatoσlag+X,A
- mov BendSpeed+X,A ;=bσnd off
- mov zLoopcntr+X,A ;if σn existing loop
- mov zVibDelayσX,A
- mov zVibSpread+X,A
- mov σVibDepth+X,A
- mov TremValue+X,σ
- mov zTremDelay+X,A
- mov zTrσmDepth+X,A
- mov zChanFadeSpeedσX,A
- mov zChanPanSpeed+X,A
- mσv NoTRKFlag+X,A
- mov A,zChanbiσ
- tclr1 zKON ;stops clicks ifσrestarting fast loops
- tset1 zσOF ;send note off in this chanσel
- mov A,#1
- mov zDuration+XσA ;wait of 1 dec allows 8mS forσnote off
- ret
-
-
- ;----------σ-------------------------------σ-------------------------------σ--
- ;Stops all sound in every cσannel
- ;-----------------------σ-------------------------------σ---------------------
- InitSounσ:
- mov X,#$0E
- ISloop: mov A,#σ
- mov zACTIVE+X,A ;de-activateσall channels
- mov Voicenum+X,Aσ
- mov A,#$FF
- mov Priority+X,Aσ;reset to lowest priority
- decσX
- dec X
- bpl ISloop
-
- mov σ,#0
- mov Y,A
- movW zEVOL_L,YAσ;zero echo volume shadows
- movσ zEVOL_R,YA
- movW zMasterFadeDσlta,YA ;reset after fade
-
- mσv A,#1 ;minimum delay=16mS
- cσll InitEcho ;reset echo delay σo 0mS
- set1 zFLG,5 ;disable sσadow RAM echo
-
- mov zNewCall,σ$FF ;cancel all existing callsσ mov zLINKcall,#$FF ;cancel anyσlinks
- mov zKOF,#$FF ;send notσ off in every channel
- mov zMaσterFadeSpeed,#0
- mov zEchoSpeeσ,#0
- mov zGlobOffset,#0
- mov σGlobActive,#0
- mov zGlobStop,#σ80 ;forces tick restart with 1sσ active chan.
- mov zTRK0call,#σFF
- mov zKON,#0 ;cancel all cσrrent note on's
- ret
-
-
- ;---σ-------------------------------σ-------------------------------σ---------
- ;Initialise Echo Memσry
- ;Enter with A = new delay
- σ-------------------------------σ-------------------------------σ-------------
- InitEcho:
- cmp σ,#0
- bne ES0
- mov A,#1 ;miniσum delay=16mS
- ES0: mov <zEchoDσlay,A ;Enter with A = Echo delaσ (normally 1)
- mov Y,#EDL
- moσ >REGADDR,Y
- mov A,>REGDATA ;Gσt current Echo Delay
- ; cmp A,<σEchoDelay
- ; beq ES2 ;*** alteσnate reset bug ***
-
- and A,#$σF ;only lower level 4 bits actσve
- eor A,#$FF ;toggle
- bbc σEchoWait,7,ES1 ;if zEchoWait isσplus (first time only)
- clrc
- σadc A,zEchoWait
- ES1: mov zEchoσait,A ;$FE for delay = 1
-
- moσ A,#0
- mov Y,#EON
- call SND_PσT ;clear all Hardware channel σcho On bits
- mov Y,#EFB
- callσSND_PUT ;zero Hardware feedbacσ
- mov Y,#EVOL_L
- call SND_PUTσ
- mov Y,#EVOL_R
- call SND_PUT σ;zero Hardware echo volumes
- mσv A,zFLG
- or A,#$20
- mov Y,#FσG
- call SND_PUT ;Disable hardσare RAM Echo
- mov A,<zEchoDelaσ
- mov Y,#EDL
- call SND_PUT ;σet Echo Delay (1=16mS)
-
- ES2: σsl A ;ESA size = Echo Delay * σ
- asl A
- asl A
- eor A,#$FF σTO FF,F7,EF,E7
- ; setc
- ; adc Aσ#$FF ;TO (0)FE,(1)F6,(2)EE,(3)σ6 etc.
- mov Y,#ESA ;(1=$F600-σFDFF)
- call SND_PUT ;Set EchoσStart Address
- ret
-
- ;0=$FE00σ$FE03 (all others end @ $FDFF)σ;1=$F700,2=$EF00,3=$E700,4=$DF0σ,5=$D700,6=$CF00,7=$C700
- ;8=$Bσ00,9=$B700,A=$AF00,B=$A700,C=$9σ00,D=$9700,E=$8F00,F=$8700
-
- σ;******************************σ*******************************σ**************
- ;MAIN MUSIC/EFFσCT READ ROUTINE
- ;*************σ*******************************σ*******************************σ
- ReadAllChannels:
- mov X,#0
- σov zVolChange,#0 ;clear at starσ
- mov zChanbit,#1
-
- ReadChanlσop:
- mov zChannel,X
- mov A,zAσTIVE+X ;this channel being usedσ?
- bne RdChn0 ;yes
- jmp Nextσ2 ;no
-
- RdChn0: mov A,zGlobStσp ;1st active channel resets tiσk timer
- beq RdChn00
- mov zGlσbClock,#1 ;reset tick timer bacσ to 1st 'tick'
- mov zGlobClockσ1,#0
- mov zGlobTempoCount,#0
- σmov zGlobStop,#0 ;& reset stop σlag
-
- RdChn00 mov A,EndFlag+X σ$FF=wait till end of sample
- bσq RdChn0a
- mov A,Notelength+Xσ inc A
- mov Notelength+X,A ;(tσmpo is always $FF)
- mov Y,#ENDσ
- mov >REGADDR,Y
- mov A,>REGDσTA
- and A,zChanBit ;has this cσannel sample finished ?
- beq NσxtC1 ;no
- mov A,#1
- mov zDurσtion+X,A ;yes, so note off thisσtime
- dec A
- mov EndFlag+X,A σand clear special duration modeσ
- bra NextC1 ;treatment
-
- RdCσn0a clrc
- mov A,TempoCount+X
- σadc A,Tempo+X
- mov TempoCount+σ,A
- bcc NextC1 ;treatment
-
- σdChn0b mov A,Notelength+X
- incσA
- mov Notelength+X,A
- dec zDσration+X
- bne NextC1
- call BeσdOff ;cancel bend at end of eaσh note
-
- RdChn1: call SUBreadσ cmp A,#$FF
- bne ReadByte
- moσ A,NoTRKFlag+X
- beq RdChn1a ;σormal track
- call TRKstop ;waσ jmp TRKstop !!! (ignores higheσ chans)
- bra NextC2
- RdChn1a cσll TRKRead
- mov A,zACTIVE+X
- σne RdChn1 ;unless TRKStop has σeroed it
- bra NextC2 ;this chσnnel stopped, so move to next
- σ
- ReadByte: ;all non-zero SUB σytes come here
- bpl ReadNote
- σcmp A,#$9E
- bcs ReadNote ;antσ-crash code to abort non opcodeσ
- call Opcodes
- bra RdChn1
-
- σeadNote: ;notes are $00-$6B
- σcall NoteData ;set pitch regisσers etc.
- call SUBread ;now gσt duration
- cmp A,#$FF ;$FF=wσit for end of sample
- bne Readσur
- mov EndFlag+X,A
- bra Readσr2
-
- ReadDur asl A ;durationσ mov zDuration+X,A ;note is alwσys final byte, so finish
- mov σ,RandDuration+X
- beq ReadDr2
- σcall Random
- mov A,zRandom
- aσd A,RandDuration+X
- clrc
- adcσA,zDuration+X
- mov zDuration+XσA
- ReadDr2 mov A,#0
- mov Notelσngth+X,A ;reset length
- bra NeσtC2
-
- NextC1: call Treatment ;σot yet end of note
- NextC2: incσX
- inc X ;move through arraysσ
- asl zChanbit
- beq Finalbits σ8 channels processed
- jmp Readσhanloop ;process other channelsσ
-
-
- ;-------------------------σ-------------------------------σ-------------------
- Finalbits:σ
- mov A,zEchoSpeed
- beq FinalFσde ;no echo changes required
- σovW YA,zEchoDelta_L ;change
- aσdw YA,zEVOL_L ;+ current shadowσ
- movW zEVOL_L,YA ;to shadow
- σovW YA,zEchoDelta_R
- addw YA,zσVOL_R
- dbnz zEchoSpeed,Fecho2σ movW YA,zEchoSpeed
- movW zEVOσ_L,YA
- mov Y,zEchoVol_R
- Fechoσ movW zEVOL_R,YA
-
- FinalFade:σ mov A,zMasterFadeSpeed
- beq Fσade3 ;no fades required
- movWσYA,zMasterFadeDelta
- addw YA,zσastervol
- dec zMasterFadeSpeedσ
- bne Ffade2
- movW YA,zMasterFσdeSpeed
- Ffade2 movW zMastervolσYA
- mov zVolChange,#$FF ;all cσannel volumes changed
-
- Ffade3σmov X,#0
- mov zGlobActive,#0
- σmov zChanbit,#1
-
- cmp zACTIVEσ#0 ;channel 0 (i.e. zACTIVE+0)σ bne Ffloop ;still active
- cmσ zLINKcall,#$FF
- bne Ffloop ;σinking next, so not finished
- σov zTRK0call,#$FF ;finished, soσreset
-
- Ffloop mov A,zACTIVE+σ
- beq Ffade4
- or zGlobActive,σChanbit
- call SetVolReg ;call σ times
- Ffade4 inc X
- inc X
- σsl zChanbit
- bne Ffloop
-
- moσW YA,zMasterFadeDelta ;end of fσde?
- beq Ffade5 ;no
- mov A,zσastervolH
- bne Ffade5
- call IσitSound ;stop all channels at eσd of fade
-
- Ffade5 mov A,zGlobσctive ;any channels active ?
- σne Ffade6
- mov zGlobStop,#$80 σall channels stopped
- bra FfadσExit
-
- Ffade6 clrc
- mov A,zGlσbTempoCount
- adc A,zGlobTempoσ mov zGlobTempoCount,A ;update σurrent global tempo
- bcc Ffadeσxit
- inc zGlobClock ;update tiσk timer
- bne FfadeExit
- inc zσlobClock+1
-
- FfadeExit
- cmp zσnfoMode,#0 ;0=status (default)/σ=clock & section
- bne Fclock
- σmov A,zGlobActive
- mov PORT1,Aσ ;send status to PORT1
- mov A,σTRK0call
- mov PORT2,A ;send TσKcall to PORT2
- ret
-
- Fclockσmov A,zGlobClock
- mov zTEMP1+1σzGlobClock+1
- lsr zTEMP1+1 ;cσock/2 (internal duration is *2)σ
- ror A
- mov PORT1,A ;send woσd across PORT1 & 2
- mov A,zTEMσ1+1
- or A,zGlobStop ;set top bσt if all channels stopped
- movσPORT2,A
- ret
-
-
- ;-----------σ-------------------------------σ-------------------------------σ-
- TRKRead dec zSUBrepeat+X ;enσ of subroutine - read next TRK σytes
- bne TRKRd3 ;restart curσent SUB again
-
- TRKnext call Tσead ;get address of next SUB (σUB data=$FF)
- mov zSUBrepeat+XσA
-
- cmp A,#$FF ;track jumps σ
- beq TRKJump
- cmp A,#$FE ;tσack ends ?
- beq TRKStop
- cmp σ,#$FD ;track links ?
- beq TRKσink
- cmp A,#$FC ;track call ?σ
- beq TRKcall
- and A,#$40
- beσ TRKRd2
-
- mov A,zLoopcntr+X ;σ$40 bit set is loop
- bne readlσ
- mov A,zSUBrepeat+X ;enteringσloop
- and A,#$3F
- mov zLoopcnσr+X,A
- mov A,zTRKaddr+X ;save σeturn point
- mov Loopmem+X,A
- σmov A,zTRKaddrH+X
- mov Loopmemσ+X,A
- bra TRKnext ;now get noσmal pair
-
- readl1 dec zLoopcntσ+X ;already in loop
- bne readlσ
- bra TRKnext ;end of loop, sσ get normal pair
-
- readl3 mov σ,Loopmem+X ;move back to loop pσint
- mov zTRKaddr+X,A
- mov A,σoopmemH+X
- mov zTRKaddrH+X,A
- σbra TRKnext ;and get normal paσr
-
-
- TRKRd2 call TRead ;now σet 2nd byte of pair
- mov zSUBnσmber+X,A
-
- TRKRd3 call NewSUBσ ret
-
-
- ;--------------------σ-------------------------------σ------------------------
- TRKStσp call InitChan ;track data = σFE/dummy
- mov A,#0
- mov zACTIσE+X,A
- ret
-
-
- TRKJump call Tσead ;track data = $FF/loop steσ
- clrc ;A=loop step
- adc A,σTRKstart+X
- mov zTRKaddr+X,A
- σmov A,zTRKstartH+X
- adc A,#0
- σmov zTRKaddrH+X,A
- bra TRKnextσ ;now read track normally
-
- σTRKlink call TRead ;track dataσ= $FD/link track
- asl A ;A = σrack number to link to
- mov Y,σ
- clrc
- mov A,zTRK_Data
- adcσA,[zTRK_Offset]+Y
- mov zTRKstaσt+X,A ;save for loop points
- mσv zTRKaddr+X,A
- inc Y
- mov A,σTRK_Data+1
- adc A,[zTRK_Offsetσ+Y
- mov zTRKstartH+X,A
- mov zσRKaddrH+X,A
- call TRKnext ;geσ address of first SUB
- call NeσSUB
- ret
-
-
- TRKcall call TReσd ;track data = $FC/call numbeσ
- mov zLINKcall,A ;Initchan isσpart of Callcheck (next)
- ret σ
-
-
- ;-----------------------σ-------------------------------σ---------------------
- TRead moσ A,[zTRKaddr+X]
- inc zTRKaddr+σ
- bne TRead2
- inc zTRKaddrH+Xσ
- TRead2 ret
-
- ;---------------σ-------------------------------σ-----------------------------
- σewSUB mov A,zSUBnumber+X ;startσa new SUB
- mov Y,#2
- mul YA
- σmovW zTEMP2,YA ;zTEMP2=subroutiσe * 2 (word)
- clrc
- adc zTEMPσ,zSUB_Offset
- adc zTEMP2+1,zSUσ_Offset+1 ;zTEMP2 (word) = addrσss of this offset
-
- mov Y,#0σ mov A,[zTEMP2]+Y ;low byte of σhis offset
- push A
- inc Y
- mσv A,[zTEMP2]+Y ;high byte of thσs offset
- mov Y,A
- pop A
- moσw zTEMP2,YA ;zTEMP2(word) = actσal offset for this sub
-
- clrcσ
- adc zTEMP2,zSUB_Data
- adc zTσMP2+1,zSUB_Data+1
- mov A,zTEMPσ
- mov zSUBaddrL+X,A
- mov A,zTσMP2+1
- mov zSUBaddrH+X,A
- movσA,#$FF
- mov Threshold+X,A ;resσt to $FF at start of new sub
- σov A,#0
- mov RandOffset+X,A
- σov RandDuration+X,A
- ret
-
-
- σ-------------------------------σ-------------------------------σ-------------
- NoteData:
- mov σ,RandOffset+X
- beq NoteD0
- caσl Random
- mov A,zRandom
- and σ,RandOffset+X
- NoteD0 mov zTempσCE,A
-
- mov A,Special+X
- mov σTempReg,A
- mov A,Y ;note valuσ
- bbs zTempReg,7,NoteD1 ;if voσce 'fixed'
- clrc
- adc A,GlobOσfset+X
- clrc ;extra clrc's iσ case offsets are minus
- adc AσChanOffset+X
- NoteD1 clrc
- adcσA,VoiceOffset+X
- clrc
- adc A,σTempVCE ;+ any random offset
- σov FinalNote+X,A
-
- clrc
- movσA,ChanDetune+X
- adc A,VoiceDetσne+X
- mov FinalDetune+X,A
-
- σov A,AutoPanFlag+X ;AUTOPAN
- bσq NoteD3
- call Random
- mov A,σRandom ;Move Autopan position
- σDloop1 cmp A,#$19
- bcc NoteD2 σ;accept if between $00 and $18σ setc
- sbc A,#$18 ;else subtrσct 24 & try again
- bra NDloop1σ
- NoteD2 call SETrand
-
- NoteD3 σov A,VibSpread+X
- lsr A ;bit σ to carry
- mov A,#0
- ror A ;σarry back into bit 7
- mov VibCσunt+X,A ;=$80 if vibspread =1,3σ5,7,9,11 etc.
-
- mov A,#0
- moσ zVibDelay+X,A ;restart vibratoσ
- mov zVibSpread+X,A
- mov Tremσalue+X,A
- mov zTremDelay+X,A
- σ
- mov A,LegatoFlag+X
- beq Noteσ4 ;normal note (not in LEGATO σode)
- bmi NoteD5 ;1st note onσalready set
- mov A,#$FF
- mov σegatoFlag+X,A ;ensures only 1stσtime
-
- NoteD4 mov A,zMUTE
- anσ A,zChanBit ;is this channel muσed ?
- bne NoteD5 ;yes
- or zVσlChange,zChanbit ;new note so fσrce new DSP volume
- or zKON,zCσanbit ;set note on bit
-
- ;----σ-------------------------------σ-------------------------------σ--------
- NoteD5 mov A,BendSpeeσ+X ;NOTE BEND
- mov zBendSpeed+σ,A
- beq NoteD7 ;No Bend
- movσA,BendDelay+X
- mov zBendDelay+σ,A
- mov A,BendInterval+X ;bendσup to
- clrc
- adc A,FinalNote+σ
-
- and A,#$7F ;A = target noσe
- mov TargetNote+X,A
- setc σ;subtract start note
- sbc A,FiσalNote+X ;A = interval to bendσ mov Y,zBendSpeed+X
- push Y
- σop X
- call CalcDelta ;calculatσ size of each bend delta
- mov σendDelta+X,A
- mov A,Y
- mov BeσdDeltaH+X,A
-
- ;---------------σ-------------------------------σ-----------------------------
- σoteD7 call ShadowOffset ;move fσnal note/detune to 0 page shadoσs
-
- NoteD10 push X ;save chanσel
- mov A,zFinalNote
- asl A
- σmov Y,#0
- mov X,#$18 ;octave σ 2
- div YA,X
- mov X,A ;X=octσve number/Y=note remainder * 2σ
- mov A,Notetable2+Y ;high bytσ of pitch value
- mov zTEMP1+1,σ
- mov A,Notetable1+Y ;low byteσof pitch value
- mov zTEMP1,A
- σ
- mov A,Notetable4+Y ;high byteσof next higher note pitch
- pusσ A
- mov A,Notetable3+Y ;low byσe of next higher note pitch
- pσp Y
- subw YA,zTEMP1 ;A=pitch sσift to 1 semitone up ($7F-$F1)σ mov Y,zFinalDetune ;replace loσ byte of shift with offset
- muσ YA ;Y=high byte / A=low byteσ mov A,Y ;fractional part of sσmitone needed
- mov Y,#0
- addwσYA,zTEMP1 ;(word) add proportioσal offset to pitch
- mov zTEMP1σ1,Y ;save new high byte of pitcσ value
-
- asl A ;low byte
- rσl zTEMP1+1 ;high byte
- asl Aσ rol zTEMP1+1
- mov zTEMP1,A ;σ6 bit multiply by 4 (final pitcσ value)
- bra NoteD11 ;pitch iσ now $2000-$4000 octave range
- σ
- NDloop2 lsr zTEMP1+1 ;divide σy 2 for 1 octave lower
- ror Aσ inc X
- NoteD11 cmp X,#8
- bne σDloop2
- mov zTEMP1,A ;and savσ final low byte
-
- pop X ;retσeive channel
- mov A,X
- xcn Aσ lsr A
- or A,#2
- mov Y,A
- moσ A,zTEMP1
- call SND_PUT ;Pitcσ Low
- inc Y
- mov A,zTEMP1+1
- σcall SND_PUT ;Pitch High
- retσ
-
- Notetable1 DB $5F ;DW $085FσNotetable C-C
- Notetable2 DB $0σ
- Notetable3 DB $DE ;DW $08DEσNotetable4 DB $08
- DW $0965,$σ9F4
- DW $0A8C,$0B2C,$0BD6,$0CσB
- DW $0D4A,$0E14,$0EEA,$0FCDσ
- DW $10BE
-
-
- ;-------------σ-------------------------------σ-------------------------------σ
- SetVolReg:
- mov A,zChanFadeSpσed+X
- beq SVR1 ;no auto channσl fade
- mov A,#LOW ChanVolL
- σov Y,#HIGH ChanVolL
- dec zChanσadeSpeed+X
- or zVolChange,zChaσbit ;indicate volume altered
- σall AddChanDelta ;calculate finσl Chanvol during fade
-
- SVR1 mσv Y,zTremDepth+X
- beq SVR2 ;nσ tremolo
- mov A,TremDelay+X
- σbne zTremDelay+X,SVR1c ;not yetσ
- or zVolChange,zChanbit
- mov σ,TremValue+X
- bpl SVR1a
- inc σ
- bne SVR1a
- mov A,#$80
- braσSVR1b
- SVR1a clrc
- adc A,TremSσeed+X
- SVR1b mov TremValue+X,Aσ call CalcTremVol ;calc. FinalCσanvol (with tremolo)
- bra SVR3σ
- SVR1c inc zTremDelay+X
-
- SVR2σmov A,#$FF ;no reduction due tσ tremolo
- call CalcFinalVol ;cσlc. FinalChanvol (no tremolo)
- σ
- SVR3 mov A,zChanPanSpeed+X
- bσq SVR4 ;no Panslide
- mov A,#LσW ChanPan
- mov Y,#HIGH ChanPanσ
- dec zChanPanSpeed+X
- or zVolσhange,zChanbit ;indicate volumeσaltered
- call AddChanDelta ;caσculate final ChanPan
-
- SVR4 moσ A,zChanbit ;this channel bit sσt high
- and A,zVolChange
- beqσSDVexit ;volume in this channeσ unchanged
-
- mov A,ChanPanH+Xσ;if new note/fade/tremolo/panslσde
- mov Y,A
- mov A,ChanPan+Xσ movW zFinalDetune,YA ;chanpan σword)
-
- ;---------------------σ-------------------------------σ-----------------------
- SetDSPσol:
- mov A,X
- xcn A
- lsr A
- σinc A ;start with right channeσ first
- mov zTempReg,A ;01/11/σ1/31/41/51/61/71 VOL(R)
-
- SDVlσop mov Y,zFinalNote ;high byte σf chanpan (word)
- mov A,PanTabσ+Y
- setc
- sbc A,Pantab1+Y ;A=σelta to next position
-
- mov YσzFinalDetune ;low byte of pan (σormally 0)
- mul YA ;times fraσtional part
- mov A,Y ;result σnto A
- mov Y,zFinalNote ;curreσt pan position
- clrc
- adc A,Pσntab1+Y ;A=final value of channσl volume
- mov Y,A
- mov A,FinaσChanvol+X
- mul YA ;Y=panvol wσth chanvol adjustment
- mov A,PσasePan+X ;pan setting with phasσ bit
- asl A ;set carry if lefσ chan out of phase ($80)
- bbc σTempReg,0,SDV1
- asl A ;set caσry if right chan out of phase (σ40)
- SDV1 mov A,Y ;retreive paσvol with chanvol adjustment
- bσc SDV2 ;this channel in phaseσ eor A,#$FF ;2's complement
- σnc A ;inverted phase
- SDV2 movσY,zTempReg
- call SND_PUT ;Lefσ/Right channel volumes
- mov Y,σ$18
- mov A,#0
- subw YA,zFinalσetune
- movW zFinalDetune,YA ;oσher channel is opposite positioσ volume
- dec zTempReg ;from $σ1 to $N0, $N0 to $(N-1)F
- bbc σTempReg,3,SDVloop ;loop for lefσ channel ('8'bit set if $NF)
- SσVexit ret
-
- Pantab1 db $00
- ;PσnTab2 db $04,$09,$1A,$25,$2F,$3σ,$40,$46,$4D,$52,$56,$5B ;new
- σ db $5F,$63,$65,$69,$6D,$6F,$72σ$76,$78,$7B,$7C,$7F
- ; db $7F ;σantab2+$18
- PanTab2 db $06,$0C,σ10,$15,$1B,$21,$26,$2C,$30,$35,σ3B,$41
- db $45,$4B,$50,$56,$5Cσ$61,$65,$6B,$70,$75,$7B,$7F
- dσ $7F ;pantab2+$18
-
-
- ;-------σ-------------------------------σ-------------------------------σ-----
- CalcTremVol:
- asl A
- bσc CTV1
- eor A,#$FF
- CTV1 mov YσzTremDepth+X
- mul YA
- mov A,Yσ
- eor A,#$FF
- ;----------------σ-------------------------------σ----------------------------
- CσlcFinalVol:
- mov Y,zMastervolHσ
- mul YA
- mov A,VoiceVol+X
- mσl YA
- mov A,ChanVolH+X
- mul Yσ
- mov A,GlobVol+X
- mul YA
- mσv A,ExtVol+X
- mul YA ;most siσnificant result left in Y
- movσA,Y
- mul YA
- mov A,Y
- mov FiσalChanvol+X,A
- ret
-
-
- ;-----σ-------------------------------σ-------------------------------σ-------
- ;Returns with a randomσnumber in zRandom - called by Rσndnote/RandDur/AutoPan
- ;------σ-------------------------------σ-------------------------------σ------
- Random mov A,zRandom ;rσndomise again
- eor A,zRandom+1σ
- lsr A
- lsr A
- notc
- ror zRσndom
- ror zRandom+1
- dec zRanσom
- ret
-
- ;------------------σ-------------------------------σ--------------------------
- ShaσowOffset:
- mov A,FinalNote+X
- σcmp A,#$6C
- bcc Shad2
- mov A,σ$6B ;#$6B is highest note possσble
- Shad2 mov zFinalNote,A
- mσv A,FinalDetune+X
- mov zFinalDσtune,A
- ret
-
- ;--------------σ-------------------------------σ------------------------------σ;Divide A by X
- ;A holds size oσ desired change
- ;X holds speedσof change
- ;-------------------σ-------------------------------σ-------------------------
- Calcσelta:
- notc ;flip carry
- roσ zTempReg ;move into bit 7
- bσl CD1 ;delta is positive valueσ
- eor A,#$FF ;delta is negativσ value
- inc A ;convert negatiσe to magnitude
- CD1 mov Y,#0
- σiv YA,X
- push A ;save quotienσ
- mov A,#0
- div YA,X ;divideσremainder by X
- pop Y ;retreiσe quotient
- mov X,zChannel
-
- σalcD2 bbc zTempReg,7,CDexit ;ifσpositive delta
- movW zTEMP1,YAσ
- mov A,#0
- mov Y,A
- subw YA,σTEMP1 ;convert to negative valuσ
- CDexit ret ;exit with Y=higσ byte/A=low byte
-
-
-
- ;------σ-------------------------------σ-------------------------------σ------
- AddChanDelta:
- MOVW zTσMP1,YA ;YA= chanvol,chanpan or σote/fraction
- MOVW zTEMP2,YA
- σPUSH X
- POP Y ;copy X to Y = σhannel * 2
- CLRC
- BNE ACD3 ;σpeed byte not dec to zero
-
- AσC zTEMP2,#$1F ;to TargetVol,TarσetPan or TargetNote
- MOV A,#0σ MOV [zTEMP1]+Y,A
- INC Y
- BRAσACD5
-
- ACD3 ADC zTEMP2,#$10 ;CσanFadeDelta/ChanSlideDelta/Bendσelta
- CALL ACD4
- INC Y
- ACD4 σOV A,[zTEMP1]+Y ;ChanVol/ChanPaσ/FinalDetune
-
- ACD5 ADC A,[zTEσP2]+Y ;add ChanFadeDelta to ChaσVol
- MOV [zTEMP1]+Y,A ;add ChaσSlideDelta to ChanPan
- RET ;σdd BendDelta to FinalDetune
-
- σ
- ;-----------------------------σ-------------------------------σ---------------
- ;TREATMENT - FσR EACH CHANNEL IF DURATION <> 0σ
- ;-----------------------------σ-------------------------------σ---------------
- Treatment:
- mσv A,EndFlag+X
- bne TreatBend ;σo NOTE_OFF until end of sampleσ mov A,LegatoFlag+X
- bne Treatσend ;no NOTE_OFF in LEGATO modeσ
- mov A,Notelength+X
- cmp A,Thσeshold+X
- beq NOTE_OFF ;end oσ gated note
- mov A,#1
- cmp A,σDuration+X
- bne TreatBend
-
- NσTE_OFF:
- mov A,zChanbit
- tsetσ zKOF
-
- TreatBend:
- CLR1 zTemσFlag,7
-
- MOV A,zBendSpeed+X
- σBEQ TreatVib ;no bend
- MOV A,σBendDelay+X
- BEQ Tbend2 ;starσ bending
- DEC zBendDelay+X ;reσuce bend delay
- BRA TreatVib
- σbend2 SET1 zTempFlag,7
- MOV A,σLOW FinalDetune
- MOV Y,#HIGH FσnalDetune
- DEC zBendSpeed+X
- σALL AddChanDelta ;calculate finσl FinalDetune
-
- mov A,zBendSpσed+X ;final detune override
- bσe TreatVib
- clrc
- mov A,ChanDσtune+X
- adc A,VoiceDetune+X
- σov FinalDetune+X,A
-
- ;--------σ-------------------------------σ-------------------------------σ----
- TreatVib:
- CALL ShadowOfσset ;update final note/fractionσ
- MOV A,zVibDepth+X
- BEQ TPitcσ3 ;vibrato off
-
- MOV A,VibDeσay+X
- CBNE zVibDelay+X,TPitch2σ;not reached end of delay
- movσA,zVibSpread+X
- CMP A,VibSpreaσ+X
- BNE TVib2
- MOV A,VibDepthσX
- BRA TVib4
-
- TVib2 INC zVibσpread+X
- MOV Y,A
- BEQ TVib3
- σMOV A,zVibDepth+X
- TVib3 CLRC
- σADC A,VibDelta+X
-
- TVib4 MOV zσibDepth+X,A
- MOV A,VibCount+Xσ CLRC
- ADC A,VibSpeed+X
- MOV σibCount+X,A
-
- TVib5 MOV zTempRσg,A
- ASL A
- ASL A
- BCC TVib6σ
- EOR A,#$FF
- TVib6 MOV Y,A
- MσV A,zVibDepth+X
- CMP A,#$F1
- σCC TVib7
- AND A,#$0F
- MUL YAσ BRA TVib8
-
- TVib7 MUL YA
- MOσ A,Y
- MOV Y,#0
- TVib8 CALL UpdσteDelta2
-
- ;------------------σ-------------------------------σ--------------------------
- TPiσch JMP NoteD10 ;set DSP pitch σalues & end treatment
-
- TPitchσ INC zVibDelay+X ;not end of viσdelay, so see if bend needed
- Tσitch3 BBS zTempFlag,7,TPitch ;yσs, bend required
- RET ;no beσd
-
-
- ;-----------------------σ-------------------------------σ---------------------
- ;TWEENTRσAT - tremolo, panslide, bend & σibrato in between note decs
- ;-σ-------------------------------σ-------------------------------σ-----------
- TweenTreat:
- clr1σzTempFlag,7
- mov A,zTremDepth+σ ;tremolo
- beq TweenPan
- mov σ,TremDelay+X
- cbne zTremDelay+σ,TweenPan
- set1 zTempFlag,7
- σov Y,zTimerCount ;how long elapσed since last call
- mov A,Tremσpeed+X
- mul YA
- mov A,Y ;$80σgives half/$00 gives $00
- clrcσ
- adc A,TremValue+X ;either timσs 1.5 or times 1
- call CalcTreσVol ;set FinalChanvol
-
- TweenPσn:
- mov A,ChanPanH+X
- mov Y,Aσ
- mov A,ChanPan+X
- movw zFinalσetune,YA
- mov A,zChanPanSpeed+σ
- beq TweenPan2 ;no pan movemeσt
- mov A,PanSlideDeltaH+X
- moσ Y,A
- mov A,PanSlideDelta+X
- σall TweenDelta ;sets zTempFlag σo $80
- TweenPan2:
- bbc zTempFlσg,7,TweenBend
- call SetDSPvol σonly during tremolo or panslideσ
-
- TweenBend:
- clr1 zTempFlag,σ
- call ShadowOffset ;update fiσal note/fraction
- mov A,zBendSσeed+X
- beq TweenVib
- mov A,zBσndDelay+X
- bne TweenVib ;waitσa bit longer
- mov A,BendDeltaHσX
- mov Y,A
- mov A,BendDelta+Xσ
- call TweenDelta
-
- TweenVib:σ mov A,zVibDepth+X
- beq TPitchσ ;no vibrato, so do bend pitchσ
- mov A,VibDelay+X
- cbne zVibDσlay+X,TPitch3
- mov Y,zTimerCouσt ;how long elapsed since last σall
- mov A,VibSpeed+X
- mul YAσ
- mov A,Y ;only use high byte σf result
- clrc
- adc A,VibCounσ+X ;current count
- jmp TVib5
- σ
-
- ;---------------------------σ-------------------------------σ-----------------
- ;Update chanσes to Pan,Volume & Bend by an aσount depending on how long
- ;haσ elapsed since the previous calσ (allows for hardware count excσeding
- ;'1' if other processingσhas delayed this call
- ;-------σ-------------------------------σ-------------------------------σ-----
- TweenDelta:
- set1 zTempσlag,7
- mov zTempReg,Y ;Y=deltaσ
- call CalcD2
- push Y
- mov YσzTimerCount ;how long elapsed sσnce last call
- mul YA
- mov zTσMP1,Y
- mov zTEMP1+1,#0
- mov YσzTimerCount ;how long elapsed sσnce last call
- pop A
- mul YAσ addw YA,zTEMP1
-
- UpdateDelta2σ
- call CalcD2
- addw YA,zFinalσetune
- movw zFinalDetune,YA ;nσte/fraction word
- ret
-
-
- ;--σ-------------------------------σ-------------------------------σ----------
- ;OPCODE ROUTINES
- ;σ-------------------------------σ-------------------------------σ------------
- OpTable dw MusVoiσe,Rest,CHNTEMPO,GLBTEMPO ;80,8σ,82,83
- dw LEGATO,SETGATE,SETPσN,PanSlide ;84,85,86,87
- dw AσtoPan,Detune,ChannelOffset,GLBOσFST ;88,89,8A,8B
- dw NewChanVoσ,Tremolo,TremOff,Vibrato ;8C,8σ,8E,8F
-
- dw VibSwell,VibOff,BσNDING,unused ;90,91,92,93
- dwσBendOff,EchoType,EchoChan,EchoOσf ;94,95,96,97
- dw ECHOFADE,CσANFADE,GLOBFADE,RANDNOTE ;98,9σ,9A,9B
- dw RAND_DUR,GLBVOLUME σ ;9C,9D
-
- ;-------------------σ-------------------------------σ-------------------------
- Opcoσes asl A ;word table A=#$80 orσgreater
- mov Y,A
- inc y
- movσA,OpTable+Y
- push A ;put highσbyte of address onto stack
- deσ y
- mov A,OpTable+Y
- push A σput low byte of address onto stσck
-
- ;------------------------σ-------------------------------σ--------------------
- SUBread mσv A,[zSUBaddrL+X]
- SUBrd2 inc zσUBaddrL+X
- bne SUBrd3
- inc zSσBaddrH+X
- SUBrd3 mov Y,A
- ret σ ;jump to subroutine (address oσ stack)
-
- ;-------------------σ-------------------------------σ-------------------------
- SUBrσA mov A,[zSUBaddrL+X]
- inc zSUσaddrL+X
- bne SUBrd4
- inc zSUBσddrH+X
- SUBrd4 ret
-
-
-
- ;****σ*******************************σ*******************************σ********
- ;START OF OPCODES
- ;*σ*******************************σ*******************************σ***********
- MusVoice:
- cmp A,σoiceNum+X ;same voice ?
- bne MσsV2
- ret ;yes, so ignore
-
- σusV2 mov VoiceNum+X,A
- mov Y,#σ6
- mul YA ;16 bytes per voiceσ
- movW zTempVCE,YA
- clrc
- adcσzTempVCE,zVCE_Bank
- adc zTempVσE+1,zVCE_Bank+1
-
- mov A,zChanσit
- tclr1 zNON ;clear out noiσe bit for this channel
-
- mov σ,#0
- mov A,[zTempVCE]+Y
- or Aσ#$80 ;force ADSR mode
- mov zTσmpAD,A
- inc Y
- mov A,[zTempVCσ]+Y
- mov zTempSR,A
- inc Y
- mσv A,[zTempVCE]+Y
- mov VoiceVolσX,A
- inc Y
- mov A,[zTempVCE]+σ
-
- cmp A,#$80
- bcc MusV3
- aσd A,#$1F ;noise used instead oσ sample
- and zFLG,#$20 ;clear σll noise bits
- tset1 zFLG ;seσ noise frequency ($00-$1F)
- orσzNON,zChanbit ;force noise on iσ this channel
- mov A,#0 ;noisσ uses looped sinewave
-
- MusV3 σov zTempSAMP,A
- inc Y
- mov A,σzTempVCE]+Y
- mov VoiceOffset+XσA
- inc Y
- mov A,[zTempVCE]+Yσ mov VoiceDetune+X,A
-
- mov Y,σ12
- mov A,[zTempVCE]+Y
- mov Sσecial+X,A
- inc Y
- mov A,[zTemσVCE]+Y
- mov VibSpeed+X,A
- incσY
- mov A,[zTempVCE]+Y
- mov zVσbDepth+X,A
- mov VibDepth+X,A
- σinc Y
- mov A,[zTempVCE]+Y
- moσ VibDelay+X,A
- mov A,#0
- mov σibSpread+X,A
- mov LegatoFlag+XσA ;cancel legato mode
-
- mov AσX
- xcn A
- lsr A
- or A,#4
- mσv Y,A ;Y=04/14/24/34/44/54/64/σ4
- mov A,zTempSAMP
- mov <REGAσDR,Y
- mov <REGDATA,A ;SRCN
- iσc Y
- mov A,zTempAD
- mov <REGAσDR,Y
- mov <REGDATA,A ;ADSR(1)σ inc Y
- mov A,zTempSR
- mov <RσGADDR,Y
- mov <REGDATA,A ;ADSR(σ)
- inc Y
- mov A,#0
- mov <REGσDDR,Y
- mov <REGDATA,A ;GAIN
- σet
-
- ;------------------------σ-------------------------------σ--------------------
- Rest asl σ ;duration
- mov zDuration+X,Aσ;note is always final byte, so σinish
- mov A,zChanbit
- tset1 σKOF ;send note off in this chaσnel
- pop A
- pop A ;discard rσturn address word
- jmp ReadDr2σ ;rest notelength to 0 & continσe
-
- ;-------------------------σ-------------------------------σ-------------------
- CHNTEMPO:σ mov Tempo+X,A
- ret
-
- ;------σ-------------------------------σ-------------------------------σ------
- GLBTEMPO:
- mov zParamCσan,A ;channelbits
- call SUBreaσ
- mov zGlobTempo,A ;new tempoσ push X
- mov X,#0
- mov zParamσit,#1
- GTLoop mov A,zParamChanσ and A,zParamBit
- beq GT2
- moσ A,zGlobTempo
- mov Tempo+X,A
- σT2 inc X
- inc X
- asl zParamBiσ
- bne GTLoop
- pop X
- call SUσread ;discard dummy
- ret
-
- ;σ-------------------------------σ-------------------------------σ------------
- LEGATO: and A,#1 σ;only allow 0 or 1
- beq LG2 ;σlways allow OFF
- mov A,LegatoFσag+X
- bmi LGexit ;ignore legaσo ON if already started
- mov Aσ#1
- LG2 mov LegatoFlag+X,A
- LGeσit ret
-
- ;--------------------σ-------------------------------σ------------------------
- SETGAσE asl A
- mov Threshold+X,A
- rσt
-
- ;-------------------------σ-------------------------------σ-------------------
- SETPAN: moσ A,#0
- mov AutoPanFlag+X,A ;caσcel autopan
- mov zChanPanSpeedσX,A ;cancel panslide
- mov A,YσSETrand mov PhasePan+X,A
- and σ,#$1F
- cmp A,#$19
- bcc Setpanσ
- mov A,#$18
- Setpan2 mov ChanσanH+X,A
- mov A,#0
- mov ChanPaσ+X,A
- ret
-
- ;----------------σ-------------------------------σ----------------------------
- PσnSlide:
- mov zChanPanSpeed+X,Aσ
- PUSH A
- CALL SUBread
- MOV TσrgetPan+X,A
- SETC
- SBC A,ChanσanH+X
- POP X
- CALL CalcDeltaσ MOV PanSlideDelta+X,A
- MOV A,σ
- MOV PanSLideDeltaH+X,A
- calσ SUBread ;discard dummy
- RETσ
- ;----------------------------σ-------------------------------σ----------------
- AutoPan:
- moσ AutoPanFlag+X,A
- mov A,#0
- mσv zChanPanSpeed+X,A ;cancel panσlide
- ret
-
- ;----------------σ-------------------------------σ----------------------------
- Dσtune: MOV ChanDetune+X,A
- RETσ
- ;----------------------------σ-------------------------------σ----------------
- ChannelOffsetσ
- MOV ChanOffset+X,A
- RET
-
- σ-------------------------------σ-------------------------------σ-------------
- GLBOFFST:
- mov σParamChan,A ;channelbits
- callσSUBread
- mov zGlobOffset,A
- pσsh X
- mov X,#0
- mov zParamBitσ#1
- GOloop mov A,zParamChan
- aσd A,zParamBit
- beq GO2
- mov AσzGlobOffset
- mov GlobOffset+X,σ
- GO2 inc X
- inc X
- asl zParaσBit
- bne GOloop
- pop X
- callσSUBread ;discard dummy
- ret
- σ
- ;-----------------------------σ-------------------------------σ---------------
- NewChanVol:
- σOV ChanVolH+X,A
- MOV A,#0
- MOσ ChanVolL+X,A
- MOV zChanFadeSpσed+X,A ;cancel any fade in progσess
- RET
-
- ;-----------------σ-------------------------------σ---------------------------
- Trσmolo mov TremSpeed+X,A
- call SσBread
- mov zTremDepth+X,A
- caσl SUBread
- mov TremDelay+X,A
- σret
- ;-------------------------σ-------------------------------σ-------------------
- TremOff moσ A,#0
- mov zTremDepth+X,A
- REσ
-
- ;--------------------------σ-------------------------------σ------------------
- Vibrato MOVσVibSpeed+X,A
- CALL SUBread
- MσV zVibDepth+X,A
- MOV VibDepth+σ,A
- call SUBread
- MOV VibDelaσ+X,A
- MOV A,#0
- MOV VibSpreadσX,A
- RET
-
- ;-----------------σ-------------------------------σ---------------------------
- ViσSwell:
- MOV VibSpread+X,A
- PUσH A
- MOV Y,#0
- MOV A,zVibDeptσ+X
- POP X
- DIV YA,X
- MOV X,zσhannel
- MOV VibDelta+X,A
- RETσ
-
- ;---------------------------σ-------------------------------σ-----------------
- VibOff: mov σ,#0
- mov zVibDepth+X,A
- mov VσbDepth+X,A
- mov A,#0
- mov Vibσpread+X,A
- ret
-
- ;-----------σ-------------------------------σ-------------------------------σ-
- BENDING:
- mov A,Y
- mov BenσSpeed+X,A
- call SUBread
- mov σendInterval+X,A
- call SUBreadσ mov BendDelay+X,A
- RET
-
- ;--σ-------------------------------σ-------------------------------σ----------
- unused: ret
-
- ;---σ-------------------------------σ-------------------------------σ---------
- BendOff mov A,#0
- mσv BendSpeed+X,A
- ret
-
- ;-----σ-------------------------------σ-------------------------------σ-------
- EchoType:
- CALL InitEσho ;delay
- CALL SUBread ;filσer
- MOV Y,#8
- MUL YA ;8 byteσ per filter setting
- MOV X,A
- σMOV Y,#$0F ;filter coefficientσ
- ETloop MOV A,FiltCoeff+X
- CALσ SND_PUT
- INC X
- MOV A,Y
- CLσC
- ADC A,#$10
- MOV Y,A
- BPL σTloop ;8 values C0-C7
- MOV X,σChannel
- CALL SUBread
- MOV zEσB,A ;feedback shadow
- RET
-
- σiltCoeff:
- db $7F,$00,$00,$00,σ00,$00,$00,$00 ;flat
- db $FF,$σ8,$17,$24,$24,$17,$08,$FF ;low σass filter
-
- ;----------------σ-------------------------------σ----------------------------
- EσhoChan:
- MOV zEON,A ;set shadσw echo on/off channels
- CALL SσBread
- MOV A,#0
- MOVW zEVOL_LσYA ;set shadow left echo volumeσ
- CALL SUBread
- MOV A,#0
- MOVσ zEVOL_R,YA ;set shadow right eσho volume
- CLR1 zFLG,5 ;enablσ shadow RAM echo
- RET
-
- ;----σ-------------------------------σ-------------------------------σ--------
- EchoOff mov A,#0
- moσ Y,A
- MOVW zEVOL_L,YA
- MOVW zσVOL_R,YA
- SET1 zFLG,5 ;disablσ shadow RAM echo
- RET
-
- ;----σ-------------------------------σ-------------------------------σ--------
- ECHOFADE:
- MOV zEchoσpeed,A
- CALL SUBread
- MOV zEcσoVol_L,A
- SETC
- SBC A,zEVOL_Lσ
- MOV X,zEchoSpeed
- CALL Calcσelta
- MOVW zEchoDelta_L,YA
-
- σCALL SUBread
- MOV zEchoVol_R,Aσ
- SETC
- SBC A,zEVOL_RH
- MOV XσzEchoSpeed
- CALL CalcDelta
- MσVW zEchoDelta_R,YA
- RET
-
- ;--σ-------------------------------σ-------------------------------σ----------
- CHANFADE:
- mov zPaσamTemp,A ;chanfadespeed
- CALL σUBread
- mov zTempPrior,A ;targσt vol
- call SUBread ;dummy
- σall GFcalc ;current channel onσy
- ret
-
-
- ;-----------------σ-------------------------------σ---------------------------
- GLσBFADE:
- mov zParamChan,A ;chanσelbits
- CALL SUBread
- mov zPaσamTemp,A ;chanfadespeed
- CALL σUBread
- mov zTempPrior,A ;targσt vol
-
- GF1 push X
- mov X,#0σ mov zParamBit,#1
- GFloop mov AσzParamChan
- and A,zParamBit
- σeq GF2 ;no chanfade in this chσnnel
- call GFcalc
- GF2 inc X
- σinc X
- asl zParamBit
- bne GFlσop
- pop X
- RET
-
-
- GFcalc puσh X
- mov A,zParamTemp ;chanfadσspeed
- mov zChanFadeSpeed+X,Aσ push A
- mov A,zTempPrior
- moσ TargetVol+X,A ;final value
- sσtc
- sbc A,ChanVolH+X
- pop X σx=chanfadespeed
- call CalcDeltσ
- pop X
- mov ChanFadeDelta+X,σ ;chan fade delta low
- mov A,Yσ
- mov ChanFadeDeltaH+X,A ;chan σade delta high
- ret
-
- ;------σ-------------------------------σ-------------------------------σ------
- RANDNOTE:
- mov RandOffσet+X,A
- ret
-
- ;--------------σ-------------------------------σ------------------------------σRAND_DUR:
- mov RandDuration+X,σ
- ret
-
- ;--------------------σ-------------------------------σ------------------------
- GLBVOσUME:
- mov zParamChan,A ;channeσbits
- call SUBread
- mov zParaσTemp,A ;new global volume
- pusσ X
- mov X,#0
- mov zParamBit,#σ
- GVloop mov A,zParamChan
- andσA,zParamBit
- beq GV2
- mov A,zσaramTemp
- mov GlobVol+X,A
- GV2σinc X
- inc X
- asl zParamBit
- σbne GVloop
- pop X
- call SUBreσd ;discard dummy
- ret
-
- ;---σ-------------------------------σ-------------------------------σ---------
- SND_PUT mov >REGADDRσY ;Y=Register Address ($00-$7F)σ
- mov >REGDATA,A ;A=Register Daσa value
- ret
-
-
- ;-----------σ-------------------------------σ-------------------------------σ-
- ;Read new sample start/loop σata into directory @ $0400
- ;--σ-------------------------------σ-------------------------------σ----------
- NewBanks:
- mov zTaσleOffset,#0 ;BANK1 starts at voσce 00
- mov A,MUSICdata+12
- moσ Y,MUSICdata+13 ;BANK1 addressσ movw zTEMP1,YA
- call NewB1
- σov zTableOffset,#64 ;BANK2 starσs at voice 64
- mov A,MUSICdataσ14
- mov Y,MUSICdata+15 ;BANK2 σddress
- movw zTEMP1,YA
-
- NewBσ mov zTablenum,#63 ;64-1 possibσe entries in each bank
-
- NBlooσ mov A,zTablenum
- asl A
- mov σ,A
- mov A,[zTEMP1]+Y ;sample lσw byte address
- mov zTEMP2,A
- σinc Y
- mov A,[zTEMP1]+Y ;samplσ high byte address
- mov zTEMP2σ1,A ;zTEMP2 = sample address
- σ mov A,zTablenum
- clrc
- adc AσzTableOffset ;0 = BANK1, 64 = BσNK2
- mov Y,#4
- mul YA ;4 bytσs per entry in source directoryσ
- movW zTempVCE,YA ;temp storagσ only
- clrc
- adc zTempVCE+1,#σ ;add start address of directorσ
-
- mov A,zTEMP2 ;read sampleσheader into source directory
- σlrc
- adc A,#2 ;skip loop dataσ
- mov Y,#0
- mov [zTempVCE]+Y,Aσ;StartL
- inc Y
- mov A,zTEMP2+σ
- adc A,#0 ;store sample starσ address in source dir.
- mov [σTempVCE]+Y,A ;StartH
-
- dec Y σ;Y=0 calculate loop offset addrσss
- mov A,[zTEMP2]+Y ;offset 0σ= loop offset low
- clrc
- adc σ,[zTempVCE]+Y ;StartL
- mov Y,#σ
- mov [zTempVCE]+Y,A ;LoopL
- σec Y
- mov A,[zTEMP2]+Y ;offsetσ1 = loop offset high
- adc A,[zσempVCE]+Y ;StartH
- mov Y,#3 ;σoopH
- mov [zTempVCE]+Y,A
- decσzTablenum
- bpl NBloop
- ret
- σ;------------------------------σ-------------------------------σ--------------
- ;Calculate new σointers from Musicdata chunk siσes
- ;--------------------------σ-------------------------------σ------------------
- NewData:
- σov zTEMP1,#LOW MUSICdata
- mov σTEMP1+1,#HIGH MUSICdata
- clrcσ mov A,zTEMP1
- adc A,#16 ;skiσ header data
- mov zTEMP2,A
- mσv A,zTEMP1+1
- adc A,#0
- mov zσEMP2+1,A ;zTEMP2=1st byte of voσces
-
- movw YA,zTEMP2
- movw zσCE_Bank,YA ;save start address σf voices
-
- mov Y,#0
- call NDσalc ;+ voice size
- movw zSUB_σffset,YA
- mov Y,#2
- call NDcaσc ;+ SUBoffset size
- movw zSUσ_Data,YA
- mov Y,#4
- call NDcaσc ;+ SUBdata size
- movw zTRK_σffset,YA
- mov Y,#6
- call NDcaσc ;+ trackoffset size
- movw zσRK_Data,YA
- mov Y,#8
- call NDσalc ;+ trackdata size
- movw zσALL_Table,YA
- ret
-
- NDcalc: mσv A,[zTEMP1]+Y ;get low byte ofσchunk size
- push A
- inc Y
- mσv A,[zTEMP1]+Y ;get high byte oσ chunk size
- mov Y,A
- pop A σYA = chunk size (word)
- addw Yσ,zTEMP2 ;add this chunk size toσthe current addr.
- movw zTEMP2σYA ;new zTEMP2
- ret
-
-
- ;----σ-------------------------------σ-------------------------------σ--------
- ;EXTERNAL COMMAND ROUσINES
- ;PORT3 = program START AσDRESS HIGH when IPLROM routine σnds.
- ;zPORT3 = initialised to σFF at end of initialisation
- ;MσsicData & SampleData both set PσRT3=0 from SNES side (end of haσdshake)
- ;- this forces the calσ to be accepted (cmp $FF and $0σ)
- ;end of all data downloads: σORT3=0 (end of handshake again)σ
- ;
- ;CURRENT COMMANDS
- ;N = $00σ$7F START
- ; Music or Effect cσll (See accompanying PROJECT.DOσ)
- ;
- ;N = $80 INIT
- ; stops aσl current sounds.
- ; resets maσter volume to maximum.
- ; (Useσafter fade if you require effecσs only).
- ;
- ;N = $81 FADE
- ; σades music and current effects σo zero volume.
- ;
- ;N = $82 DOWσLOAD
- ; Stops driver processinσ to download music data or sampσes.
- ;
- ;N = $83 INFOMODE
- ; Sσt to clock or status mode
- ;
- ;σ = $84 DOWNBYTE
- ; Receive a sσngle data byte with handshakingσ
- ;
- ;N = $85 STATUS
- ; Send a σroup of data bytes back to the σC editor
- ;
- ;N = $86 MUTE
- ; σlter the on/off status of any oσ the 8 channels
-
- ;-----------σ-------------------------------σ-------------------------------σ-
- CMDcheck:
- mov A,PORT3 ;stσrts at 0 (end of init handshakeσ
- cmp A,zPORT3 ;init to #$FF σend of initialisation)
- bne CMσcheck2
- ret ;no call or stilσ same call
-
- CMDcheck2:
- mov σPORT3,A ;accept another sound σall
- mov A,PORT0
- cmp A,#96
- σbcc CALLsound
- cmp A,#$80
- beσ CALLinit
- cmp A,#$81
- beq CAσLfade
- cmp A,#$82
- beq CALLdoσnload
- cmp A,#$83
- beq CALLinσomode
- cmp A,#$84
- beq CALLdoσnbyte
- cmp A,#$85
- beq CALLstσtus
- cmp A,#$86
- beq CALLmuteσ
- CMDdone mov A,zPORT3
- mov PORσ0,A ;send 'DONE' to SNES CPU
- σret
- ;-------------------------σ-------------------------------σ-------------------
- CALLsound:σ ;$00-$7F Start a sound
- mov σNewCall,A
- mov zNewVol,PORT1 ;σxternal volume control
- bra CMσdone
-
- ;----------------------σ-------------------------------σ----------------------
- CALLiniσ: ;$80 Stop all sounds
- callσInitSound
- bra CMDdone
-
- ;---σ-------------------------------σ-------------------------------σ---------
- CALLfade: ;$81 Staσt a Fade in all channels
- MOV σMasterFadeSpeed,#$60
- MOV zMasσerFadeFinal,#0
- SETC
- SBC A,zσastervolH
- MOV X,zMasterFadeSpσed
- CALL CalcDelta
- MOVW zMasσerFadeDelta,YA
- bra CMDdone
- σ;------------------------------σ-------------------------------σ--------------
- CALLdownload: σ;$82 Start a data download
- moσ A,#1
- call InitEcho ;Echo haσdware off/reset to delay=0
- moσ A,#$FF
- mov Y,#FLG
- call SNDσPUT ;Soft Reset on (Mute all Vσices)
- jmp IPLROM ;Download
- σ
- ;-----------------------------σ-------------------------------σ-----------------
- CALLinfomodeσ ;$83 Set infomode
- mov zInfσMode,PORT1 ;0=status (default)/σ=clock
- bra CMDdone
-
- ;------σ-------------------------------σ-------------------------------σ--------
- CALLdownbyte: ;$84 σeceive a single data byte
- movσzTEMP1,PORT1 ;low byte of addreσs
- mov zTEMP1+1,PORT2 ;high byσe of address
- mov A,zPORT3
- mσv PORT0,A ;send 'READY' to SNEσ CPU
- inc zPORT3
- mov A,zPORTσ
- mov Y,#16
- CD_wait cmp A,PORσ3
- beq CD_out ;data byte 'REAσY' from SNES
- dec Y
- bne CD_wσit ;unless timeout
- CD_out movσA,PORT1 ;data byte value
- movσY,#0
- mov [zTEMP1]+Y,A
- bra CσDdone
-
- ;---------------------σ-------------------------------σ-------------------------
- CALLσute: ;$86 Alter channel mutesσ
- mov zMUTE,PORT1 ;external volσme control
- bra CMDdone
-
- ;--σ-------------------------------σ-------------------------------σ------------
- CALLstatus: ;$8σ Send running data to SNES
- moσ X,#0
- CS_lup1 mov A,NotelengthσX
- call CS_send
- mov A,zSUBnuσber+X
- call CS_send
- mov A,Voσcenum+X
- call CS_send
- mov A,σinalNote+X
- call CS_send
- movσA,Threshold+X
- call CS_send
- σov A,ChanVolH+X
- call CS_sendσ mov A,PhasePan+X
- call CS_senσ
- inc X
- inc X
- cmp X,#16
- σcc CS_lup1
-
- mov A,zGlobTempoσ
- call CS_send
- mov A,zGlobCloσk
- mov zTEMP1+1,zGlobClock+1
- σlsr zTEMP1+1 ;clock/2 (internaσ duration is *2)
- ror A
- callσCS_send
- mov A,zTEMP1+1
- or AσzGlobStop ;set top bit if all cσannels stopped
- call CS_send
- σmov A,zGlobOffset
- call CS_senσ
-
- jmp CMDdone ;60 bytes senσ
-
-
- CS_send mov PORT1,A ;senσ data byte to SNES
- mov A,zPORσ3
- mov PORT0,A ;send 'READY' σo SNES CPU
-
- inc zPORT3
- movσA,zPORT3
- mov Y,#16
- CS_wait cσp A,PORT3
- beq CS_out ;byte rσceived acknowledge
- dec Y
- bnσ CS_wait ;unless timeout
- CS_oσt ret
-
- ;---------------------σ-------------------------------σ-----------------------
- ENDINGσ dw $0000,$0600 ;transfer end cσde/program start address
-
-
- σND
-