Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
3326 lines (2995 sloc) 85.2 KB
;*
;* Copyright 2009 Mukunda Johnson (www.mukunda.com)
;*
;* This file is part of SNESMOD.
;*
;* SNESMOD is free software: you can redistribute it and/or modify
;* it under the terms of the GNU General Public License as published by
;* the Free Software Foundation, either version 3 of the License, or
;* (at your option) any later version.
;*
;* SNESMOD is distributed in the hope that it will be useful,
;* but WITHOUT ANY WARRANTY; without even the implied warranty of
;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;* GNU General Public License for more details.
;*
;* You should have received a copy of the GNU General Public License
;* along with SNESMOD. If not, see <http://www.gnu.org/licenses/>.
;*
#define DEBUGINC inc debug \ mov SPC_PORT0, debug
.define LBYTE(z) (z & 0FFh)
.define HBYTE(z) (z >> 8)
.define SPROC TCALL 0
.define SPROC2 SPROC
;********************************************************
; PROTOCOL
;
; mm = mimic data
; id = message id
; vv = validation data (not previous value)
; v1 = nonzero validation data (not previous value)
;
; SPC PORTS:
; PORT0 = RESERVED
; PORT1 = COMMUNICATION
; PORT2 = STATUS:
; MSB fep-cccc LSB
; f = module volume fade[out/in] in progress
; e = end of module reached (restarted from beginning)
; p = module is playing (0 means not playing or preparing...)
; cccc = cue, incremented on SF1 pattern effect
; PORT3 = MODULE POSITION
;
; NAME ID DESC
;--------------------------------------------------------
; LOAD 00 Upload Module
;
; >> id vv -- -- send message
; << -- mm -- -- message confirmed
;
; >> -- v1 DD DD transfer module
; << -- mm -- -- DDDD = data, loop until all words xferred
;
; >> -- 00 DD DD final word
; << -- mm -- -- okay proceed to transfer sources...
;
; for each entry in SOURCE_LIST:
;
; >> 01 vv LL LL send loop point
; << -- mm -- -- loop point saved
; >> -- v1 DD DD transfer source data
; << -- mm -- -- DDDD = data, loop unti all words xferred
;
; >> -- 00 DD DD transfer last word
; << -- mm -- --
;
; [loop until all needed sources are transferred]
;
; >> 00 vv -- -- terminate transfer
; << -- mm -- --
;
; notes:
; this function resets the memory system
; all sound effects will become invalid
;
; after final sample transferred the system may
; be halted for some time to setup the echo delay.
;--------------------------------------------------------
; LOADE 01 Upload Sound Effect
;
; >> id vv LL LL send message
; << -- mm -- -- source registered, ready for data
;
; >> -- v1 DD DD transfer source data
; << -- mm -- -- loop until all words xferred
;
; >> -- 00 DD DD send last word
; << -- mm -- -- okay, ready for playback
;
; sound effects are always one-shot
; LLLL is not used (or maybe it is...........)
;--------------------------------------------------------
; VOL 02 Set Master Volume
;
; >> id vv VV --
; << -- mm -- --
;
; VV = master volume level (0..127)
;--------------------------------------------------------
; PLAY 03 Play Module
;
; >> id vv -- pp
; << -- mm -- --
;
; pp = start position
;--------------------------------------------------------
; STOP 04 Stop Playback
;
; >> id vv -- --
; << -- mm -- --
;--------------------------------------------------------
; MVOL 05 Set Module Volume
;
; >> id vv -- VV
; << -- mm -- --
;
; VV = 0..255 new module volume scale
;--------------------------------------------------------
; FADE 06 Fade Module Volume
;
; >> id vv tt VV
; << -- mm -- --
;
; VV = 0..255 target volume level
; tt = fade speed (added every m tick)
;--------------------------------------------------------
; RES 07 Reset
;
; >> id vv -- --
;
; <driver unloaded>
;--------------------------------------------------------
; FX 08 Play Sound Effect
;
; >> id vv vp sh
; << -- mm -- --
;
; s = sample index
; h = pitch ( 8 = 32000hz, h = pitch height >> 9 )
; v = volume (15 = max)
; p = panning (8 = center)
;--------------------------------------------------------
; TEST 09 Test function
;
; >> id vv -- --
; << -- mm -- --
;--------------------------------------------------------
; SSIZE 0A Set sound region size
;
; >> id vv -- SS
; << -- mm -- --
;
; SS = size of sound region (SS*256 bytes)
;--------------------------------------------------------
; STREAM Update digital stream
;
; previously written port data must be buffered.
;
; >> 8m -- -- -- send update flag (8m = previous data OR 80H)
; [wait for spc, this is a high-priority signal]
; << 80 -- -- -- receive ready signal
;
; >> nn mm vp hh nn = number of blocks (9 bytes) to transfer (1..28)
; << nn -- -- --
;
; if mm <> 0 then
; [new sample, reset sound]
; v = volume
; p = panning
; hh = pitch height H byte (6 bits)
;
; length should be significantly larger than required on
; initial transfer (mm<>0)
;
; [xx is a counter starting with 'nn' written to port0 earlier]
; [add 1 before first message]
;
; transfer 1 chunk:
; loop 3 times:
; >> xx D2 D0 D1
; << xx -- -- --
; >> xx D5 D3 D4
; << xx -- -- --
; >> xx D8 D6 D7
; << xx -- -- --
; loop nn times
;
;(EXIT):
; [spc will resume operation after a short period]
; [port status must be restored before the spc resumes (approx. 45us)]
; >> pp pp pp pp restore port status
;********************************************************
;*****************************************************************************************
; registers
;*****************************************************************************************
SPC_TEST =0F0h ; undocumented
SPC_CONTROL =0F1h ; control register
SPC_DSP =0F2h
SPC_DSPA =0F2h
SPC_DSPD =0F3h
SPC_PORT0 =0F4h ; i/o port0
SPC_PORT1 =0F5h ; i/o port1
SPC_PORT2 =0F6h ; i/o port2
SPC_PORT3 =0F7h ; i/o port3
SPC_FLAGS =0F8h ; custom flags
SPC_TIMER0 =0FAh ; timer0 setting
SPC_TIMER1 =0FBh ; timer1 setting
SPC_TIMER2 =0FCh ; timer2 setting
SPC_COUNTER0 =0FDh ; timer0 counter
SPC_COUNTER1 =0FEh ; timer1 counter
SPC_COUNTER2 =0FFh ; timer2 counter
DEBUG_P0 = SPC_PORT0
DEBUG_P2 = SPC_PORT2
;*****************************************************************************************
; dsp registers
;*****************************************************************************************
DSPV_VOL =00h
DSPV_VOLR =01h
DSPV_PL =02h
DSPV_PH =03h
DSPV_SRCN =04h
DSPV_ADSR1 =05h
DSPV_ADSR2 =06h
DSPV_GAIN =07h
DSPV_ENVX =08h
DSPV_OUTX =09h
DSP_MVOL =0Ch
DSP_MVOLR =1Ch
DSP_EVOL =2Ch
DSP_EVOLR =3Ch
DSP_KON =4Ch
DSP_KOF =5Ch
DSP_FLG =6Ch
DSP_ENDX =7Ch
DSP_EFB =0Dh
DSP_PMON =2Dh
DSP_NON =3Dh
DSP_EON =4Dh
DSP_DIR =5Dh
DSP_ESA =6Dh
DSP_EDL =7Dh
DSP_C0 =0Fh
DSP_C1 =1Fh
DSP_C2 =2Fh
DSP_C3 =3Fh
DSP_C4 =4Fh
DSP_C5 =5Fh
DSP_C6 =6Fh
DSP_C7 =7Fh
FLG_RESET =80h
FLG_MUTE =40h
FLG_ECEN =20h
#define SETDSP(xx,yy) mov SPC_DSPA, #xx\ mov SPC_DSPD, #yy
;*****************************************************************************************
; module defs
;*****************************************************************************************
MOD_IV =00H ; INITIAL VOLUME
MOD_IT =01H ; INITIAL TEMPO
MOD_IS =02H ; INITIAL SPEED
MOD_CV =03H ; INITIAL CHANNEL VOLUME
MOD_CP =0BH ; INITIAL CHANNEL PANNING
MOD_EVOL =13H ; ECHO VOLUME (LEFT)
MOD_EVOLR =14H ; ECHO VOLUME (RIGHT)
MOD_EDL =15H ; ECHO DELAY
MOD_EFB =16H ; ECHO FEEDBACK
MOD_EFIR =17H ; ECHO FIR COEFS
MOD_EON =1FH ; ECHO ENABLE BITS
MOD_SEQU =20H ; SEQUENCE
MOD_PTABLE_L =0E8H ; PATTERN TABLE
MOD_PTABLE_H =128H ;
MOD_ITABLE_L =168H ; INSTRUMENT TABLE
MOD_ITABLE_H =1A8H ;
MOD_STABLE_L =1E8H ; SAMPLE TABLE
MOD_STABLE_H =228H ;
INS_FADEOUT =00H
INS_SAMPLE =01H
INS_GVOL =02H
INS_SETPAN =03H
INS_ENVLEN =04H
INS_ENVSUS =05H
INS_ENVLOOPST =06H
INS_ENVLOOPEND =07H
INS_ENVDATA =08H
SAMP_DVOL =00H
SAMP_GVOL =01H
SAMP_PITCHBASE =02H
SAMP_DINDEX =04H
SAMP_SETPAN =05H
;*****************************************************************************************
; zero-page memory
;*****************************************************************************************
xfer_address: .block 2
m0: .block 2
m1: .block 2
m2: .block 2
m3: .block 2
m4: .block 2
m5: .block 2
m6: .block 2
next_sample: .block 1
comms_v: .block 1 ;communication variable
evol_l: .block 1
evol_r: .block 1
module_vol: .block 1 ;module volume
module_fadeT: .block 1 ;module volume fade target
module_fadeR: .block 1 ;module volume fade rate
module_fadeC: .block 1 ;timer counter
mod_tick: .block 1
mod_row: .block 1
mod_position: .block 1
mod_bpm: .block 1
mod_speed: .block 1
mod_active: .block 1
mod_gvol: .block 1
patt_addr: .block 2
patt_rows: .block 1
pattjump_enable: .block 1
pattjump_index: .block 1
patt_update: .block 1 ;PATTERN UPDATE FLAGS
ch_start:
ch_pitch_l: .block 8
ch_pitch_h: .block 8
ch_volume: .block 8 ;0..64
ch_cvolume: .block 8 ;0..128 (IT = 0..64)
ch_panning: .block 8 ;0..64
ch_cmem: .block 8
ch_note: .block 8
ch_instr: .block 8
ch_vcmd: .block 8
ch_command: .block 8
ch_param: .block 8
ch_sample: .block 8
ch_flags: .block 8
ch_env_y_l: .block 8
ch_env_y_h: .block 8
ch_env_node: .block 8
ch_env_tick: .block 8
ch_fadeout: .block 8
ch_end:
; channel processing variables:
t_hasdata: .block 1
t_sampoff: .block 1
t_volume: .block 1
t_panning: .block 1
t_pitch:
t_pitch_l: .block 1
t_pitch_h: .block 1
t_flags: .block 1
t_env: .block 1 ; 0..255
p_instr: .block 2
STATUS: .block 1
STATUS_P =32
STATUS_E =64
STATUS_F =128
debug: .block 1
CF_NOTE =1
CF_INSTR =2
CF_VCMD =4
CF_CMD =8
CF_KEYON =16
CF_FADE =32
CF_SURROUND =64
TF_START =80H
TF_DELAY =2
;---------------------------
; sound effects
;---------------------------
sfx_mask: .block 1
sfx_next: .block 1
;-----------------------------------------------------------------------------------------
stream_a: .block 1
stream_write: .block 2
stream_rate: .block 1
stream_volL: .block 1
stream_volR: .block 1
stream_gain: .block 1
stream_initial: .block 1
stream_size: .block 1
stream_region: .block 1
;*****************************************************************************************
; sample directory
;*****************************************************************************************
SampleDirectory =0200h ; 256 bytes (64-sample directory)
EffectDirectory =0300h ; 16*4 bytes (16 sound effects)
StreamAddress =0340h ; 4 bytes (streaming buffer address)
PatternMemory =0380h ; 16*8 bytes
; [extra ram]
;*****************************************************************************************
; program (load @ 400h)
;*****************************************************************************************
;--------------------------------------------------------
.org 400h
;--------------------------------------------------------
;--------------------------------------------------------
main:
;--------------------------------------------------------
mov x, #0
mov a, #0
_clrmem:
mov (X)+, a
cmp x, #0F0h
bne _clrmem
mov SPC_PORT1, #0 ; reset some ports
mov SPC_PORT2, #0 ;
mov SPC_PORT3, #0 ;
mov SPC_CONTROL, #0 ; reset control
mov SPC_TIMER1, #255 ; reset fade timer
mov module_vol, #255 ; reset mvol
mov module_fadeT, #255 ;
;----------------
call ResetSound ;
;----------------
mov SPC_DSPA, #DSP_MVOL ; reset main volume
mov SPC_DSPD, #80 ;
mov SPC_DSPA, #DSP_MVOLR ;
mov SPC_DSPD, #80 ;
;----------------
mov SPC_DSPA, #DSP_DIR ; set source dir
mov SPC_DSPD, #SampleDirectory >> 8
call ResetMemory
call Streaming_Init
mov SPC_CONTROL, #%110
;----------------------------------------------------------------------
bra patch1 ; patch for it->spc conversion
;
call Module_Stop ;
mov a, #0 ;
call Module_Start ;
patch1: ;
;----------------------------------------------------------------------
;--------------------------------------------------------
main_loop:
;--------------------------------------------------------
SPROC2
call ProcessComms
SPROC
call ProcessFade
SPROC
call Module_Update
SPROC
call UpdatePorts
SPROC
call SFX_Update
bra main_loop
;--------------------------------------------------------
UpdatePorts:
;--------------------------------------------------------
mov SPC_PORT2, STATUS
mov SPC_PORT3, mod_position
ret
;--------------------------------------------------------
ResetMemory:
;--------------------------------------------------------
mov xfer_address, #MODULE & 0FFh ; reset transfer address
mov xfer_address+1, #MODULE >> 8 ;
mov next_sample, #0 ; reset sample target
ret
;--------------------------------------------------------
ResetSound:
;--------------------------------------------------------
SETDSP( DSP_KOF, 0FFh );
SETDSP( DSP_FLG, FLG_ECEN );
SETDSP( DSP_PMON, 0 );
SETDSP( DSP_EVOL, 0 );
SETDSP( DSP_EVOLR, 0 );
SETDSP( DSP_NON, 00h );
SETDSP( DSP_KOF, 000h ); this is weird
mov sfx_mask, #0
ret
;--------------------------------------------------------
ProcessComms:
;--------------------------------------------------------
cmp comms_v, SPC_PORT1 ; test for command
bne _new_message ;
ret ; <no message>
_new_message:
mov comms_v, SPC_PORT1 ; copy V
mov a, SPC_PORT0 ; jump to message
nop ; verify data
cmp a, SPC_PORT0 ;
bne _new_message ;
and a, #127 ; mask 7 bits
asl a ;
mov x, a ;
jmp [CommandTable+x] ;'
;--------------------------------------------------------
CommandRet:
mov SPC_PORT1, comms_v
ret
;--------------------------------------------------------
CommandTable:
;--------------------------------------------------------
.word CMD_LOAD ; 00h - load module
.word CMD_LOADE ; 01h - load sound
.word CMD_VOL ; 02h - set volume
.word CMD_PLAY ; 03h - play
.word CMD_STOP ; 04h - stop
.word CMD_MVOL ; 05h - set module volume
.word CMD_FADE ; 06h - fade module volume
.word CMD_RES ; 07h - reset
.word CMD_FX ; 08h - sound effect
.word CMD_TEST ; 09h - test
.word CMD_SSIZE ; 0Ah - set stream size
; .word CMD_PDS ; 0Ah - play streamed sound
; .word CMD_DDS ; 0Bh - disable digital stream
;********************************************************
CMD_LOAD:
;********************************************************
call Module_Stop
call ResetMemory ; reset memory system
call StartTransfer
mov m1, #0
_wait_for_sourcen: ;
cmp comms_v, SPC_PORT1 ;
beq _wait_for_sourcen ;
mov comms_v, SPC_PORT1 ;
cmp SPC_PORT0, #0 ; if p0 != 0:
beq _end_of_sources ; load source
;
mov y, m1 ;
clrc ;
adc m1, #4 ;
call RegisterSource ;
call StartTransfer ;
;
bra _wait_for_sourcen ; load next source
_end_of_sources: ; if p0 == 0:
jmp CommandRet ;
;-------------------------------------------------------------------
RegisterSource:
;-------------------------------------------------------------------
mov a, xfer_address
mov !SampleDirectory+y, a
clrc
adc a, SPC_PORT2
mov !SampleDirectory+2+y, a
mov a, xfer_address+1
mov !SampleDirectory+1+y, a
adc a, SPC_PORT3
mov !SampleDirectory+3+y, a
ret
;-------------------------------------------------------------------
StartTransfer:
;-------------------------------------------------------------------
mov x, comms_v ; start transfer
mov y, #0 ;
mov SPC_PORT1, x ;
;-------------------------------------------------------------------
DoTransfer:
;-------------------------------------------------------------------
cmp x, SPC_PORT1 ; wait for data
beq DoTransfer ;
mov x, SPC_PORT1 ;
;---------------------------
mov a, SPC_PORT2 ; copy data
mov [xfer_address]+y, a ;
mov a, SPC_PORT3 ;
mov SPC_PORT1, x ;<- reply to snes
inc y ;
mov [xfer_address]+y, a ;
inc y ;
beq _inc_address ; catch index overflow
_cont1: cmp x, #0 ; loop until x=0
bne DoTransfer ;
mov m0, y
clrc
adc xfer_address, m0
adc xfer_address+1, #0
mov comms_v, x
ret
_inc_address:
inc xfer_address+1
bra _cont1
;********************************************************
CMD_LOADE:
;********************************************************
mov a, xfer_address
mov y, next_sample
mov !EffectDirectory+y, a
clrc
adc a, SPC_PORT2
mov !EffectDirectory+2+y, a
mov a, xfer_address+1
mov !EffectDirectory+1+y, a
adc a, SPC_PORT3
mov !EffectDirectory+3+y, a
clrc ; safety clear for invalid loop points (thanks KungFuFurby)
adc next_sample, #4
call StartTransfer
jmp CommandRet
;********************************************************
CMD_VOL:
;********************************************************
mov a, SPC_PORT2
mov SPC_DSPA, #DSP_MVOL
mov SPC_DSPD, a
mov SPC_DSPA, #DSP_MVOLR
mov SPC_DSPD, a
call UpdateEchoVolume
jmp CommandRet
;********************************************************
CMD_PLAY:
;********************************************************
call Module_Stop
mov a, SPC_PORT3
and STATUS, #~STATUS_P
mov SPC_PORT2, STATUS
mov SPC_PORT1, comms_v
jmp Module_Start
;********************************************************
CMD_STOP:
;********************************************************
call Module_Stop
jmp CommandRet
;********************************************************
CMD_MVOL:
;********************************************************
mov module_vol, SPC_PORT3
mov module_fadeT, SPC_PORT3
jmp CommandRet
;********************************************************
CMD_FADE:
;********************************************************
or STATUS, #STATUS_F
mov SPC_PORT2, STATUS
mov module_fadeT, SPC_PORT3
mov module_fadeR, SPC_PORT2
jmp CommandRet
;********************************************************
CMD_RES:
;********************************************************
mov SPC_DSPA, #DSP_FLG
mov SPC_DSPD, #11100000b
clrp
mov SPC_CONTROL, #10000000b ;
jmp 0FFC0h
;********************************************************
CMD_FX:
;********************************************************
movw ya, SPC_PORT2
movw m0, ya
mov SPC_PORT1, comms_v
jmp SFX_Play
;********************************************************
CMD_TEST:
;********************************************************
SETDSP( 00h, 7fh )
SETDSP( 01h, 7fh )
SETDSP( 02h, 00h )
SETDSP( 03h, 10h )
SETDSP( 04h, 09h )
SETDSP( 05h, 00h )
SETDSP( 06h, 00h )
SETDSP( 07h, 7fh )
SETDSP( 0Ch, 70h )
SETDSP( 1Ch, 70h )
SETDSP( 4Ch, 01h )
jmp CommandRet
;********************************************************
CMD_SSIZE:
;********************************************************
call Module_Stop
mov a, SPC_PORT3
call Streaming_Resize
jmp CommandRet
;********************************************************
CMD_DDS:
;********************************************************
; call Streaming_Deactivate
; jmp CommandRet
;********************************************************
; Setup echo...
;********************************************************
SetupEcho:
SETDSP( DSP_FLG, 00100000b );
SETDSP( DSP_EVOL, 0 );
SETDSP( DSP_EVOLR, 0 );
mov a, !MODULE+MOD_EVOL
mov evol_l, a
mov a, !MODULE+MOD_EVOLR
mov evol_r, a
mov a, !MODULE+MOD_EDL ; ESA = stream_region - EDL*8
xcn a ; max = stream_region -1
lsr a ;
mov m0, a ;
mov a, stream_region ;
setc ;
sbc a, m0 ;
cmp a, stream_region ;
bne _edl_not_ss ;
dec a ;
_edl_not_ss: ;
mov SPC_DSPA, #DSP_ESA ;
mov SPC_DSPD, a ;
mov m0+1, a ; clear memory region used by echo
mov m0, #0 ;
mov a, #0 ;
mov y, #0 ;
_clearmem: ;
mov [m0]+y, a ;
inc y ;
bne _clearmem ;
inc m0+1 ;
cmp m0+1, stream_region ;
bne _clearmem ;
setc ; copy FIR coefficients
mov SPC_DSPA, #DSP_C7 ;
mov y, #7 ;
_copy_coef: ;
mov a, !MODULE+MOD_EFIR+y ;
mov SPC_DSPD, a ;
sbc SPC_DSPA, #10h ;
dec y ;
bpl _copy_coef ;
mov SPC_DSPA, #DSP_EFB ; copy EFB
mov a, !MODULE+MOD_EFB ;
mov SPC_DSPD, a ;
mov SPC_DSPA, #DSP_EON ; copy EON
mov a, !MODULE+MOD_EON ;
mov SPC_DSPD, a ;
mov SPC_DSPA, #DSP_EDL ; read old EDL, set new EDL
mov y, SPC_DSPD ;
mov a, !MODULE+MOD_EDL ;
mov SPC_DSPD, a ;
;-----------------------------------------
; delay EDL*16ms before enabling echo
; 16384 clks * EDL
; EDL<<14 clks
;
; run loop EDL<<10 times
;-----------------------------------------
mov a, y ;
asl a ;
asl a ;
inc a
mov m0+1, a ;
mov m0, #0 ;
_delay_16clks: ;
cmp a, [0]+y ;
decw m0 ;
bne _delay_16clks ;
mov a, !MODULE+MOD_EDL
beq _skip_enable_echo
call UpdateEchoVolume
mov SPC_DSPA, #DSP_FLG ; clear ECEN
mov SPC_DSPD, #0
ret
_skip_enable_echo:
mov evol_l, #0
mov evol_r, #0
ret
;********************************************************
; set echo volume with master scale applied
;********************************************************
UpdateEchoVolume:
mov SPC_DSPA, #DSP_MVOL ; set EVOL scaled by main volume
mov a, SPC_DSPD ;
asl a ;
mov m0, a ;
mov SPC_DSPA, #DSP_EVOL ;
mov y, evol_l ;
mul ya ;
mov a, y ;
mov y, evol_l ;
bpl _plus ;
setc ;
sbc a, m0 ;
_plus: mov SPC_DSPD, a ;
mov a, m0 ; set EVOLR scaled by main volume
mov SPC_DSPA, #DSP_EVOLR ;
mov y, evol_r ;
mul ya ;
mov a, y ;
mov y, evol_r ;
bpl _plusr ;
setc ;
sbc a, m0 ;
_plusr: mov SPC_DSPD, a ;
ret
;********************************************************
; zerofill channel data
;********************************************************
Module_ResetChannels:
mov x, #ch_start
mov a, #0
_zerofill_ch:
mov (x)+, a
cmp x, #ch_end
bne _zerofill_ch
ret
Module_Stop:
call ResetSound
mov SPC_CONTROL, #%110
mov mod_active, #0
ret
;********************************************************
; play module...
;
; a = initial position
;********************************************************
Module_Start:
mov mod_position, a
call ResetSound
call Module_ResetChannels
mov mod_active, #1
mov a, !MODULE+MOD_IS
mov mod_speed, a
mov a, !MODULE+MOD_IT
call Module_ChangeTempo
mov a, !MODULE+MOD_IV
mov mod_gvol, a
mov x, #7 ;
_copy_cvolume: ; copy volume levels
mov a, !MODULE+MOD_CV+x ;
mov ch_cvolume+x, a ;
dec x ;
bpl _copy_cvolume ;
mov x, #7
_copy_cpan:
mov a, !MODULE+MOD_CP+x
cmp a, #65
bcs _cpan_surround
mov ch_panning+x, a
bra _cpan_normal
_cpan_surround:
mov a, #32
mov ch_panning+x, a
mov a, #CF_SURROUND
mov ch_flags+x, a
_cpan_normal:
dec x
bpl _copy_cpan
call SetupEcho
mov a, mod_position
call Module_ChangePosition
; start timer
mov SPC_CONTROL, #%111
or STATUS, #STATUS_P
mov SPC_PORT2, STATUS
SETDSP( DSP_KOF, 0 ); // ??????
ret
;********************************************************
; set sequence position
;
; a=position
;********************************************************
Module_ChangePosition:
mov y, a
_skip_pattern:
mov a, !MODULE+MOD_SEQU+y
cmp a, #254 ; skip +++
bne _not_plusplusplus ;
inc y ;
bra _skip_pattern ;
_not_plusplusplus:
cmp a, #255 ; restart on ---
bne _not_end ;
mov y, #0 ;
bra _skip_pattern ;
_not_end:
mov mod_position, y
mov y, a
mov a, !MODULE+MOD_PTABLE_L+y
mov patt_addr, a
mov a, !MODULE+MOD_PTABLE_H+y
mov patt_addr+1, a
mov y, #0
mov a, [patt_addr]+y
mov patt_rows, a
incw patt_addr
mov pattjump_enable, #0
mov mod_tick, #0
mov mod_row, #0
ret
;********************************************************
; a = new BPM value
;********************************************************
Module_ChangeTempo:
push x
mov mod_bpm, a
mov SPC_CONTROL, #%110
mov x, a
mov y, #50h
mov a, #00h
div ya, x
mov SPC_TIMER0, a
pop x
ret
;********************************************************
; process module fading
;********************************************************
ProcessFade:
mov a, SPC_COUNTER1
beq _skipfade
or STATUS, #STATUS_F
mov a, module_vol
cmp a, module_fadeT
beq _nofade
bcc _fadein
;--------------------------------------------
_fadeout:
;--------------------------------------------
sbc a, module_fadeR
bcs _fade_satL
mov module_vol, module_fadeT
ret
_fade_satL:
cmp a, module_fadeT
bcs _fadeset
mov module_vol, module_fadeT
ret
;--------------------------------------------
_fadein:
;--------------------------------------------
adc a, module_fadeR
bcc _fade_satH
mov module_vol, module_fadeT
ret
_fade_satH:
cmp a, module_fadeT
bcc _fadeset
mov module_vol, module_fadeT
ret
_fadeset:
mov module_vol, a
ret
_nofade:
and STATUS, #~STATUS_F
_skipfade:
ret
;********************************************************
; Update module playback
;
;********************************************************
Module_Update:
mov a, mod_active
beq _no_tick
mov a, SPC_COUNTER0 ; check for a tick
beq _no_tick ;
call Module_OnTick ;
_no_tick: ;
ret ;
;********************************************************
; module tick!!!
;********************************************************
Module_OnTick:
cmp mod_tick, #0
bne _skip_read_pattern
call Module_ReadPattern
_skip_read_pattern:
call Module_UpdateChannels
inc mod_tick ; increment tick until >= SPEED
cmp mod_tick, mod_speed ;
bcc _exit_tick ;
mov mod_tick, #0 ;
cmp pattjump_enable, #0 ; catch pattern jump...
beq _no_pattjump ;
mov a, pattjump_index ;
jmp Module_ChangePosition ;
_no_pattjump: ;
inc mod_row ; increment row until > PATTERN_ROWS
beq _adv_pos
cmp mod_row, patt_rows ;
beq _exit_tick
bcc _exit_tick ;
_adv_pos:
mov a, mod_position ; advance position
inc a ;
jmp Module_ChangePosition ;
_exit_tick:
ret
;********************************************************
; read pattern data
;********************************************************
Module_ReadPattern:
mov y, #1 ; skip hints
mov a, [patt_addr]+y ; copy update flags
inc y ;
mov patt_update, a ;
mov m1, a ;
mov x, #0
lsr m1 ; test first bit
bcc _no_channel_data ;
_read_pattern_data:
SPROC
mov a, [patt_addr]+y ; read maskvar
inc y ;
mov m0, a ;
bbc4 m0, _skip_read_note ; test/read new note
mov a, [patt_addr]+y ;
inc y ;
mov ch_note+x, a ;
_skip_read_note: ;
bbc5 m0, _skip_read_instr ; test/read new instrument
mov a, [patt_addr]+y ;
inc y ;
mov ch_instr+x, a ;
_skip_read_instr: ;
bbc6 m0, _skip_read_vcmd ; test/read new vcmd
mov a, [patt_addr]+y ;
inc y ;
mov ch_vcmd+x, a ;
_skip_read_vcmd: ;
bbc7 m0, _skip_read_cmd ; test/read new cmd+param
mov a, [patt_addr]+y ;
inc y ;
mov ch_command+x, a ;
mov a, [patt_addr]+y ;
inc y ;
mov ch_param+x, a ;
_skip_read_cmd: ;
and m0, #0Fh ; set flags (lower nibble)
mov a, ch_flags+x ;
and a, #0F0h ;
or a, m0 ;
mov ch_flags+x, a ;
_no_channel_data: ;
_rp_nextchannel:
inc x ; increment index
lsr m1 ; shift out next bit
bcs _read_pattern_data ; process if set
bne _no_channel_data ; loop if bits remain (upto 8 iterations)
;-------------------------------
mov m0, y ; add offset to pattern address
clrc ;
adc patt_addr, m0 ;
adc patt_addr+1, #0 ;
ret
BITS:
.byte 1, 2, 4, 8, 16, 32, 64, 128
;********************************************************
; update module channels...
;********************************************************
Module_UpdateChannels:
mov x, #0
mov a, patt_update
_muc_loop:
lsr a
push a
mov a, #0
rol a
mov t_hasdata, a
call Module_UpdateChannel
pop a
inc x
cmp x, #8
bne _muc_loop
ret
;********************************************************
; update module channel
;********************************************************
Module_UpdateChannel:
SPROC
;--------------------------------------
; get data pointers
;--------------------------------------
mov y, ch_instr+x
dec y
mov a, !MODULE+MOD_ITABLE_L+y
mov p_instr, a
mov a, !MODULE+MOD_ITABLE_H+y
mov p_instr+1, a
mov t_flags, #0
cmp t_hasdata, #0
beq _muc_nopatterndata
call Channel_ProcessData
bra _muc_pa
_muc_nopatterndata:
call Channel_CopyTemps
_muc_pa:
call Channel_ProcessAudio
ret
;********************************************************
Channel_ProcessData:
;********************************************************
cmp mod_tick, #0 ; skip tick0 processing on other ticks
bne _cpd_non0 ;
mov a, ch_flags+x
mov m6, a
bbc0 m6, _cpd_no_note ; test for note
mov a, ch_note+x ;
cmp a, #254 ; test notecut/noteoff
beq _cpd_notecut ;
bcs _cpd_noteoff ;
_cpd_note: ; dont start note on glissando
bbc3 m6, _cpdn_test_for_glis ;
mov a, ch_command+x ;
cmp a, #7 ;
beq _cpd_note_next ;
_cpdn_test_for_glis: ;
;
call Channel_StartNewNote ;
bra _cpd_note_next ;
_cpd_notecut: ;notecut:
mov a, #0 ; cut volume
mov ch_volume+x, a ;
and m6, #~CF_NOTE ; clear note flag
bra _cpd_note_next ;
_cpd_noteoff: ;noteoff:
and m6, #~(CF_NOTE|CF_KEYON); clear note and keyon flags
_cpd_note_next:
bbc1 m6, _cpdn_no_instr ; apply instrument SETPAN
mov y, #INS_SETPAN ;
mov a, [p_instr]+y ;
bmi _cpdi_nsetpan ;
mov ch_panning+x, a ;
_cpdi_nsetpan: ;
mov y, ch_sample+x ; apply sample SETPAN
; beq _cpdi_nosample ;
mov a, !MODULE+MOD_STABLE_L+y ;
mov m0, a ;
mov a, !MODULE+MOD_STABLE_H+y ;
mov m0+1, a ;
mov y, #SAMP_DVOL ; copy default volume
mov a, [m0]+y ;
mov ch_volume+x, a ;
mov y, #SAMP_SETPAN ;
mov a, [m0]+y ;
bmi _cpdi_nsetpan_s ;
mov ch_panning+x, a ;
_cpdi_nsetpan_s:
_cpdi_nosample:
_cpdn_no_instr:
and m6, #~CF_NOTE
_cpd_no_note: ;
mov a, m6 ; save flag mods
mov ch_flags+x, a ;
and a, #(CF_NOTE|CF_INSTR) ; test for note or instrument
beq _no_note_or_instr ;
call Channel_ResetVolume ; and reset volume things
_no_note_or_instr: ;
_cpd_non0: ; nonzero ticks: just update audio
SPROC
mov a, ch_flags+x ; test and process volume command
and a, #CF_VCMD ;
beq _skip_vcmd ;
call Channel_ProcessVolumeCommand
_skip_vcmd:
SPROC
call Channel_CopyTemps ; copy t values
mov a, ch_flags+x ; test and process command
and a, #CF_CMD ;
beq _skip_cmd ;
call Channel_ProcessCommand ;
_skip_cmd:
ret
;********************************************************
Channel_CopyTemps:
;********************************************************
mov a, ch_pitch_l+x ; prepare for effects processing.....
mov y, ch_pitch_h+x ;
movw t_pitch, ya ;
mov a, ch_volume+x ;
mov y, ch_panning+x ;
movw t_volume, ya ;
mov t_sampoff, #0 ;
ret
;********************************************************
Channel_StartNewNote:
;********************************************************
mov a, ch_note+x ; pitch = note * 64
mov y, #64 ;
mul ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, y ;
mov a, ch_instr+x ; test for instrument and copy sample!
beq _csnn_no_instr ;
mov y, #INS_SAMPLE ;
mov a, [p_instr]+y ;
mov ch_sample+x, a ;
_csnn_no_instr:
or t_flags, #TF_START ; set start flag
ret
;********************************************************
Channel_ResetVolume:
;********************************************************
mov a, #255 ; reset fadeout
mov ch_fadeout+x, a ;----------------
mov a, #0 ; reset envelope
mov ch_env_node+x, a ;
mov ch_env_tick+x, a ;----------------
mov ch_cmem+x, a ; reset CMem
;----------------
mov a, ch_flags+x ; set KEYON
or a, #CF_KEYON ; clear FADE
and a, #~CF_FADE ;
mov ch_flags+x, a ;----------------
ret
;********************************************************
Channel_ProcessAudio:
;********************************************************
SPROC
mov y, ch_sample+x ; m5 = sample address
; beq _cpa_nsample ;
mov a, !MODULE+MOD_STABLE_L+y ;
mov m5, a ;
mov a, !MODULE+MOD_STABLE_H+y ;
mov m5+1, a ;
_cpa_nsample: ;
call Channel_ProcessEnvelope
mov a, ch_flags+x ; process FADE
and a, #CF_FADE ;
beq _skip_fade ;
mov a, ch_fadeout+x ;
setc ;
mov y, #INS_FADEOUT ;
sbc a, [p_instr]+y ;
bcs _subfade_noverflow ;
mov a, #0 ;
_subfade_noverflow: ;
mov ch_fadeout+x, a ;
_skip_fade: ;
mov a, !BITS+x
and a, sfx_mask
bne _sfx_override
mov a, t_flags ; exit if 'note delay' is set
and a, #TF_DELAY ;
beq _cpa_ndelay ;
_sfx_override:
ret ;
_cpa_ndelay: ;
;----------------------------------------
; COMPUTE VOLUME:
; V*CV*SV*GV*VEV*FADE
; m0 = result (0..255)
;----------------------------------------
mov y, #INS_GVOL
mov a, [p_instr]+y
push a
mov y, #SAMP_GVOL
mov a, [m5]+y
push a
mov a, t_volume ; y = 8-BIT VOLUME
asl a ;
asl a ;
bcc _cpa_clamp_vol ;
mov a, #255 ;
_cpa_clamp_vol ;
mov y, a ;
mov a, ch_cvolume+x ; *= CV
asl a ;
asl a
bcs _calcvol_skip_cv ;
mul ya ;
_calcvol_skip_cv: ;
pop a ; *= SV
asl a ;
asl a
bcs _calcvol_skip_sv ;
mul ya ;
_calcvol_skip_sv: ;
pop a ;
asl a ;
bcs _calcvol_skip_iv ;
mul ya ;
_calcvol_skip_iv:
mov a, mod_gvol ; *= GV
asl a ;
bcs _calcvol_skip_gvol ;
mul ya ;
_calcvol_skip_gvol: ;
mov a, t_env ; *= VEV
mul ya ;
mov a, ch_fadeout+x ; *= FADE
mul ya ;
mov a, module_vol
mul ya
mov a, y ; store 7bit result
lsr a ;
mov m2, a
cmp t_flags, #80h
bcs _dont_hack_gain
cmp a, #0
bne _gain_not_zero ; map value 0 to fast linear decrease
mov a, #%10011100 ; (8ms)
_gain_not_zero: ;
cmp a, #127 ; map value 127 to fast linear increase
bne _gain_not_max ; (8ms)
mov a, #%11011100 ;
_gain_not_max: ;
mov m2, a ;
_dont_hack_gain:
;---------------------------------------
; compute PANNING
;---------------------------------------
mov a, t_panning ; a = panning 0..127
asl a ;
bpl _clamppan ;
dec a ;
_clamppan: ;
mov m1+1, a ; store panning (volume) levels
eor a, #127 ;
mov m1, a ;
mov a, ch_flags+x ; apply surround (R = -R)
and a, #CF_SURROUND ;
beq _cpa_nsurround ;
eor m1+1, #255 ;
inc m1+1 ;
_cpa_nsurround: ;
;---------------------------------------
; compute PITCH
;---------------------------------------
cmp x, #1
mov y, #SAMP_PITCHBASE ; m3 = t_pitch PITCHBASE
mov a, [m5]+y ;
clrc ;
adc a, t_pitch_l ;
mov m3, a ;
inc y ;
mov a, [m5]+y ;
adc a, t_pitch_h ;
mov m3+1, a ;
mov y, a ; m0 = octave
mov a, !LUT_DIV3+y ;
mov m0, a ;
asl a ; m3 -= (oct*3) << 8
adc a, m0 ;
mov m0+1, a ;
mov a, m3+1 ;
setc ;
sbc a, m0+1 ;
asl m3 ; m3 = m3*2 + LUT_FTAB base
rol a ;
adc m3, #(LUT_FTAB&0FFh) ;
adc a, #(LUT_FTAB>>8) ;
mov m3+1, a ;
mov y, #0 ; read ftab[f]
mov a, [m3]+y ;
mov m4, a ;
inc y ;
mov a, [m3]+y ;
push a ;
mov a, #8 ; y = 8-oct
setc ;
sbc a, m0 ;
mov y, a ;
pop a ; a,m4 = ftab value
beq _no_pitch_shift ; skip shift if 0
lsr a ; shift by (8-oct)
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
dec y ;
beq _no_pitch_shift ;
lsr a ;
ror m4 ;
_no_pitch_shift:
mov m4+1, a
;----------------------------------------
; m1 = VOL/VOLR
; m2 = GAIN
; m4 = PITCH
;----------------------------------------
mov a, x ; DSPA = voices[x]
xcn a ;
mov SPC_DSPA, a ;
;------------------------------
mov a, t_flags ; test for KEYON
and a, #TF_START ;
beq _cpa_nstart ;------------------------------
;keyon:
mov y, #SAMP_DINDEX ; set SRCN
mov a, [m5]+y ;
or SPC_DSPA, #DSPV_SRCN ;
mov SPC_DSPD, a ;------------------------------
;----------------------------------------
; **TODO: SAMPLE OFFSET
;----------------------------------------
mov SPC_DSPA, #DSP_KON ; set KON bit
mov a, !BITS+x ;
mov SPC_DSPD, a ;------------------------------
mov a, x ; restore DSPA = voices[x]
xcn a ;
mov SPC_DSPA, a ;
;------------------------------------------------
_cpa_nstart:
;------------------------------------------------
mov SPC_DSPD, m1 ; set VOLUME
inc SPC_DSPA ;
mov SPC_DSPD, m1+1 ;
inc SPC_DSPA ;------------------------------
mov SPC_DSPD, m4 ; set PITCH
inc SPC_DSPA ;
mov SPC_DSPD, m4+1 ;
inc SPC_DSPA ;
inc SPC_DSPA ;------------------------------
mov SPC_DSPD, #00h ; disable ADSR
or SPC_DSPA, #07h ; set GAIN
mov SPC_DSPD, m2 ;------------------------------
;----------------------------------------
; **TODO: RESTORE SAMPLE OFFSET
;----------------------------------------
SPROC
ret
;********************************************************
Channel_ProcessEnvelope:
;********************************************************
mov y, #INS_ENVLEN ; test for envelope
mov a, [p_instr]+y ;
mov m0, a
bne _envelope_valid ;if no envelope:
mov t_env, #255 ; set to max
mov a, ch_flags+x ; start fade on KEYOFF
and a, #CF_KEYON ;
beq _env_quit ;
jmp _env_setfade ;
_env_quit:
ret ;
_envelope_valid: ;
mov a, ch_env_node+x ; read envelope node data
clrc ; m1/m2
adc a, #INS_ENVDATA ;
mov y, a ;
mov a, [p_instr]+y ;
mov m1, a ;
inc y ;
mov a, [p_instr]+y ;
mov m1+1, a ;
inc y ;
mov a, [p_instr]+y ;
mov m2, a ;
inc y ;
mov a, [p_instr]+y ;
mov m2+1, a ;
SPROC
mov a, ch_env_tick+x ; test zero/nonzero tick
bne _env_nonzero_tick ;
;ZEROTICK:
mov a, m1 ; copy Y level
mov ch_env_y_h+x, a ;
mov a, #0 ;
mov ch_env_y_l+x, a ;
bra _env_zerotick ;
_env_nonzero_tick: ;NONZERO:
mov a, ch_env_y_l+x
clrc
adc a, m2
mov ch_env_y_l+x, a
mov a, ch_env_y_h+x
adc a, m2+1
bpl _catch_negative ; clamp result 0.0->64.0
mov a, #0 ;
mov ch_env_y_h+x, a ;
mov ch_env_y_l+x, a ;
bra _env_zerotick ;
_catch_negative: ;
cmp a, #64 ;
bcc _catch_plus ;
mov a, #64 ;
mov ch_env_y_h+x, a ;
mov a, #0 ;
mov ch_env_y_l+x, a ;
bra _env_zerotick ;
_catch_plus: ;
;
mov ch_env_y_h+x, a ;
_env_zerotick:
mov a, ch_env_y_l+x ; t_env = env << 2
mov m1, a ;
mov a, ch_env_y_h+x ;
asl m1 ;
rol a ;
asl m1 ;
rol a ;
bcc _env_shift_clamp ; clamp to 255
mov a, #255 ;
_env_shift_clamp: ;
mov t_env, a ;
mov a, ch_flags+x ; dont advance if "keyon" and node=sustain
and a, #CF_KEYON ;
beq _env_nsustain ;
mov y, #INS_ENVSUS ;
mov a, [p_instr]+y ;
cmp a, ch_env_node+x ;
bne _env_nsustain ;
ret ;
_env_nsustain: ;
inc ch_env_tick+x ; increment tick
mov a, ch_env_tick+x ;
cmp a, m1+1 ; exit if < duration
bcc _env_exit ;
mov a, #0 ; reset tick
mov ch_env_tick+x, a ;
mov y, #INS_ENVLOOPEND ; turn on FADE if keyoff and loop
mov a, [p_instr]+y ;
cmp a, #255 ;
beq _env_no_loop ;
mov a, ch_flags+x ;
and a, #CF_KEYON ;
bne _env_no_fade ;
mov a, ch_flags+x ;
or a, #CF_FADE ;
mov ch_flags+x, a ;
_env_no_fade:
mov a, ch_env_node+x ; test for loop point
; mov y, #INS_ENVLOOPEND ;
cmp a, [p_instr]+y ;
bne _env_loop_test ;
mov y, #INS_ENVLOOPST
mov a, [p_instr]+y
mov ch_env_node+x, a
ret
_env_loop_test: ;
_env_no_loop:
mov a, ch_env_node+x
setc ; suspicious...
sbc m0, #4
cmp a, m0 ; test for envelope end
beq _env_setfade ;
clrc ; increment node
adc a, #4 ;
mov ch_env_node+x, a ;
ret
_env_setfade:
mov a, ch_flags+x
or a, #CF_FADE
mov ch_flags+x, a
_env_exit: ;
ret
;********************************************************
Channel_ProcessVolumeCommand:
;********************************************************
mov a, ch_volume+x
mov y, ch_vcmd+x
mov m0, y
call do_vcmd
mov ch_volume+x, a
ret
do_vcmd:
cmp y, #65
bcc vcmd_setvol
cmp y, #75
bcc vcmd_finevolup
cmp y, #85
bcc vcmd_finevoldown
cmp y, #95
bcc vcmd_volup
cmp y, #105
bcc vcmd_voldown
cmp y, #193
bcs vcmd_invalid
cmp y, #128
bcs vcmd_pan
vcmd_invalid:
ret
;--------------------------------------------------------
; 00-64 set volume
;--------------------------------------------------------
vcmd_setvol:
cmp mod_tick, #0 ; a = volume
bne exit_vcmd ;
mov a, y ;
exit_vcmd: ;
ret ;
;--------------------------------------------------------
; 65-74 fine vol up
;--------------------------------------------------------
vcmd_finevolup:
sbc m0, #65 ; m0 = rate (-1)
cmp mod_tick, #0
bne exit_vcmd
_vcmd_add_sat64
adc a, m0 ; a += rate (+1)
cmp a, #65 ; saturate to 64
bcc exit_vcmd ;
mov a, #64 ;
ret ;
;--------------------------------------------------------
; 75-84 fine vol down
;--------------------------------------------------------
vcmd_finevoldown:
sbc m0, #75-1 ; m0 = rate [carry is cleared]
cmp mod_tick, #0
bne exit_vcmd
_vcmd_sub_sat0:
sbc a, m0 ; a -= rate
bcs exit_vcmd ; saturate lower bound to 0
mov a, #0 ;
ret ;
;--------------------------------------------------------
; 85-94 vol up
;--------------------------------------------------------
vcmd_volup:
sbc m0, #85 ; m0 = rate (-1)
cmp mod_tick, #0
beq exit_vcmd
bra _vcmd_add_sat64
;--------------------------------------------------------
; 95-104 vol down
;--------------------------------------------------------
vcmd_voldown:
sbc m0, #95-1
cmp mod_tick, #0
beq exit_vcmd
bra _vcmd_sub_sat0
;--------------------------------------------------------
; 128-192 set pan
;--------------------------------------------------------
vcmd_pan:
cmp mod_tick, #0 ; set panning
bne exit_vcmd ;
push a ;
mov a, y ;
sbc a, #128 ;
mov ch_panning+x, a ;
pop a ;
ret ;
command_memory_map:
.byte 00h, 00h, 00h, 10h, 20h, 20h, 30h, 70h, 00h
; A B C D E F G H I
.byte 40h, 10h, 10h, 00h, 10h, 50h, 10h, 80h, 70h
; J K L M N O P Q R
.byte 60h, 00h, 70h, 00h, 10h, 00h, 70h, 00h
; S T U V W X Y Z
;********************************************************
Channel_ProcessCommandMemory:
;********************************************************
mov y, ch_command+x
mov a, !command_memory_map-1+y
beq _cpc_quit ; 0 = no memory!
mov m0, x
clrc
adc a, m0
mov y, a
cmp y, #70h ; <7 : single param
bcc _cpcm_single ;
;--------------------------------------------------------
_cpcm_double: ; >=7: double param
;--------------------------------------------------------
mov a, !PatternMemory-10h+y
mov m0, a
mov a, ch_param+x
cmp a, #10h
bcc _cpcmd_h_clr
push a
and m0, #0Fh
or a, m0
mov m0, a
pop a
_cpcmd_h_clr:
and a, #0Fh
beq _cpcmd_l_clr
and m0, #0F0h
or a, m0
mov m0, a
_cpcmd_l_clr:
mov a, m0
mov ch_param+x, a
mov !PatternMemory-10h+y, a
ret
;--------------------------------------------------------
_cpcm_single:
;--------------------------------------------------------
mov a, ch_param+x
beq _cpcms_clear
mov !PatternMemory-10h+y, a
ret
_cpcms_clear:
mov a, !PatternMemory-10h+y
mov ch_param+x, a
_cpc_quit:
ret
;********************************************************
Channel_ProcessCommand:
;********************************************************
mov a, ch_command+x ; exit if cmd = 0
beq _cpc_quit ;
cmp mod_tick, #0 ; process MEMORY on t0
bne _cpc_nott0 ;
call Channel_ProcessCommandMemory
_cpc_nott0:
mov y, ch_command+x ; setup jump address
mov a, !CMD_JUMPTABLE_L-1+y ;
mov !cpc_jump+1, a ;
mov a, !CMD_JUMPTABLE_H-1+y ;
mov !cpc_jump+2, a ;
mov a, ch_param+x ; preload data
mov y, mod_tick ;
;-------------------------------
; a = param
; y = tick
; Z = tick=0
;-------------------------------
cpc_jump:
jmp $0011
; note: tasm has some kind of bug that removes the 16th character
; in macro args (...?)
;-----------------------------------------------------------------------
CMD_JUMPTABLE_L:
;-----------------------------------------------------------------------
.byte LBYTE(Command_SetSpeed) ; Axx
.byte LBYTE(Command_SetPositiion) ; Bxx
.byte LBYTE(Command_PatternBrreak) ; Cxx
.byte LBYTE(Command_VolumeSliide) ; Dxy
.byte LBYTE(Command_PitchSliddeDown) ; Exy
.byte LBYTE(Command_PitchSliddeUp) ; Fxy
.byte LBYTE(Command_Glissandoo) ; Gxx
.byte LBYTE(Command_Vibrato) ; Hxy
.byte LBYTE(Command_Tremor) ; Ixy
.byte LBYTE(Command_Arpeggio) ; Jxy
.byte LBYTE(Command_VolumeSliideVibrato) ; Kxy
.byte LBYTE(Command_VolumeSliideGliss) ; Lxy
.byte LBYTE(Command_SetChanneelVolume) ; Mxx
.byte LBYTE(Command_ChannelVoolumeSlide) ; Nxy
.byte LBYTE(Command_SampleOfffset) ; Oxx
.byte LBYTE(Command_PanningSllide) ; Pxy
.byte LBYTE(Command_RetriggerrNote) ; Qxy
.byte LBYTE(Command_Tremolo) ; Rxy
.byte LBYTE(Command_Extended) ; Sxy
.byte LBYTE(Command_Tempo) ; Txy
.byte LBYTE(Command_FineVibraato) ; Uxy
.byte LBYTE(Command_SetGloballVolume) ; Vxx
.byte LBYTE(Command_GlobalVollumeSlide) ; Wxy
.byte LBYTE(Command_SetPanninng) ; Xxx
.byte LBYTE(Command_Panbrelloo) ; Yxy
.byte LBYTE(Command_MidiMacroo) ; Zxy
;-----------------------------------------------------------------------
CMD_JUMPTABLE_H:
;-----------------------------------------------------------------------
.byte HBYTE(Command_SetSpeed) ; Axx
.byte HBYTE(Command_SetPositiion) ; Bxx
.byte HBYTE(Command_PatternBrreak) ; Cxx
.byte HBYTE(Command_VolumeSliide) ; Dxy
.byte HBYTE(Command_PitchSliddeDown) ; Exy
.byte HBYTE(Command_PitchSliddeUp) ; Fxy
.byte HBYTE(Command_Glissandoo) ; Gxx
.byte HBYTE(Command_Vibrato) ; Hxy
.byte HBYTE(Command_Tremor) ; Ixy
.byte HBYTE(Command_Arpeggio) ; Jxy
.byte HBYTE(Command_VolumeSliideVibrato) ; Kxy
.byte HBYTE(Command_VolumeSliideGliss) ; Lxy
.byte HBYTE(Command_SetChanneelVolume) ; Mxx
.byte HBYTE(Command_ChannelVoolumeSlide) ; Nxy
.byte HBYTE(Command_SampleOfffset) ; Oxx
.byte HBYTE(Command_PanningSllide) ; Pxy
.byte HBYTE(Command_RetriggerrNote) ; Qxy
.byte HBYTE(Command_Tremolo) ; Rxy
.byte HBYTE(Command_Extended) ; Sxy
.byte HBYTE(Command_Tempo) ; Txy
.byte HBYTE(Command_FineVibraato) ; Uxy
.byte HBYTE(Command_SetGloballVolume) ; Vxx
.byte HBYTE(Command_GlobalVollumeSlide) ; Wxy
.byte HBYTE(Command_SetPanninng) ; Xxx
.byte HBYTE(Command_Panbrelloo) ; Yxy
.byte HBYTE(Command_MidiMacroo) ; Zxy
;=======================================================================
Command_SetSpeed:
;=======================================================================
bne cmd_exit1 ;on tick0:
cmp a, #0 ; if param != 0
beq cmd_exit1 ; mod_speed = param
mov mod_speed, a ;
cmd_exit1: ;
ret ;
;=======================================================================
Command_SetPosition:
;=======================================================================
bne cmd_exit1 ;on tick0:
mov pattjump_index, a ; set jump index
mov pattjump_enable, #1 ; enable pattern jump
ret ;
;=======================================================================
Command_PatternBreak:
;=======================================================================
; nonzero params are not supported
;
bne cmd_exit1 ;on tick0:
mov pattjump_index, mod_position ; index = position+1
inc pattjump_index ; enable pattern jump(break)
mov pattjump_enable, #1 ;
ret
;=======================================================================
Command_VolumeSlide:
;=======================================================================
mov m0, t_volume ; slide volume
mov m0+1, #64 ;
call DoVolumeSlide ;
mov t_volume, a ;
mov ch_volume+x, a ;
ret ;
;=======================================================================
Command_PitchSlideDown:
;=======================================================================
call PitchSlide_Load ; m0 = slide amount
movw ya, t_pitch ; pitch -= m0
subw ya, m0 ;
bmi _exx_zero ; saturate lower to 0
movw t_pitch, ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, y ;
ret ;
;---------------------------------------------------------------------
_exx_zero:
;---------------------------------------------------------------------
mov a, #0 ; zero pitch
mov y, #0 ;
movw t_pitch, ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, a ;
ret ;
;=======================================================================
Command_PitchSlideUp:
;=======================================================================
call PitchSlide_Load ; m0 = slide amount
movw ya, t_pitch ;
addw ya, m0 ;
cmp y, #01Ah ;
bcs _fxx_max ; clamp upper bound to 1A00H
movw t_pitch, ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, y ;
ret ;
;-----------------------------------------------------------------------
_fxx_max:
;-----------------------------------------------------------------------
mov y, #01Ah ; max pitch
mov a, #0 ;
movw t_pitch, ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, y ;
ret ;
;=======================================================================
Command_Glissando:
;=======================================================================
beq cmd_exit1 ; on tickn:
mov m0+1, #0 ; m0 = xx*4 (slide amount)
asl a ;
rol m0+1 ;
asl a ;
rol m0+1 ;
mov m0, a ;
mov a, ch_note+x ; m1 = slide target
mov m1, #0 ;
lsr a ;
ror m1 ;
lsr a ;
ror m1 ;
mov m1+1, a ;
movw ya, t_pitch ; test slide direction
cmpw ya, m1 ;
bcc _gxx_slideup
;-----------------------------------------------
_gxx_slidedown:
;-----------------------------------------------
subw ya, m0 ; subtract xx*4 from pitch
bmi _gxx_set ; saturate lower to target pitch
cmpw ya, m1 ;
bcc _gxx_set ;
_gxx_set2: ;
movw t_pitch, ya ;
mov ch_pitch_l+x, a ;
mov ch_pitch_h+x, y ;
ret ;
;-----------------------------------------------
_gxx_slideup:
;-----------------------------------------------
addw ya, m0 ; add xx*4 to pitch
cmpw ya, m1 ; saturate upper to target pitch
bcs _gxx_set ;
bra _gxx_set2 ;
;-----------------------------------------------
_gxx_set: ; pitch = target
;-----------------------------------------------
movw ya, m1 ;
bra _gxx_set2 ;
;=======================================================================
Command_Vibrato:
;=======================================================================
mov a, #70h
mov m0, x
clrc
adc a, m0
mov y, a
mov a, !PatternMemory-10h+y
mov m0, a
and m0, #0Fh
lsr a ; cmem += x*4
lsr a ;
and a, #111100b ;
clrc ;
adc a, ch_cmem+x ;
mov ch_cmem+x, a ;
mov y, a ; a = sine[cmem]
mov a, !IT_FineSineData+y ;
bpl _hxx_plus
_hxx_neg:
eor a, #255
inc a
mov y, m0
mul ya
mov m0+1, y
lsr m0+1
ror a
lsr m0+1
ror a
lsr m0+1
ror a
lsr m0+1
ror a
mov m0, a
movw ya, t_pitch
subw ya, m0
bmi _hxx_zero
movw t_pitch, ya
ret
_hxx_plus:
mov y, m0
mul ya
mov m0+1, y
lsr m0+1
ror a
lsr m0+1
ror a
lsr m0+1
ror a
lsr m0+1
ror a
mov y, m0+1
addw ya, t_pitch ; warning: might break something on highest note
movw t_pitch, ya
ret
_hxx_zero:
mov t_pitch, #0
mov t_pitch+1, #0
ret
;=======================================================================
Command_Tremor: ; unimplemented
;=======================================================================
ret
;=======================================================================
Command_Arpeggio:
;=======================================================================
bne _jxx_other
mov a, #0
mov ch_cmem+x, a
ret
_jxx_other:
mov a, ch_cmem+x
inc a
cmp a, #3
bcc _jxx_less3
mov a, #0
_jxx_less3:
mov ch_cmem+x, a
cmp a, #1
beq _jxx_x
bcs _jxx_y
ret
_jxx_x:
mov a, ch_param+x
_jxx_add:
and a, #0F0h
asl a
mov m0+1, #0
rol m0+1
asl a
rol m0+1
mov m0, a
movw ya, t_pitch
addw ya, m0
movw t_pitch, ya
ret
_jxx_y:
mov a, ch_param+x
xcn a
bra _jxx_add
;=======================================================================
Command_VolumeSlideVibrato:
;=======================================================================
call Command_Vibrato
mov a, ch_param+x
mov y, mod_tick
mov m0, t_volume ; slide volume
mov m0+1, #64 ;
call DoVolumeSlide ;
mov t_volume, a ;
mov ch_volume+x, a ;
cmd_exit2:
ret ;
;=======================================================================
Command_VolumeSlideGliss: ; unimplemented
;=======================================================================
ret
;=======================================================================
Command_SetChannelVolume:
;=======================================================================
bne cmd_exit2 ; on tick0:
cmp a, #65 ; cvolume = param > 64 ? 64 : param
bcc cscv_under65 ;
mov a, #64 ;
cscv_under65: ;
mov ch_cvolume+x, a ;
ret ;
;=======================================================================
Command_ChannelVolumeSlide:
;=======================================================================
mov a, ch_cvolume+x ; slide channel volume
mov m0, a ;
mov m0+1, #64 ;
mov a, ch_param+x ;
call DoVolumeSlide ;
mov ch_cvolume+x, a ;
ret ;
;=======================================================================
Command_SampleOffset:
;=======================================================================
bne cmd_exit2 ; on tick0:
mov t_sampoff, a ; set sampoff data
ret ;
;=======================================================================
Command_PanningSlide:
;=======================================================================
xcn a
mov m0, t_panning ; slide panning
mov m0+1, #64 ;
call DoVolumeSlide ;
mov t_panning, a ;
mov ch_panning+x, a ;
ret ;
;=======================================================================
Command_RetriggerNote:
;=======================================================================
and a, #0Fh ; m0 = y == 0 ? 1 : x
bne _crn_x1 ;
inc a ;
_crn_x1: ;
mov m0, a ;
mov a, ch_cmem+x ;if cmem is 0:
bne _crn_cmem_n0 ; cmem = m0
mov a, m0 ;
_crn_count_ret:
mov ch_cmem+x, a ;
ret ;
_crn_cmem_n0: ;else:
dec a ; dec cmem until 0
bne _crn_count_ret ;
;RETRIGGER NOTE:
mov a, m0 ; cmem = m0
mov ch_cmem+x, a ;
;----------------------------------------
; affect volume
;----------------------------------------
mov a, ch_param+x
xcn a
and a, #0Fh
mov m1, a
asl a
push x
mov x, a
mov a, t_volume
clrc
jmp [rnvtable+x]
rnvtable:
.word rnv_0
.word rnv_1
.word rnv_2
.word rnv_3
.word rnv_4
.word rnv_5
.word rnv_6
.word rnv_7
.word rnv_8
.word rnv_9
.word rnv_A
.word rnv_B
.word rnv_C
.word rnv_D
.word rnv_E
.word rnv_F
rnv_1: dec a
bra _rnv_sat0
rnv_2: sbc a, #2-1
bra _rnv_sat0
rnv_3: sbc a, #4-1
bra _rnv_sat0
rnv_4: sbc a, #8-1
bra _rnv_sat0
rnv_5: sbc a, #16-1
bra _rnv_sat0
rnv_6: mov y, #170
mul ya
mov a, y
bra _rnv_set
rnv_7: lsr a
bra _rnv_set
rnv_8:
rnv_0: bra _rnv_set
rnv_9: inc a
bra _rnv_sat64
rnv_A: adc a, #2
bra _rnv_sat64
rnv_B: adc a, #4
bra _rnv_sat64
rnv_C: adc a, #8
bra _rnv_sat64
rnv_D: adc a, #16
bra _rnv_sat64
rnv_E: mov y, #3
mul ya
lsr a
bra _rnv_sat64
rnv_F: asl a
bra _rnv_sat64
_rnv_sat0:
bpl _rnv_set
mov a, #0
bra _rnv_set
_rnv_sat64:
cmp a, #65
bcc _rnv_set
mov a, #64
_rnv_set:
pop x
mov t_volume, a
mov ch_volume+x, a
or t_flags, #TF_START
ret
;=======================================================================
Command_Tremolo: ; unimplemented
;=======================================================================
ret
;=======================================================================
Command_Extended:
;=======================================================================
xcn a ; setup jump to:
and a, #0Fh ; CmdExTab[x]
mov y, a ;
mov a, !CmdExTab_L+y ;
mov !cmdex_jmp+1, a ;
mov a, !CmdExTab_H+y ;
mov !cmdex_jmp+2, a ;
mov a, ch_param+x ; a = y
and a, #0Fh ; y = tick
mov y, mod_tick ; z = tick0
cmdex_jmp:
jmp 0a0bh
SCommand_Null:
ret
CmdExTab_L:
.byte LBYTE(SCommand_Echo)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Panning)
.byte LBYTE(SCommand_SoundCo ntrol)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_NoteCut)
.byte LBYTE(SCommand_NoteDelXay)
.byte LBYTE(SCommand_Null)
.byte LBYTE(SCommand_Cue)
CmdExTab_H:
.byte HBYTE(SCommand_Echo)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Panning)
.byte HBYTE(SCommand_SoundCo ntrol)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_NoteCut)
.byte HBYTE(SCommand_NoteDelXay)
.byte HBYTE(SCommand_Null)
.byte HBYTE(SCommand_Cue)
; S01 = turn on echo
; S02 = turn off echo
; S03 = turn on echo for all
; S04 = turn off echo for all
;=======================================================================
SCommand_Echo:
;=======================================================================
mov SPC_DSPA, #DSP_EON
cmp a, #1
beq _sce_enable_one
bcc cmd_exit3
cmp a, #3
bcc _sce_disable_one
beq _sce_disable_all
cmp a, #4
beq _sce_enable_all
cmd_exit3:
ret
_sce_enable_one:
mov a, !BITS+x
or a, SPC_DSPD
mov SPC_DSPD, a
ret
_sce_disable_one:
mov a, !BITS+x
eor a, #255
and a, SPC_DSPD
mov SPC_DSPD, a
ret
_sce_enable_all:
mov SPC_DSPD, #0FFh
ret
_sce_disable_all:
mov SPC_DSPD, #0
ret
;=======================================================================
SCommand_Panning:
;=======================================================================
bne cmd_exit3 ; on tick0:
mov m0, a ; panning = (y << 2) + (y >> 2)
asl a ;
asl a ;
lsr m0 ;
lsr m0 ;
adc a, m0 ;
mov t_panning, a ;
mov ch_panning+x, a ;
ret ;
;=======================================================================
SCommand_SoundControl:
;=======================================================================
bne cmd_exit3
cmp a, #1
bne cmd_exit3
mov a, ch_flags+x
or a, #CF_SURROUND
mov ch_flags+x, a
mov a, #32
mov ch_panning+x, a
mov t_panning, a
ret
;=======================================================================
SCommand_NoteCut:
;=======================================================================
cmp a, mod_tick ; on tick Y:
bne cmd_exit3 ;
mov a, #0 ; zero volume
mov t_volume, a ;
mov ch_volume+x, a ;
ret ;
;=======================================================================
SCommand_NoteDelay:
;=======================================================================
cmp a, mod_tick
beq scdelay_equ
bcs scdelay_lower
ret
scdelay_lower:
or t_flags, #TF_DELAY
ret
scdelay_equ:
or t_flags, #TF_START
ret
;=======================================================================
SCommand_Cue:
;=======================================================================
bne cmd_exit3 ;on tick0:
inc STATUS ; increment CUE value
and STATUS, #11101111b ; in status and send to
mov SPC_PORT2, STATUS ; snes
ret ;
;=======================================================================
Command_Tempo:
;=======================================================================
cmp a, #20h
bcc _temposlide
cmp a, #80
bcs _txxu1
mov a, #80
_txxu1: cmp a, #200
bcc _txxu2
mov a, #200
_txxu2: call Module_ChangeTempo
mov SPC_CONTROL, #%111
ret
_temposlide:
cmp a, #10h
bcc _txx_down
and a, #0Fh
clrc
adc a, mod_bpm
cmp a, #200
bcc _txx_satH
mov a, #200
_txx_satH:
call Module_ChangeTempo
mov SPC_CONTROL, #%111
ret
_txx_down:
mov m0, a
mov a, mod_bpm
setc
sbc a, m0
cmp a, #80
bcs _txx_satH
mov a, #80
call Module_ChangeTempo
mov SPC_CONTROL, #%111
ret
;=======================================================================
Command_FineVibrato: ; unimplemented
;=======================================================================
ret
;=======================================================================
Command_SetGlobalVolume:
;=======================================================================
bne cmd_exit4 ; set global volume on tick0
cmp a, #80h ;
bcc _vxx_nsat ; saturate to 80h
mov a, #80h ;
_vxx_nsat: ;
mov mod_gvol, a ;
cmd_exit4: ;
ret ;
;=======================================================================
Command_GlobalVolumeSlide:
;=======================================================================
mov m0, mod_gvol ; slide global volume
mov m0+1, #128 ; max 128
call DoVolumeSlide ;
mov mod_gvol, a ;
ret ;
;=======================================================================
Command_SetPanning:
;=======================================================================
bne cmd_exit4 ; set panning on tick0
lsr a ;
lsr a ;
mov t_panning, a ;
mov ch_panning+x, a ;
mov a, ch_flags+x
and a, #~CF_SURROUND
mov ch_flags+x, a
ret ;
;=======================================================================
Command_Panbrello: ; unimplemented
;=======================================================================
ret
;=======================================================================
Command_MidiMacro: ; ?
;=======================================================================
ret
;-----------------------------------------------------------------------
; a = param
; y = tick
; m0 = value
; m0+1 = upper bound
;
; return: a = result
;-----------------------------------------------------------------------
DoVolumeSlide:
;-----------------------------------------------------------------------
mov m1, a ; test param for slide behavior
;-------------------------------
and a, #0Fh ; Dx0 : slide up
beq _dvs_up ;-------------------------------
mov a, m1 ; D0y : slide down
and a, #0F0h ;
beq _dvs_down ;-------------------------------
mov a, m1 ; DxF : slide up fine
and a, #0Fh ;
cmp a, #0Fh ;
beq _dvs_fineup ;-------------------------------
mov a, m1 ; DFy : slide down fine
cmp a, #0F0h ;
bcs _dvs_finedown ;
_dvs_quit: ;-------------------------------
mov a, m0 ; (invalid)
_dvs_exit: ;
ret ;
;-----------------------------------------------------------------------
_dvs_finedown: ; DFy
;-----------------------------------------------------------------------
cmp y, #0 ;on tick0:
bne _dvs_quit ;
mov a, m0 ; a = volume - y
and m1, #0Fh ;
sbc a, m1 ;
bcs _dvs_exit ; saturate lower bound to 0
mov a, #0 ;
ret ;
;-----------------------------------------------------------------------
_dvs_fineup: ; DxF
;-----------------------------------------------------------------------
cmp y, #0 ;on tick0:
bne _dvs_quit ;
mov a, m1 ; a = x + volume
xcn a ;
and a, #0Fh ;
clrc ;
adc a, m0 ;
cmp a, m0+1 ; saturate upper to [m0.h]
bcc _dvs_exit ;
mov a, m0+1 ;
ret ;
;-----------------------------------------------------------------------
_dvs_down: ; D0y
;-----------------------------------------------------------------------
cmp m1,#0Fh ;on tick0 OR y == 15
beq _dvsd_15 ;
cmp y, #0 ;
beq _dvs_quit ;
_dvsd_15: ;
mov a, m0 ; a = volume - param
setc ;
sbc a, m1 ;
bcs _dvs_exit ; saturate lower to 0
mov a, #0 ;
ret ;
;-----------------------------------------------------------------------
_dvs_up: ;
;-----------------------------------------------------------------------
cmp m1, #0F0h ;on tick0 OR x == 15
beq _dvsu_15 ;
cmp y, #0 ;
beq _dvs_quit ;
_dvsu_15: ;
mov a, m1 ; a = x + volume
xcn a ;
and a, #0Fh ;
clrc ;
adc a, m0 ;
cmp a, m0+1 ; saturte upper to [m0.h]
bcc _dvs_exit ;
mov a, m0+1 ;
ret ;
;-----------------------------------------------------------------------
;=======================================================================
; a = param
; y = tick
; return m0:word = slide amount
;=======================================================================
PitchSlide_Load:
;=======================================================================
cmp a, #0F0h ; Fx: fine slide
bcs _psl_fine ;
cmp a, #0E0h ; Ex: extra fine slide
bcs _psl_exfine ;
;-----------------------------------------------------------------------
_psl_normal:
;-----------------------------------------------------------------------
cmp y, #0 ; no slide on tick0
beq _psl_zero ;
mov m0+1, #0 ; m0 = a*4
asl a ;
rol m0+1 ;
asl a ;
rol m0+1 ;
mov m0, a ;
ret ;
;-----------------------------------------------------------------------
_psl_fine:
;-----------------------------------------------------------------------
cmp y, #0 ; no slide on not tick0
bne _psl_zero ;
mov m0+1, #0 ; m0 = y*4
and a, #0Fh ;
asl a ;
asl a ;
mov m0, a ;
ret ;
;-----------------------------------------------------------------------
_psl_exfine:
;-----------------------------------------------------------------------
cmp y, #0 ; no slide on not tick0
bne _psl_zero ;
mov m0+1, #0 ; m0 = y
and a, #0Fh ;
mov m0, a ;
ret ;
;-----------------------------------------------------------------------
_psl_zero:
;-----------------------------------------------------------------------
mov m0, #0
mov m0+1, #0
ret
;************************************************************************************************************************************************
LUT_DIV3:
.byte 0, 0, 0, 1, 1, 1, 2, 2, 2
.byte 3, 3, 3, 4, 4, 4, 5, 5, 5
.byte 6, 6, 6, 7, 7, 7, 8, 8, 8
.byte 9, 9, 9,10,10
LUT_FTAB:
.word 02174h, 0217Bh, 02183h, 0218Bh, 02193h, 0219Ah, 021A2h, 021AAh, 021B2h, 021BAh, 021C1h, 021C9h, 021D1h, 021D9h, 021E1h, 021E8h
.word 021F0h, 021F8h, 02200h, 02208h, 02210h, 02218h, 0221Fh, 02227h, 0222Fh, 02237h, 0223Fh, 02247h, 0224Fh, 02257h, 0225Fh, 02267h
.word 0226Fh, 02277h, 0227Fh, 02287h, 0228Fh, 02297h, 0229Fh, 022A7h, 022AFh, 022B7h, 022BFh, 022C7h, 022CFh, 022D7h, 022DFh, 022E7h
.word 022EFh, 022F7h, 022FFh, 02307h, 0230Fh, 02317h, 0231Fh, 02328h, 02330h, 02338h, 02340h, 02348h, 02350h, 02358h, 02361h, 02369h
.word 02371h, 02379h, 02381h, 0238Ah, 02392h, 0239Ah, 023A2h, 023AAh, 023B3h, 023BBh, 023C3h, 023CBh, 023D4h, 023DCh, 023E4h, 023EDh
.word 023F5h, 023FDh, 02406h, 0240Eh, 02416h, 0241Fh, 02427h, 0242Fh, 02438h, 02440h, 02448h, 02451h, 02459h, 02462h, 0246Ah, 02472h
.word 0247Bh, 02483h, 0248Ch, 02494h, 0249Dh, 024A5h, 024AEh, 024B6h, 024BEh, 024C7h, 024CFh, 024D8h, 024E0h, 024E9h, 024F2h, 024FAh
.word 02503h, 0250Bh, 02514h, 0251Ch, 02525h, 0252Dh, 02536h, 0253Fh, 02547h, 02550h, 02559h, 02561h, 0256Ah, 02572h, 0257Bh, 02584h
.word 0258Ch, 02595h, 0259Eh, 025A7h, 025AFh, 025B8h, 025C1h, 025C9h, 025D2h, 025DBh, 025E4h, 025ECh, 025F5h, 025FEh, 02607h, 0260Fh
.word 02618h, 02621h, 0262Ah, 02633h, 0263Ch, 02644h, 0264Dh, 02656h, 0265Fh, 02668h, 02671h, 0267Ah, 02682h, 0268Bh, 02694h, 0269Dh
.word 026A6h, 026AFh, 026B8h, 026C1h, 026CAh, 026D3h, 026DCh, 026E5h, 026EEh, 026F7h, 02700h, 02709h, 02712h, 0271Bh, 02724h, 0272Dh
.word 02736h, 0273Fh, 02748h, 02751h, 0275Ah, 02763h, 0276Dh, 02776h, 0277Fh, 02788h, 02791h, 0279Ah, 027A3h, 027ACh, 027B6h, 027BFh
.word 027C8h, 027D1h, 027DAh, 027E4h, 027EDh, 027F6h, 027FFh, 02809h, 02812h, 0281Bh, 02824h, 0282Eh, 02837h, 02840h, 0284Ah, 02853h
.word 0285Ch, 02865h, 0286Fh, 02878h, 02882h, 0288Bh, 02894h, 0289Eh, 028A7h, 028B0h, 028BAh, 028C3h, 028CDh, 028D6h, 028E0h, 028E9h
.word 028F2h, 028FCh, 02905h, 0290Fh, 02918h, 02922h, 0292Bh, 02935h, 0293Eh, 02948h, 02951h, 0295Bh, 02965h, 0296Eh, 02978h, 02981h
.word 0298Bh, 02995h, 0299Eh, 029A8h, 029B1h, 029BBh, 029C5h, 029CEh, 029D8h, 029E2h, 029EBh, 029F5h, 029FFh, 02A08h, 02A12h, 02A1Ch
.word 02A26h, 02A2Fh, 02A39h, 02A43h, 02A4Dh, 02A56h, 02A60h, 02A6Ah, 02A74h, 02A7Eh, 02A87h, 02A91h, 02A9Bh, 02AA5h, 02AAFh, 02AB9h
.word 02AC3h, 02ACCh, 02AD6h, 02AE0h, 02AEAh, 02AF4h, 02AFEh, 02B08h, 02B12h, 02B1Ch, 02B26h, 02B30h, 02B3Ah, 02B44h, 02B4Eh, 02B58h
.word 02B62h, 02B6Ch, 02B76h, 02B80h, 02B8Ah, 02B94h, 02B9Eh, 02BA8h, 02BB2h, 02BBCh, 02BC6h, 02BD1h, 02BDBh, 02BE5h, 02BEFh, 02BF9h
.word 02C03h, 02C0Dh, 02C18h, 02C22h, 02C2Ch, 02C36h, 02C40h, 02C4Bh, 02C55h, 02C5Fh, 02C69h, 02C74h, 02C7Eh, 02C88h, 02C93h, 02C9Dh
.word 02CA7h, 02CB2h, 02CBCh, 02CC6h, 02CD1h, 02CDBh, 02CE5h, 02CF0h, 02CFAh, 02D04h, 02D0Fh, 02D19h, 02D24h, 02D2Eh, 02D39h, 02D43h
.word 02D4Dh, 02D58h, 02D62h, 02D6Dh, 02D77h, 02D82h, 02D8Ch, 02D97h, 02DA1h, 02DACh, 02DB7h, 02DC1h, 02DCCh, 02DD6h, 02DE1h, 02DECh
.word 02DF6h, 02E01h, 02E0Bh, 02E16h, 02E21h, 02E2Bh, 02E36h, 02E41h, 02E4Bh, 02E56h, 02E61h, 02E6Ch, 02E76h, 02E81h, 02E8Ch, 02E97h
.word 02EA1h, 02EACh, 02EB7h, 02EC2h, 02ECCh, 02ED7h, 02EE2h, 02EEDh, 02EF8h, 02F03h, 02F0Eh, 02F18h, 02F23h, 02F2Eh, 02F39h, 02F44h
.word 02F4Fh, 02F5Ah, 02F65h, 02F70h, 02F7Bh, 02F86h, 02F91h, 02F9Ch, 02FA7h, 02FB2h, 02FBDh, 02FC8h, 02FD3h, 02FDEh, 02FE9h, 02FF4h
.word 02FFFh, 0300Ah, 03015h, 03020h, 0302Ch, 03037h, 03042h, 0304Dh, 03058h, 03063h, 0306Eh, 0307Ah, 03085h, 03090h, 0309Bh, 030A7h
.word 030B2h, 030BDh, 030C8h, 030D4h, 030DFh, 030EAh, 030F5h, 03101h, 0310Ch, 03117h, 03123h, 0312Eh, 0313Ah, 03145h, 03150h, 0315Ch
.word 03167h, 03173h, 0317Eh, 03189h, 03195h, 031A0h, 031ACh, 031B7h, 031C3h, 031CEh, 031DAh, 031E5h, 031F1h, 031FCh, 03208h, 03213h
.word 0321Fh, 0322Bh, 03236h, 03242h, 0324Dh, 03259h, 03265h, 03270h, 0327Ch, 03288h, 03293h, 0329Fh, 032ABh, 032B7h, 032C2h, 032CEh
.word 032DAh, 032E5h, 032F1h, 032FDh, 03309h, 03315h, 03320h, 0332Ch, 03338h, 03344h, 03350h, 0335Ch, 03367h, 03373h, 0337Fh, 0338Bh
.word 03397h, 033A3h, 033AFh, 033BBh, 033C7h, 033D3h, 033DFh, 033EBh, 033F7h, 03403h, 0340Fh, 0341Bh, 03427h, 03433h, 0343Fh, 0344Bh
.word 03457h, 03463h, 0346Fh, 0347Bh, 03488h, 03494h, 034A0h, 034ACh, 034B8h, 034C4h, 034D1h, 034DDh, 034E9h, 034F5h, 03502h, 0350Eh
.word 0351Ah, 03526h, 03533h, 0353Fh, 0354Bh, 03558h, 03564h, 03570h, 0357Dh, 03589h, 03595h, 035A2h, 035AEh, 035BAh, 035C7h, 035D3h
.word 035E0h, 035ECh, 035F9h, 03605h, 03612h, 0361Eh, 0362Bh, 03637h, 03644h, 03650h, 0365Dh, 03669h, 03676h, 03683h, 0368Fh, 0369Ch
.word 036A8h, 036B5h, 036C2h, 036CEh, 036DBh, 036E8h, 036F4h, 03701h, 0370Eh, 0371Bh, 03727h, 03734h, 03741h, 0374Eh, 0375Ah, 03767h
.word 03774h, 03781h, 0378Eh, 0379Ah, 037A7h, 037B4h, 037C1h, 037CEh, 037DBh, 037E8h, 037F5h, 03802h, 0380Eh, 0381Bh, 03828h, 03835h
.word 03842h, 0384Fh, 0385Ch, 03869h, 03876h, 03884h, 03891h, 0389Eh, 038ABh, 038B8h, 038C5h, 038D2h, 038DFh, 038ECh, 038FAh, 03907h
.word 03914h, 03921h, 0392Eh, 0393Bh, 03949h, 03956h, 03963h, 03970h, 0397Eh, 0398Bh, 03998h, 039A6h, 039B3h, 039C0h, 039CEh, 039DBh
.word 039E8h, 039F6h, 03A03h, 03A11h, 03A1Eh, 03A2Bh, 03A39h, 03A46h, 03A54h, 03A61h, 03A6Fh, 03A7Ch, 03A8Ah, 03A97h, 03AA5h, 03AB2h
.word 03AC0h, 03ACEh, 03ADBh, 03AE9h, 03AF6h, 03B04h, 03B12h, 03B1Fh, 03B2Dh, 03B3Bh, 03B48h, 03B56h, 03B64h, 03B72h, 03B7Fh, 03B8Dh
.word 03B9Bh, 03BA9h, 03BB6h, 03BC4h, 03BD2h, 03BE0h, 03BEEh, 03BFCh, 03C09h, 03C17h, 03C25h, 03C33h, 03C41h, 03C4Fh, 03C5Dh, 03C6Bh
.word 03C79h, 03C87h, 03C95h, 03CA3h, 03CB1h, 03CBFh, 03CCDh, 03CDBh, 03CE9h, 03CF7h, 03D05h, 03D13h, 03D21h, 03D2Fh, 03D3Eh, 03D4Ch
.word 03D5Ah, 03D68h, 03D76h, 03D85h, 03D93h, 03DA1h, 03DAFh, 03DBDh, 03DCCh, 03DDAh, 03DE8h, 03DF7h, 03E05h, 03E13h, 03E22h, 03E30h
.word 03E3Eh, 03E4Dh, 03E5Bh, 03E6Ah, 03E78h, 03E86h, 03E95h, 03EA3h, 03EB2h, 03EC0h, 03ECFh, 03EDDh, 03EECh, 03EFAh, 03F09h, 03F18h
.word 03F26h, 03F35h, 03F43h, 03F52h, 03F61h, 03F6Fh, 03F7Eh, 03F8Dh, 03F9Bh, 03FAAh, 03FB9h, 03FC7h, 03FD6h, 03FE5h, 03FF4h, 04002h
.word 04011h, 04020h, 0402Fh, 0403Eh, 0404Dh, 0405Bh, 0406Ah, 04079h, 04088h, 04097h, 040A6h, 040B5h, 040C4h, 040D3h, 040E2h, 040F1h
.word 04100h, 0410Fh, 0411Eh, 0412Dh, 0413Ch, 0414Bh, 0415Ah, 04169h, 04178h, 04188h, 04197h, 041A6h, 041B5h, 041C4h, 041D3h, 041E3h
.word 041F2h, 04201h, 04210h, 04220h, 0422Fh, 0423Eh, 0424Eh, 0425Dh, 0426Ch, 0427Ch, 0428Bh, 0429Ah, 042AAh, 042B9h, 042C9h, 042D8h
IT_FineSineData:
.byte 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 16, 17, 19, 20, 22, 23
.byte 24, 26, 27, 29, 30, 32, 33, 34, 36, 37, 38, 39, 41, 42, 43, 44
.byte 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59
.byte 59, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 64, 64, 64
.byte 64, 64, 64, 64, 64, 64, 63, 63, 63, 62, 62, 62, 61, 61, 60, 60
.byte 59, 59, 58, 57, 56, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46
.byte 45, 44, 43, 42, 41, 39, 38, 37, 36, 34, 33, 32, 30, 29, 27, 26
.byte 24, 23, 22, 20, 19, 17, 16, 14, 12, 11, 9, 8, 6, 5, 3, 2
.byte 0, -2, -3, -5, -6, -8, -9,-11,-12,-14,-16,-17,-19,-20,-22,-23
.byte -24,-26,-27,-29,-30,-32,-33,-34,-36,-37,-38,-39,-41,-42,-43,-44
.byte -45,-46,-47,-48,-49,-50,-51,-52,-53,-54,-55,-56,-56,-57,-58,-59
.byte -59,-60,-60,-61,-61,-62,-62,-62,-63,-63,-63,-64,-64,-64,-64,-64
.byte -64,-64,-64,-64,-64,-64,-63,-63,-63,-62,-62,-62,-61,-61,-60,-60
.byte -59,-59,-58,-57,-56,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46
.byte -45,-44,-43,-42,-41,-39,-38,-37,-36,-34,-33,-32,-30,-29,-27,-26
.byte -24,-23,-22,-20,-19,-17,-16,-14,-12,-11, -9, -8, -6, -5, -3, -2
;****************************************************************************************
;* Sound Effects
;****************************************************************************************
map_15_127:
.byte 0, 8, 17, 25,
.byte 34, 42, 51, 59,
.byte 68, 76, 85, 93,
.byte 102, 110, 119, 127
;*************************************************************************
;* play sound effect
;*
;* m0 = params
;* vp sh
;*
;* s = sample index
;* h = pitch ( 8 = 32000hz, h = pitch height >> 9 )
;* v = volume (15 = max)
;* p = panning (8 = center)
;*************************************************************************
SFX_Play:
;-------------------------------------------------------------------------
mov a, m0 ; m1 = GAIN (0-15 = 0-127)
xcn a ;
and a, #0Fh ;
mov y, a ;
mov a, !map_15_127+y ;
mov m1, a ;---------------------------------
mov a, m0 ; m2 = volumes
and a, #0Fh ;
mov y, a ;
mov a, !map_15_127+y ;
mov m2+1, a ;
eor a, #127 ;
mov m2, a ;---------------------------------
mov a, m0+1 ; m1.h = src
and a, #0F0h ;
xcn a ;
clrc ;
adc a, #64 ;
mov m1+1, a ;---------------------------------
mov a, m0+1 ; m3 = pitch.h
and a, #0Fh ; (pitch.l = 0)
asl a ;
mov m3, a ;---------------------------------
mov a, sfx_mask ; test for unused channels
asl a ;
bcc _sfx_use1 ;
beq _sfx_use0 ;---------------------------------
eor sfx_next, #1 ; otherwise alternate channels
bne _sfx_use1 ;
;-------------------------------------------------------------------------
_sfx_use0:
;-------------------------------------------------------------------------
mov sfx_next, #0 ;
mov SPC_DSPA, #064h ; set SRCN value for channel
mov SPC_DSPD, m1+1 ;---------------------------------
mov SPC_DSPA, #DSP_KON ; set KON bit
mov SPC_DSPD, #%01000000 ;
or sfx_mask, #%01000000 ; set SFX flag
mov SPC_DSPA, #060h ; setup dsp pointer
bra _sfx_start ;
;-------------------------------------------------------------------------
_sfx_use1:
;-------------------------------------------------------------------------
; cmp stream_active, #0 ; [STREAMING reserves channel7]
; bne _sfx_use0 ;
mov sfx_next, #1
mov SPC_DSPA, #074h
mov SPC_DSPD, m1+1
mov SPC_DSPA, #DSP_KON
mov SPC_DSPD, #%10000000
or sfx_mask, #%10000000
mov SPC_DSPA, #070h
;-------------------------------------------------------------------------
_sfx_start:
;-------------------------------------------------------------------------
mov SPC_DSPD, m2 ; VOLUME L
inc SPC_DSPA ;
mov SPC_DSPD, m2+1 ; VOLUME R
inc SPC_DSPA ;
mov SPC_DSPD, #0 ; PITCH L
inc SPC_DSPA ;
mov SPC_DSPD, m3 ; PITCH H
inc SPC_DSPA ;
inc SPC_DSPA ;
mov SPC_DSPD, #0 ; ADSR1
or SPC_DSPA, #7 ;
mov SPC_DSPD, m1 ; GAIN
ret ;
;-------------------------------------------------------------------------
;*************************************************************************
;* update sound effects
;*************************************************************************
SFX_Update:
;-------------------------------------------------------------------------
mov SPC_DSPA, #DSP_ENDX ; reset SFX mask flags with ENDX
mov a, SPC_DSPD ;
mov SPC_DSPD, a ; <- clear endx
; cmp stream_active, #0
; beq _sfxu_nstreaming
; and a, #127
;_sfxu_nstreaming:
eor a, sfx_mask ;
and a, sfx_mask ;
mov sfx_mask, a ;
ret ;
;-------------------------------------------------------------------------
;*************************************************************************
;*
;* Streaming
;*
;*************************************************************************
;**************************************************************************************
;* setup streaming system
;**************************************************************************************
Streaming_Init:
;--------------------------------------------------------------------------------------
mov a, #0 ; reset region size
call Streaming_Resize ;
;--------------------------------------------------------------------------------------
mov a, #__BRK_ROUTINE__ & 0FFh ; set BRK/TCALL0 vector
mov !0FFDEH, a ;
mov a, #__BRK_ROUTINE__ >> 8 ;
mov !0FFDFH, a ;
;--------------------------------------------------------------------------------------
ret
;**************************************************************************************
;* RESIZE STREAM
;* a = newsize
;**************************************************************************************
Streaming_Resize:
;--------------------------------------------------------------------------------------
; call Streaming_CancelActive
;--------------------------------------------------------------------------------------
mov stream_size, a ;
mov a, #0FFh ; calc streaming region address H
setc ;
sbc a, stream_size ;
mov stream_region, a ;
;--------------------------------------------------------------------------------------
mov a, #0 ; copy stream buffer address
mov !StreamAddress, a ;
mov !StreamAddress+2, a ;
mov a, stream_region ;
mov !StreamAddress+1, a ;
mov !StreamAddress+3, a ;
;--------------------------------------------------------------------------------------
ret
;Streaming_CancelActive:
; mov a, sfx_mask
; and a, #80h
; beq streaming_is_inactive
; mov y, #70h|DSPV_GAIN
; mov a, #0
; movw SPC_DSP, ya
;
;streaming_is_inactive:
; ret
;**************************************************************************************
;* START STREAM
;**************************************************************************************
Streaming_Activate:
;--------------------------------------------------------------------------------------
mov a, SPC_PORT2 ; compute volume from panning
and a, #15 ;
asl a ;
asl a ;
asl a ;
mov stream_volR, a ;
eor a, #127 ;
mov stream_volL, a ;
;--------------------------------------------------------------------------------------
mov a, SPC_PORT2 ; compute GAIN (v<<3)
and a, #0F0h ;
lsr a ;
mov stream_gain, a ;
;--------------------------------------------------------------------------------------
mov stream_rate, SPC_PORT3 ; copy rate/PITCH
;--------------------------------------------------------------------------------------
mov stream_initial, #1 ; set initial flag for data routine
;--------------------------------------------------------------------------------------
call StreamResetAddress ;
;--------------------------------------------------------------------------------------
ret
;======================================================================================
StreamStartChannel:
;======================================================================================
mov stream_initial, #0 ; reset flag
or sfx_mask, #80h ; patch sfx system
mov sfx_next, #1 ;
;--------------------------------------------------------------------------------------
mov SPC_DSPA, #074h ; SRCN = stream
mov SPC_DSPD, #80 ;
;--------------------------------------------------------------------------------------
mov SPC_DSPA, #DSP_KON ; KEYON channel
mov SPC_DSPD, #80h ;
;--------------------------------------------------------------------------------------
mov SPC_DSPA, #070h ; copy volume (panning)
mov SPC_DSPD, stream_volL ;
inc SPC_DSPA ;
mov SPC_DSPD, stream_volR ;
inc SPC_DSPA ;
;--------------------------------------------------------------------------------------
mov SPC_DSPD, #00H ; copy pitch
inc SPC_DSPA ;
mov SPC_DSPD, stream_rate ;
inc SPC_DSPA ;
inc SPC_DSPA ;
;--------------------------------------------------------------------------------------
mov SPC_DSPD, #0 ; clear ADSR
inc SPC_DSPA ;
inc SPC_DSPA ;
;--------------------------------------------------------------------------------------
mov SPC_DSPD, stream_gain ; copy gain
;--------------------------------------------------------------------------------------
ret
;**************************************************************************************
;* UPDATE STREAM
;**************************************************************************************
Streaming_Run:
;--------------------------------------------------------------------------------------
mov SPC_PORT0, #80h ; respond to SNES
;--------------------------------------------------------------------------------------
push a ; preserve regs
push x ;
push y ;
;--------------------------------------------------------------------------------------
_srw1: cmp SPC_PORT0, #80h ; wait for snes
bcs _srw1 ;
;--------------------------------------------------------------------------------------
mov a, SPC_PORT0 ; copy nchunks
mov stream_a, a ;
mov a, SPC_PORT1 ; check for new note
beq _sr_nstart ;
call Streaming_Activate ;
_sr_nstart: ;
mov x, SPC_PORT0 ;
mov SPC_PORT0, x ; respond to snes
;--------------------------------------------------------------------------------------
_sr_start:
mov y, #0 ; prepare COPYING...
inc x
_sr_wait_for_snes: ;
cmp x, SPC_PORT0 ;
bne _sr_wait_for_snes ;
;--------------------------------------------------------------------------------------
bra _sr_copy
_sr_nextcopy:
inc x
_sr_wait3:
cmp x, SPC_PORT0
bne _sr_wait3
;--------------------------------------------------------------------------------------
_sr_copy: ; copy 9 bytes (16 SAMPLES)
;--------------------------------------------------------------------------------------
mov a, SPC_PORT2 ; copy first 3 bytes
STRC0: mov !0FE00h+0+y, a ;
mov a, SPC_PORT3 ;
STRC1: mov !0FE00h+1+y, a ;
mov SPC_PORT0, x ;-signal
mov a, SPC_PORT1 ;
STRC2: mov !0FE00h+2+y, a ;
inc x ;
_wait1: ; wait for data
cmp x, SPC_PORT0 ;
bne _wait1 ;
;--------------------------------------------------------------------------------------
mov a, SPC_PORT2 ; copy next 3 bytes
STRC3: mov !0FE00h+3+y, a ;
mov a, SPC_PORT3 ;
STRC4: mov !0FE00h+4+y, a ;
mov SPC_PORT0, x ;-signal
mov a, SPC_PORT1 ;
STRC5: mov !0FE00h+5+y, a ;
inc x ;
_wait2: ; wait for data
cmp x, SPC_PORT0 ;
bne _wait2 ;
;--------------------------------------------------------------------------------------
mov a, SPC_PORT2 ; copy last 3 bytes
STRC6: mov !0FE00h+6+y, a ;
mov a, SPC_PORT3 ;
STRC7: mov !0FE00h+7+y, a ;
mov SPC_PORT0, x ;-signal
mov a, SPC_PORT1 ;