Subversion Repositories svn.mios

Rev

Rev 748 | Rev 880 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
44 tk 1
; $Id: sid_se.inc 878 2010-01-02 15:40:58Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; Software Synthesizer Engine
5
;
6
; Activate this #define to measure the performance with a scope
7
; the used port has to be specified here - comment out for no measuring
8
;#define SID_SE_MEASURE_PERFORMANCE_PORT   LATC, 3
9
;
10
; ==========================================================================
11
;
12
;  Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
13
;  Idea for ENV Curve Parameter and OSC synchronization by Jess D. Skov-Nielsen
14
;  Licensed for personal non-commercial use only.
15
;  All other rights reserved.
16
;
17
; ==========================================================================
18
 
391 tk 19
 
1 tk 20
;; ==========================================================================
21
;;  SID Flags
22
;; ==========================================================================
23
 
748 tk 24
;; general SID status flags
25
SID_STAT_ENGINE_DISABLE		EQU	0 ; if set, SID tick and SID interrupt will not be processed
26
SID_STAT_ENGINE_DISABLE_LEVEL0	EQU	1 ; same as flag 0, but used during startup to overcome a wdt timeout issue when no LCD is connected
27
SID_STAT_MBNET_ACCESS		EQU	2 ; exclusive access for MBNet
28
SID_STAT_SIDPLAYER		EQU	3 ; exclusive access for SID player
29
SID_STAT_SIDPLAYER_CS_DISABLE	EQU	4 ; set if CS buttons/encoders should be ignored
30
SID_STAT_CLK_SLAVE		EQU	5 ; if set, clock generator in slave mode (flag should be outside erasable SID_BASE structure)
31
SID_STAT_SE_CYCLE		EQU	6 ; switches between first and second engine cycle
32
 
33
 
1 tk 34
;; MIDI Voice Control Flags
35
SID_MV_ARP_STATE_ARP_ACTIVE	EQU	0 ; set if at least one arp is active
36
SID_MV_ARP_STATE_ARP_UP		EQU	1 ; arp order is incremented
37
SID_MV_ARP_STATE_SYNC_ARP	EQU	2 ; syncs the arpeggiator when a new note is played
38
SID_MV_ARP_STATE_HOLD_SAVED	EQU	3 ; notifies if hold mode was active (notes should be disabled on 1->0 transition)
39
 
40
SID_V_STATE_VOICE_ACTIVE	EQU	0
41
SID_V_STATE_VOICE_DISABLED	EQU	1
42
SID_V_STATE_GATE_ACTIVE		EQU	2
43
SID_V_STATE_GATE_SET_REQ	EQU	3
44
SID_V_STATE_GATE_CLR_REQ	EQU	4
45
SID_V_STATE_PORTA_ACTIVE	EQU	5
46
SID_V_STATE_ACCENT		EQU	6
47
SID_V_STATE_SLIDE		EQU	7
48
 
248 tk 49
SID_V_STATE2_PORTA_INITIALIZED	EQU	0	; portamento omitted when first key played
399 tk 50
SID_V_STATE2_FORCE_FRQ_RECALC	EQU	1	; forces SID frequency re-calculation (used by multi-engine to takeover portamento)
248 tk 51
 
1 tk 52
SID_I_OPT1_FLAGS_ABW		EQU	0	; ADSR bug workaround
53
 
54
SID_I_L_FLAGS1_LEGATO		EQU	0	; switches between mono/legato mode
55
SID_I_L_FLAGS1_WT_ONLY		EQU	1	; notes played by WT only
56
SID_I_L_FLAGS1_SUS_KEY		EQU	2	; enables SusKey
57
 
58
SID_I_M_V_FLAGS2_LEGATO		EQU	0	; multi engine only: switches between mono/legato mode when poly not enabled
59
SID_I_M_V_FLAGS2_WT_ONLY	EQU	1	; multi engine only: notes played by WT only
60
SID_I_M_V_FLAGS2_SUS_KEY	EQU	2	; multi engine only: enables SusKey
61
SID_I_M_V_FLAGS2_POLY		EQU	3	; multi engine only: enables Poly mode
62
SID_I_M_V_FLAGS2_PHASE		EQU	4	; multi engine only: oscillator phase synchronisation
63
 
64
SID_I_B_V_FLAGS2_LEGATO		EQU	0	; bassline engine only: switches between mono/legato mode when poly not enabled
65
SID_I_B_V_FLAGS2_WT_ONLY	EQU	1	; bassline engine only: notes played by WT only
66
SID_I_B_V_FLAGS2_SUS_KEY	EQU	2	; bassline engine only: enables SusKey
67
SID_I_B_V_FLAGS2_PHASE		EQU	4	; bassline engine only: oscillator phase synchronisation
68
 
69
SID_I_V_FLAGS1_PORTA_CTG	EQU	0	; constant time glide
70
SID_I_V_FLAGS1_PORTA_GLISSANDO	EQU	1	; glissando
71
SID_I_V_FLAGS1_GSA		EQU	2	; gate stays active
72
SID_I_V_FLAGS1_VASG_0		EQU	4	; only relevant for drum engine: voice assignment, bit 0
73
SID_I_V_FLAGS1_VASG_1		EQU	5	; only relevant for drum engine: voice assignment, bit 1
74
SID_I_V_FLAGS1_VASG_2		EQU	6	; only relevant for drum engine: voice assignment, bit 2
75
SID_I_V_FLAGS1_VASG_3		EQU	7	; only relevant for drum engine: voice assignment, bit 3
76
 
77
SID_I_V_ARP_MODE_ENABLE		EQU	0	; enables arp
78
SID_I_V_ARP_MODE_DIR_DOWN	EQU	1	; arp dir Up/Down
79
SID_I_V_ARP_MODE_DIR_ALT	EQU	2	; arp dir U&D/D&U
80
SID_I_V_ARP_MODE_DIR_ALT2	EQU	3	; arp dir U&D/D&U second option (border notes played twice) - dir mode 6 and 7 will select random
81
SID_I_V_ARP_MODE_SORTED		EQU	4	; select sorted stack
82
SID_I_V_ARP_MODE_HOLD		EQU	5	; select hold stack
83
SID_I_V_ARP_MODE_DIV_SYNC	EQU	6	; disables divider reset on new notes
84
SID_I_V_ARP_MODE_CAC		EQU	7	; constant arp cycle
85
 
679 tk 86
SID_I_V_ARP_SPEED_DIV_EASY_CHORD EQU	6	; easy chord mode
1 tk 87
SID_I_V_ARP_SPEED_DIV_ONESHOT	EQU	7	; oneshot mode
88
 
89
SID_I_V_SEQ_ON			EQU	6	; drum engine only: sequencer on/off flag
90
SID_I_V_SEQ_SYNC16		EQU	7	; bassline/drum engine only: 16step sync function
91
 
92
SID_SEQ_MISC_SUBCTR		EQU	0	; [2:0] counts from 0 to 6
93
SID_SEQ_MISC_SEQ_ON		EQU	3	; stores sequencer on flag
94
SID_SEQ_MISC_SEQ_RUNNING	EQU	4	; stores sequencer running flag (only used in drum mode)
95
 
96
SID_I_F_FIP_ON			EQU	7	; located in high byte of cutoff frequency: filter interpolation flag
97
 
98
SID_I_LFO_MODE_ENABLE		EQU	0
99
SID_I_LFO_MODE_SYNC_M		EQU	1	; sync LFO (only for multi and bassline engine - lead engine uses trigger matrix!)
100
SID_I_LFO_MODE_CLKSYNC		EQU	2
101
SID_I_LFO_MODE_ONESHOT		EQU	3
102
SID_I_LFO_MODE_WAVEFORM0	EQU	4
103
SID_I_LFO_MODE_WAVEFORM1	EQU	5
104
SID_I_LFO_MODE_WAVEFORM2	EQU	6
105
SID_I_LFO_MODE_WAVEFORM3	EQU	7
106
 
107
SID_I_ENV_MODE_LOOP_B0		EQU	0	; loop begin (3 bit)
108
SID_I_ENV_MODE_LOOP_B1		EQU	1
109
SID_I_ENV_MODE_LOOP_B2		EQU	2
110
SID_I_ENV_MODE_LOOP_E0		EQU	4	; loop end (3 bit)
111
SID_I_ENV_MODE_LOOP_E1		EQU	5
112
SID_I_ENV_MODE_LOOP_E2		EQU	6
113
SID_I_ENV_MODE_CLKSYNC		EQU	7
114
 
228 tk 115
SID_I_ENV_MODE_CURVE_ATT	EQU	4	; only used by Multi/Bassline engine: curve assigned to attack
116
SID_I_ENV_MODE_CURVE_DEC	EQU	5	; only used by Multi/Bassline engine: curve assigned to sustain
117
SID_I_ENV_MODE_CURVE_REL	EQU	6	; only used by Multi/Bassline engine: curve assigned to release
118
 
1 tk 119
SID_SE_STATE_LFO_OVERRUN	EQU	0	; used by LFO handler to notify an overrun
120
SID_SE_STATE_WT_NEW_STEP_REQ	EQU	0	; used by WT handler to request new step (shared flag with LFO)
121
SID_SE_STATE_ARP_NEW_NOTE_REQ	EQU	0	; used by ARP handler to request new note (shared flag with LFO)
122
SID_SE_STATE_ARP_FIRST_NOTE_REQ	EQU	1	; used by ARP handler to request the first note (oneshot function)
123
SID_SE_STATE_ARP_GATE_CLR_REQ	EQU	2	; used by ARP handler to request a gate clear
124
SID_SE_STATE_GLOBAL_CLK_EVENT	EQU	3	; temporary "global clock event" flag
125
SID_SE_STATE_MIDI_CLK_FA_REQ	EQU	4	; "MIDI clock start" request flag
126
SID_SE_STATE_MIDI_CLK_FB_REQ	EQU	5	; "MIDI clock continue" request flag
127
SID_SE_STATE_MIDI_CLK_FC_REQ	EQU	6	; "MIDI clock stop" request flag
128
SID_SE_STATE_ACCENT		EQU	7	; used by multi/bassline ENV handler to increase depth on accent
129
 
130
SID_ENV_STATE_ATTACK1		EQU	0
131
SID_ENV_STATE_ATTACK2		EQU	1
132
SID_ENV_STATE_DECAY1		EQU	2
133
SID_ENV_STATE_DECAY2		EQU	3
134
SID_ENV_STATE_SUSTAIN		EQU	4
135
SID_ENV_STATE_RELEASE1		EQU	5
136
SID_ENV_STATE_RELEASE2		EQU	6
137
 
138
SID_ENS_CTRL1_CLK_SLAVE		EQU	0	; switch between MIDI clock master/slave
139
SID_ENS_CTRL1_CLK_AUTO		EQU	1	; automatic switching between master/slave
340 tk 140
SID_ENS_CTRL1_FIL_LOG		EQU	4	; Select logarithmic scale for filter
1 tk 141
SID_ENS_CTRL1_MONO		EQU	6	; SIDs are played mono
340 tk 142
SID_ENS_CTRL1_DOR		EQU	7	; Disable automatic Oscillator Reset during patch change (could also be called DAORDPC flag ;)
1 tk 143
 
144
SID_ENS_CTRL2_F2A		EQU	0	; forward Filter CutOff/Resonance to AOUTs
145
SID_ENS_CTRL2_V2A		EQU	1	; forward Volume to AOUTs
146
SID_ENS_CTRL2_P2A		EQU	2	; forward Pulsewidth to AOUTs
147
SID_ENS_CTRL2_K2A		EQU	3	; forward Key Values to AOUTs and Gates to Digital Out
148
SID_ENS_CTRL2_O2A		EQU	4	; forward Oscillator Values to AOUTs and Gates to Digital Out
149
 
150
SID_TRG_TARGET_L_O1L		EQU	0	; OSC1 Left
151
SID_TRG_TARGET_L_O2L		EQU	1	; OSC2 Left
152
SID_TRG_TARGET_L_O3L		EQU	2	; OSC3 Left
153
SID_TRG_TARGET_L_O1R		EQU	3	; OSC1 Right
154
SID_TRG_TARGET_L_O2R		EQU	4	; OSC2 Right
155
SID_TRG_TARGET_L_O3R		EQU	5	; OSC3 Right
156
SID_TRG_TARGET_L_E1A		EQU	6	; ENV1 Attack
157
SID_TRG_TARGET_L_E2A		EQU	7	; ENV2 Attack
158
SID_TRG_TARGET_H_E1R		EQU	0	; ENV1 Release
159
SID_TRG_TARGET_H_E2R		EQU	1	; ENV2 Release
160
SID_TRG_TARGET_H_L1		EQU	2	; LFO1 sync
161
SID_TRG_TARGET_H_L2		EQU	3	; LFO2 sync
162
SID_TRG_TARGET_H_L3		EQU	4	; LFO3 sync
163
SID_TRG_TARGET_H_L4		EQU	5	; LFO4 sync
164
SID_TRG_TARGET_H_L5		EQU	6	; LFO5 sync
165
SID_TRG_TARGET_H_L6		EQU	7	; LFO6 sync
166
SID_TRG_TARGET_U_W1R		EQU	0	; WT1 reset
167
SID_TRG_TARGET_U_W2R		EQU	1	; WT2 reset
168
SID_TRG_TARGET_U_W3R		EQU	2	; WT3 reset
169
SID_TRG_TARGET_U_W4R		EQU	3	; WT4 reset
170
SID_TRG_TARGET_U_W1S		EQU	4	; WT1 step
171
SID_TRG_TARGET_U_W2S		EQU	5	; WT2 step
172
SID_TRG_TARGET_U_W3S		EQU	6	; WT3 step
173
SID_TRG_TARGET_U_W4S		EQU	7	; WT4 step
174
 
175
;; ==========================================================================
176
 
177
 
178
;; --------------------------------------------------------------------------
179
;;  SID Sound Engine Handler: Software Synthesizer part for the SID
180
;;  called by User Timer every 1 mS
181
;; --------------------------------------------------------------------------
182
SIDSE_Handler
183
	SET_BSR	SID_BASE		; prepare BSR for SID register access
184
 
748 tk 185
	;; return immediately if engine has been disabled or direct MBNet access
186
	movf	SID_STAT, W
187
	andlw	(1 << SID_STAT_ENGINE_DISABLE) | (1 << SID_STAT_ENGINE_DISABLE_LEVEL0) | (1 << SID_STAT_MBNET_ACCESS)
188
	skpz
1 tk 189
	return
190
 
191
#ifdef SID_SE_MEASURE_PERFORMANCE_PORT
192
	bsf	SID_SE_MEASURE_PERFORMANCE_PORT
193
#endif
194
 
195
	;; save FSR0[LH] and PROD[LH] - we are in an interrupt routine
196
	movff	FSR0L, SAVED_FSR0L
197
	movff	FSR0H, SAVED_FSR0H
198
	movff	PRODL, SAVED_PRODL
199
	movff	PRODH, SAVED_PRODH
200
 
201
	;; branch depending on engine
202
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
203
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Handler_23
204
SIDSE_Handler_01
205
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Handler_1
206
SIDSE_Handler_0
207
	call	SIDSE_L_Handler
208
	rgoto	SIDSE_Handler_Cont
209
SIDSE_Handler_1
210
	call	SIDSE_B_Handler
211
	rgoto	SIDSE_Handler_Cont
212
 
213
SIDSE_Handler_23
214
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Handler_3
215
SIDSE_Handler_2
216
	call	SIDSE_D_Handler
217
	rgoto	SIDSE_Handler_Cont
218
SIDSE_Handler_3
219
	call	SIDSE_M_Handler
220
	rgoto	SIDSE_Handler_Cont
221
 
222
SIDSE_Handler_Cont
223
 
224
	;; thats all
225
	movff	SAVED_FSR0L, FSR0L		; copy back saved FSR0[LH]
226
	movff	SAVED_FSR0H, FSR0H
227
	movff	SAVED_PRODL, PRODL		; copy back saved PROD[LH]
228
	movff	SAVED_PRODH, PRODH
229
 
230
#ifdef SID_SE_MEASURE_PERFORMANCE_PORT
231
	bcf	SID_SE_MEASURE_PERFORMANCE_PORT
232
#endif
233
 
234
	return
235
 
236
 
237
 
238
 
239
;; --------------------------------------------------------------------------
240
;; This function handles the global clock
241
;; --------------------------------------------------------------------------
242
SIDSE_Clk
243
	;; by default no clock event
244
	bcf	SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED
245
 
246
	;; increment the clock counter, used to measure the delay between two F8 events
247
	;; see also USER_MIDI_NotifyRx
248
	;; ensure that it doesn't overrun
249
	incf	SID_INCOMING_CLK_CTR, W, BANKED
250
	skpz
251
	incf	SID_INCOMING_CLK_CTR, F, BANKED
252
 
253
#if 0
254
	;; try: if no slave clock is received, increment sent clock counter slowly
255
	;; (disabled by default - works fine, but is inconsistent)
256
	movf	SID_INCOMING_CLK_CTR, W, BANKED
257
	andlw	0x3f
258
	skpnz
259
	incf	SID_CLK_REQ_CTR, F, BANKED
260
#endif
261
 
878 tk 262
	;; now determine master/slave flag depending on ensemble setup
1 tk 263
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
264
	BRA_IFSET WREG, SID_ENS_CTRL1_CLK_AUTO, ACCESS, SIDSE_Clk_ModeAuto
265
	BRA_IFSET WREG, SID_ENS_CTRL1_CLK_SLAVE, ACCESS, SIDSE_Clk_ModeSlave
266
SIDSE_Clk_ModeMaster
267
	bcf	SID_STAT, SID_STAT_CLK_SLAVE
268
	rgoto	SIDSE_Clk_Mode_Cont
269
SIDSE_Clk_ModeSlave
270
	bsf	SID_STAT, SID_STAT_CLK_SLAVE
271
	rgoto	SIDSE_Clk_Mode_Cont
272
SIDSE_Clk_ModeAuto
273
	;; slave mode so long INCOMING_CLK_CTR != 0xff
274
	bcf	SID_STAT, SID_STAT_CLK_SLAVE
275
	incf	SID_INCOMING_CLK_CTR, W, BANKED
276
	skpz
277
	bsf	SID_STAT, SID_STAT_CLK_SLAVE
278
	;; 	rgoto	SIDSE_Clk_Mode_Cont
279
SIDSE_Clk_Mode_Cont
280
 
281
	;; decrement sent clock delay, send interpolated clock events 3 times
282
	decf	SID_SENT_CLK_DELAY, F, BANKED
283
	bnz	SIDSE_Clk_NoSlaveTrigger
284
SIDSE_Clk_SlaveTrigger
285
	movf	SID_SENT_CLK_CTR, W, BANKED
286
	xorlw	0x03
287
	bz	SIDSE_Clk_NoSlaveTrigger
288
	incf	SID_SENT_CLK_CTR, F, BANKED
289
	incf	SID_CLK_REQ_CTR, F, BANKED
290
	rrf	SID_INCOMING_CLK_DELAY, W, BANKED
291
	rrf	WREG, W
292
	andlw	0x3f
293
	movwf	SID_SENT_CLK_DELAY, BANKED
294
SIDSE_Clk_NoSlaveTrigger
295
 
296
	;; handle FA event (MIDI clock start)
297
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Clk_NoFA
298
SIDSE_Clk_FA
299
	;; request not cleared here, because it's also used by Arp and sequencer
300
	;; must be cleared at end of update cycle
301
	;; 	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED
302
	;; reset counters
303
	clrf	SID_SE_GLOBAL_CLK_CTR, BANKED
304
	;; propagate LFO/Env/WT sync via trigger matrix
305
	;; (static for Multi Engine)
306
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
307
	andlw	0x03
308
	bz	SIDSE_Clk_FA_Lead
309
SIDSE_Clk_FA_Multi
310
	;; no reset - this disturbs sequence recordings
311
#if 0
312
	movlw	0xfc		; LFO reset
313
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
314
	movlw	0x3f		; WT reset for all 6 instruments
315
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
316
#endif
317
	rgoto	SIDSE_Clk_FA_Multi_Cont
318
 
319
SIDSE_Clk_FA_Lead
320
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 0, WREG
321
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
322
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 1, WREG
323
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
324
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_MSt_BASE + 2, WREG
325
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
326
SIDSE_Clk_FA_Multi_Cont
327
SIDSE_Clk_NoFA
328
 
329
	;; handle F8 event (MIDI clock)
330
	movf	SID_CLK_REQ_CTR, W, BANKED
331
	bz	SIDSE_Clk_NoF8
332
SIDSE_Clk_F8
333
	;; decrement counter by one (if there are more requests, they will be handled on next handler invocation
334
	decf	SID_CLK_REQ_CTR, F, BANKED
335
	;; if slave: continue at inc routine
336
	BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SIDSE_Clk_Inc
337
SIDSE_Clk_NoF8
338
 
339
	;; if slave: no Inc (only on F8 event)
340
	BRA_IFSET SID_STAT, SID_STAT_CLK_SLAVE, ACCESS, SIDSE_Clk_NoInc
341
 
342
	;; check timer0 overrun flag
343
	BRA_IFCLR INTCON, TMR0IF, ACCESS, SIDSE_Clk_NoInc
344
	bcf	INTCON, TMR0IF			; clear overrun flag
345
	SET_BSR	TIMER0_RELOAD_L
346
	bcf	T0CON, TMR0ON
347
	movf	TIMER0_RELOAD_L, W, BANKED	; (dummy add to update TMR0H, and to get carry flag of addition)
348
	addwf	TMR0L, W			; (update TMR0H)
349
	movf	TIMER0_RELOAD_H, W, BANKED
350
	addwfc	TMR0H, F
351
	movf	TIMER0_RELOAD_L, W, BANKED
352
	addwf	TMR0L, F			; 16bit register update takes place with this write
353
	bsf	T0CON, TMR0ON
354
	SET_BSR	SID_BASE
355
SIDSE_Clk_Inc
356
 
248 tk 357
	;; increment global clock counter (for Clk/6 and Clk/24 divider)
1 tk 358
	incf	SID_SE_GLOBAL_CLK_CTR, F, BANKED
359
 
248 tk 360
	;; reset lower nibble on each 6th clock, increment high nibble
361
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
362
	andlw	0x0f
363
	xorlw	0x06
364
	bnz	SIDSE_Clk_Inc_Not6th
365
SIDSE_Clk_Inc_6th
366
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
367
	addlw	0x10
368
	andlw	0xf0
369
	movwf	SID_SE_GLOBAL_CLK_CTR, BANKED
370
SIDSE_Clk_Inc_Not6th
371
 
1 tk 372
	;; notify clock event
373
	bsf	SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED
374
 
375
	;; clock propagation
376
	;; (static for Multi Engine)
377
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
378
	andlw	0x03
379
	bz	SIDSE_Clk_Reset_Lead
380
SIDSE_Clk_Reset_Multi
381
	movlw	0x80		; only step WTs (global flag bit #7 in multi mode)
382
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
383
	rgoto	SIDSE_Clk_Reset_Multi_Cont
248 tk 384
 
1 tk 385
SIDSE_Clk_Reset_Lead
386
 
387
	;; propagate clock event to trigger matrix
388
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_Clk_BASE
389
	rcall	SIDSE_Clk_Hlp_PropClkEvent
390
 
248 tk 391
	;; propagate clock/4 event to trigger matrix on each 6th clock
392
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_Cl6_BASE
1 tk 393
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
248 tk 394
	andlw	0x0f
1 tk 395
	skpnz
396
	rcall	SIDSE_Clk_Hlp_PropClkEvent
397
 
248 tk 398
	;; propagate clock/16 event to trigger matrix on each 24th clock
399
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_C24_BASE
1 tk 400
	movf	SID_SE_GLOBAL_CLK_CTR, W, BANKED
248 tk 401
	andlw	0x30
1 tk 402
	skpnz
403
	rcall	SIDSE_Clk_Hlp_PropClkEvent
404
 
405
SIDSE_Clk_Reset_Multi_Cont
406
SIDSE_Clk_NoReset
407
SIDSE_Clk_NoInc
408
 
409
SIDSE_Clk_End
410
	return
411
 
412
 
413
;; expecting pointer to SID_Ix_L_TRG_Clk*_BASE in FSR1
414
SIDSE_Clk_Hlp_PropClkEvent
415
	movf	POSTINC1, W
416
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
417
	movf	POSTINC1, W
418
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
419
	movf	POSTINC1, W
420
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
421
	return
422
 
423
 
424
 
425
;; --------------------------------------------------------------------------
426
;; This function handles the arpeggiators
427
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
428
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
429
;;     pointer to SIDx_MVx_BASE in FSR2 (MIDI voice record)
430
;;     Voice number in SID_SE_ELEMENT_NUM
431
;; --------------------------------------------------------------------------
432
SIDSE_Arp
433
	;; TODO: portamento handling on note overlaps
434
 
435
	;; clear temporary arp flags
436
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
437
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED
438
	bcf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
439
 
440
	;; check if arp sync requested
441
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Arp_Sync
442
	movlw	SID_MVx_ARP_STATE
443
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_SYNC_ARP, ACCESS, SIDSE_Arp_NoSync
444
SIDSE_Arp_Sync
445
	;; set arp counters to max value (forces proper reset)
446
	movlw	SID_MVx_ARP_NOTE_CTR
447
	setf	PLUSW2
448
	movlw	SID_MVx_ARP_OCT_CTR
449
	setf	PLUSW2
450
 
451
	;; reset ARP up flag (will be set to 1 with first note)
452
	movlw	SID_MVx_ARP_STATE
453
	bcf	PLUSW2, SID_MV_ARP_STATE_ARP_UP
454
 
455
	;; request first note (for oneshot function)
456
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED
457
 
458
	;; reset divider if not disabled or if arp synch on MIDI clock start event
459
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED, SIDSE_Arp_DivReset
460
	movlw	SID_Ix_Vx_ARP_MODE
461
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIV_SYNC, ACCESS, SIDSE_Arp_NoDivReset
462
SIDSE_Arp_DivReset
463
	movlw	SID_MVx_ARP_DIV_CTR
464
	setf	PLUSW2
465
	movlw	SID_MVx_ARP_GL_CTR
466
	setf	PLUSW2
467
	;; request new note
468
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
469
SIDSE_Arp_NoDivReset
470
SIDSE_Arp_NoSync
471
 
472
	;; if clock sync event:
473
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_Arp_NoClk
474
SIDSE_Arp_Clk
475
	;; increment clock divider
476
	;; reset divider if it already has reached the target value
477
 
478
	movlw	SID_Ix_Vx_ARP_MODE
479
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_CAC, ACCESS, SIDSE_Arp_Clk_NoCAC
480
SIDSE_Arp_Clk_CAC
481
	;; in CAC mode: increment depending on number of pressed keys
482
	movlw	SID_MVx_NOTE_STACK_PTR	; using note of MV1 note stack
483
	movf	PLUSW2, W
484
	skpnz
485
	movlw	1
486
	movwf	PRODL
487
	rgoto	SIDSE_Arp_Clk_CAC_Cont
488
 
489
SIDSE_Arp_Clk_NoCAC
490
	;; if CAC disabled: increment only by one
491
	movlw	1
492
	movwf	PRODL
493
 
494
SIDSE_Arp_Clk_CAC_Cont
495
	;; add to div counter, temp. store result in PRODL
496
	movlw	SID_MVx_ARP_DIV_CTR
497
	movf	PLUSW2, W
498
	addwf	PRODL, F
499
 
500
	;; max value -> PRODH
501
	movlw	SID_Ix_Vx_ARP_SPEED_DIV
502
	movf	PLUSW0, W
503
	andlw	0x3f
504
	addlw	1
505
	movwf	PRODH
506
 
507
	;; now subtract PRODH from PRODL until PRODL is < PRODH
508
SIDSE_Arp_Clk_FixLoop
509
	decf	PRODH, W
510
	cpfsgt	PRODL, ACCESS
511
	rgoto SIDSE_Arp_Clk_FixLoop_Break
512
	movf	PRODH, W
513
	subwf	PRODL, F	; F-WREG
514
 
515
	;; request new note
516
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED
517
 
518
	;; request gate clear if voice not active anymore (required if Gln>=Speed)
519
	movlw	SID_Vx_STATE
520
	btfss	PLUSW1, SID_V_STATE_VOICE_ACTIVE
521
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
522
 
523
	rgoto	SIDSE_Arp_Clk_FixLoop
524
 
525
SIDSE_Arp_Clk_FixLoop_Break
526
 
302 tk 527
	;; transfer new divider value into MVx register
1 tk 528
	movlw	SID_MVx_ARP_DIV_CTR
529
	movff	PRODL, PLUSW2
530
 
531
 
532
	;; increment gatelength counter
533
	;; reset counter if it already has reached the target value
534
	movlw	SID_MVx_ARP_GL_CTR
535
	incf	PLUSW2, F
536
	decf	PLUSW2, W
537
	movwf	PRODL
538
	movlw	SID_Ix_Vx_ARP_GL_RNG
539
	movf	PLUSW0, W
540
	andlw	0x1f
541
	addlw	1
542
	cpfslt	PRODL, ACCESS
302 tk 543
	rgoto	SIDSE_Arp_Clk_GlReset
1 tk 544
	rgoto	SIDSE_Arp_Clk_NoGlReset
545
SIDSE_Arp_Clk_GlReset
546
	;; reset counter
547
	movlw	SID_MVx_ARP_GL_CTR
548
	clrf	PLUSW2
549
 
550
	;; request gate clear
551
	bsf	SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED
552
SIDSE_Arp_Clk_NoGlReset
553
 
554
SIDSE_Arp_NoClk
555
 
556
 
557
	;; check if HOLD mode has been deactivated - disable notes in this case
558
	movlw	SID_Ix_Vx_ARP_MODE
559
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_HOLD, ACCESS, SIDSE_Arp_Hold_Active
560
SIDSE_Arp_Hold_NotActive
561
	;; check if HOLD flag was active before
562
	movlw	SID_MVx_ARP_STATE
563
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED, ACCESS, SIDSE_Arp_Hold_Cont
564
	;; clear HOLD flag and disable all notes
565
	bcf	PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED
566
	rgoto	SIDSE_Arp_NotActive
567
 
568
SIDSE_Arp_Hold_Active
569
	;; store HOLD flag in MIDI voice record
570
	movlw	SID_MVx_ARP_STATE
571
	bsf	PLUSW2, SID_MV_ARP_STATE_HOLD_SAVED
572
SIDSE_Arp_Hold_Cont
573
 
574
 
575
	;; skip the rest if arp is disabled
576
	movlw	SID_Ix_Vx_ARP_MODE
577
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_ENABLE, ACCESS, SIDSE_Arp_Active
578
SIDSE_Arp_NotActive
579
	;; check if arp was active before (for proper 1->0 transition when ARP is disabled)
580
	movlw	SID_MVx_ARP_STATE
581
	BRA_IFCLR PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE, ACCESS, SIDSE_Arp_End
582
 
583
	;; notify that arp is not active anymore
584
	bcf	PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE
585
 
586
	;; clear note stack (especially important in HOLD mode!)
587
	movlw	SID_MVx_NOTE_STACK_PTR
588
	movwf	PRODL
589
SIDSE_Arp_NotActive_ClrLoop
590
	movf	PRODL, W
591
	clrf	PLUSW2
592
	incf	PRODL, F
593
	movlw	SID_MVx_NOTE_STACK_0 + SID_MVx_NOTE_STACK_LEN - 1
594
	cpfsgt	PRODL, ACCESS
595
	rgoto SIDSE_Arp_NotActive_ClrLoop
596
 
597
	;; propagate Note Off through trigger matrix
598
	;; (static for Multi Engine)
599
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
600
	andlw	0x03
601
	bz	SIDSE_Arp_NotActive_ClrLoop_L
602
SIDSE_Arp_NotActive_ClrLoop_M
603
	;; only ENV release phase
604
	movf	SID_SE_ELEMENT_NUM, W, BANKED
605
	call	MIOS_HLP_GetBitORMask
606
	iorwf	SID_SE_TRG_EVNT_ENVR, F, BANKED
607
	rgoto	SIDSE_Arp_NotActive_ClrLoop_C
608
SIDSE_Arp_NotActive_ClrLoop_L
609
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, WREG
379 tk 610
	andlw	0xc0		; (Gates handled separately by Arp)
1 tk 611
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
612
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 1, WREG
613
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
614
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 2, WREG
615
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
616
SIDSE_Arp_NotActive_ClrLoop_C
617
 
618
	;; request gate clear
619
	movlw	SID_Vx_STATE
620
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
621
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
622
 
623
	rgoto	SIDSE_Arp_End
624
 
625
 
626
SIDSE_Arp_Active
627
	;; notify that arp is active (for proper 1->0 transition when ARP is disabled)
628
	movlw	SID_MVx_ARP_STATE
629
	bsf	PLUSW2, SID_MV_ARP_STATE_ARP_ACTIVE
630
 
631
	;; check if voice not active anymore (not valid in HOLD mode) or gate clear has been requested
632
	;; skip voice active check in hold mode
633
	movlw	SID_Ix_Vx_ARP_MODE
634
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_HOLD, ACCESS, SIDSE_Arp_GateClr_Hold
635
	;; skip voice active check in voice sync mode
636
	movlw	SID_Ix_Vx_ARP_MODE
637
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIV_SYNC, ACCESS, SIDSE_Arp_GateClr_Sync
638
	movlw	SID_Vx_STATE
639
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SIDSE_Arp_GateClr
640
SIDSE_Arp_GateClr_Sync
641
SIDSE_Arp_GateClr_Hold
642
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ARP_GATE_CLR_REQ, BANKED, SIDSE_Arp_NoGateClr
643
SIDSE_Arp_GateClr
644
	;; forward this to note handler if gate is not already deactivated
645
	movlw	SID_Vx_STATE
646
	BRA_IFCLR PLUSW1, SID_V_STATE_GATE_ACTIVE, ACCESS, SIDSE_Arp_NoGateClr
647
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
648
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
649
	;; Note Off ENV/LFO/... synchronisation via trigger matrix
650
	;; (static for Multi Engine)
651
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
652
	andlw	0x03
653
	bz	SIDSE_Arp_GateClr_Lead
654
SIDSE_Arp_GateClr_Multi
655
	;; only ENV release phase
656
	movf	SID_SE_ELEMENT_NUM, W, BANKED
657
	call	MIOS_HLP_GetBitORMask
658
	iorwf	SID_SE_TRG_EVNT_ENVR, F, BANKED
659
	rgoto	SIDSE_Arp_GateClr_Multi_Cont
660
SIDSE_Arp_GateClr_Lead
661
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, WREG
379 tk 662
	andlw	0xc0		; (Gates handled separately by Arp)
1 tk 663
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
664
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 1, WREG
665
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
666
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 2, WREG
667
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
668
SIDSE_Arp_GateClr_Multi_Cont
669
SIDSE_Arp_NoGateClr
670
 
671
	;; check if a new arp note has been requested
672
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ARP_NEW_NOTE_REQ, BANKED, SIDSE_Arp_NoNewNote
673
SIDSE_Arp_NewNote
674
	;; skip if note counter is 0xaa (oneshot mode)
675
	movlw	SID_MVx_ARP_NOTE_CTR
676
	movf	PLUSW2, W
677
	xorlw	0xaa
678
	skpnz
679
	rgoto	SIDSE_Arp_NoNewNote
680
 
681
	;; increment arp counter
682
	movlw	SID_MVx_ARP_NOTE_CTR
683
	incf	PLUSW2, F
684
 
685
	;; reset gatelength counter
686
	movlw	SID_MVx_ARP_GL_CTR
687
	clrf	PLUSW2
688
 
689
	;; if max value of arp note counter reached, reset it
690
	movlw	SID_MVx_ARP_NOTE_CTR
691
	movff	PLUSW2, PRODL
692
	movlw	SID_MVx_NOTE_STACK_LEN
693
	cpfslt	PRODL, ACCESS
694
	clrf PRODL
695
 
696
	;; if note is zero, reset arp note counter
697
	movf	PRODL, W
698
	addlw	SID_MVx_NOTE_STACK_0
699
	movf	PLUSW2, W
700
	skpnz
701
	clrf	PRODL
702
 
703
	;; don't play if note still zero
704
	movf	PRODL, W
705
	addlw	SID_MVx_NOTE_STACK_0
706
	movf	PLUSW2, W
707
	skpnz
708
	rgoto	SIDSE_Arp_NoNewNote
709
 
710
	;; store new arp note counter
711
	movlw	SID_MVx_ARP_NOTE_CTR
712
	movff	PRODL, PLUSW2
713
 
714
	;; dir mode 6 (and 7) selects random direction
715
	movlw	SID_Ix_Vx_ARP_MODE
716
	rrf	PLUSW0, W
717
	andlw	0x06
718
	xorlw	0x06
719
	bz	SIDSE_Arp_NewNote_Rnd
720
 
721
	;; in DIR_ALT mode: branch depending on Up/Down flag
722
	movlw	SID_Ix_Vx_ARP_MODE
723
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_ALT2, ACCESS, SIDSE_Arp_NewNote_AltDir
724
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_DIR_ALT, ACCESS, SIDSE_Arp_NewNote_NoAltDir
725
SIDSE_Arp_NewNote_AltDir
726
	;; toggle ARP_UP flag each time the arp note counter is zero
727
	movf	PRODL, W
728
	bnz	SIDSE_Arp_NewNote_AltDir_NoTog
729
SIDSE_Arp_NewNote_AltDir_Tog
730
	movlw	SID_MVx_ARP_STATE
731
	btg	PLUSW2, SID_MV_ARP_STATE_ARP_UP
732
 
733
	;; if not ALT2 mode: increment PRODL to prevent double played notes
734
	movlw	SID_Ix_Vx_ARP_MODE
735
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_ALT2, ACCESS, SIDSE_Arp_NewNote_AltDir_Alt2
736
SIDSE_Arp_NewNote_AltDirNoAlt2
737
	incf	PRODL, F
738
SIDSE_Arp_NewNote_AltDir_Alt2
739
 
740
	;; reset PRODL again if note is zero (only one note played)
741
	movf	PRODL, W
742
	addlw	SID_MVx_NOTE_STACK_0
743
	movf	PLUSW2, W
744
	skpnz
745
	clrf	PRODL
746
 
747
	;; store updated arp note counter
748
	movlw	SID_MVx_ARP_NOTE_CTR
749
	movff	PRODL, PLUSW2
750
SIDSE_Arp_NewNote_AltDir_NoTog
751
 
752
	;; branch depending on Arp Up/Down and Alt Up/Down flag
753
	movlw	SID_Ix_Vx_ARP_MODE
754
	BRA_IFSET PLUSW0, SID_I_V_ARP_MODE_DIR_DOWN, ACCESS, SIDSE_Arp_NewNote_AltDir_D
755
SIDSE_Arp_NewNote_AltDir_U
756
	movlw	SID_MVx_ARP_STATE
757
	BRA_IFSET PLUSW2, SID_MV_ARP_STATE_ARP_UP, ACCESS, SIDSE_Arp_NewNote_Up
758
	rgoto	SIDSE_Arp_NewNote_Down
759
SIDSE_Arp_NewNote_AltDir_D
760
	movlw	SID_MVx_ARP_STATE
761
	BRA_IFSET PLUSW2, SID_MV_ARP_STATE_ARP_UP, ACCESS, SIDSE_Arp_NewNote_Down
762
	rgoto	SIDSE_Arp_NewNote_Up
763
 
764
SIDSE_Arp_NewNote_NoAltDir
765
 
766
	;; branch depending on direction
767
	movlw	SID_Ix_Vx_ARP_MODE
768
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_DIR_DOWN, ACCESS, SIDSE_Arp_NewNote_Up
769
SIDSE_Arp_NewNote_Down
770
	;; offset to last note stack entry: PTR-1-PRODL
771
	movlw	SID_MVx_NOTE_STACK_PTR
772
	movf	PLUSW2, W
773
	bz	SIDSE_Arp_NewNote_Down_NoNote
774
	addlw	-1
775
	movwf	PRODH
776
	movf	PRODL, W
777
	subwf	PRODH, W
778
	movwf	PRODL
779
SIDSE_Arp_NewNote_Down_NoNote
780
	rgoto	SIDSE_Arp_NewNote_Down_Cont
781
 
782
SIDSE_Arp_NewNote_Rnd
783
	;; generate new random number
784
	call	SID_RND_GenRandomNumber
785
	;; scale between 0 and SID_MVx_NOTE_STACK_PTR-1
786
	movlw	SID_MVx_NOTE_STACK_PTR
787
	movf	PLUSW2, W	; (ok, no dec!)
788
	mulwf	SID_RANDOM_SEED_L, BANKED
789
	movff	PRODH, PRODL	; new pointer in PRODL
790
 
791
SIDSE_Arp_NewNote_Down_Cont
792
SIDSE_Arp_NewNote_Up
793
 
878 tk 794
	;; now check for oneshot mode: if note is 0, or if note counter and oct counter is 0, stop here
1 tk 795
	movlw	SID_Ix_Vx_ARP_SPEED_DIV
796
	BRA_IFCLR PLUSW0, SID_I_V_ARP_SPEED_DIV_ONESHOT, ACCESS, SIDSE_Arp_NewNote_NoOneShot
797
SIDSE_Arp_NewNote_OneShot
798
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_ARP_FIRST_NOTE_REQ, BANKED, SIDSE_Arp_NewNote_NoOneShot
799
	movf	PRODL, W
800
	addlw	SID_MVx_NOTE_STACK_0
801
	movf	PLUSW2, W
802
	bz	SIDSE_Arp_NewNote_OneShot_Ok
803
	movf	PRODL, W
804
	movlw	SID_MVx_ARP_NOTE_CTR
805
	movf	PLUSW2, W
806
	bnz	SIDSE_Arp_NewNote_NoOneShot
807
	movlw	SID_MVx_ARP_OCT_CTR
808
	movf	PLUSW2, W
809
	bnz	SIDSE_Arp_NewNote_NoOneShot
810
 
811
SIDSE_Arp_NewNote_OneShot_Ok
812
	;; set note counter to 0xaa to stop ARP until next reset
813
	movlw	0xaa
814
	movwf	PRODL
815
	movlw	SID_MVx_ARP_NOTE_CTR
816
	movff	PRODL, PLUSW2
817
	rgoto	SIDSE_Arp_NoNewNote
818
SIDSE_Arp_NewNote_NoOneShot
819
 
820
	;; store new arp note if != 0
821
	movf	PRODL, W
822
	addlw	SID_MVx_NOTE_STACK_0
823
	movf	PLUSW2, W
824
	andlw	0x7f
825
	movwf	PRODH
826
	movlw	SID_Vx_ARP_NOTE
827
	skpz
828
	movff	PRODH, PLUSW1
829
 
830
	;; if counter is 0, increase octave until max value is reached
831
	movf	PRODL, W
832
	bnz	SIDSE_Arp_NewNote_NoOctInc
833
SIDSE_Arp_NewNote_OctInc
834
	movlw	SID_MVx_ARP_OCT_CTR
835
	incf	PLUSW2, F
836
	decf	PLUSW2, W
837
	movwf	PRODL
838
	movlw	SID_Ix_Vx_ARP_GL_RNG
839
	swapf	PLUSW0, W
840
	rrf	WREG, W
841
	andlw	0x07
842
	cpfslt	PRODL, ACCESS
843
	rgoto SIDSE_Arp_NewNote_OctReset
844
	rgoto	SIDSE_Arp_NewNote_NoOctReset
845
SIDSE_Arp_NewNote_OctReset
846
	;; reset octave counter
847
	movlw	SID_MVx_ARP_OCT_CTR
848
	clrf	PLUSW2
849
SIDSE_Arp_NewNote_NoOctReset
850
 
851
SIDSE_Arp_NewNote_NoOctInc
852
	;; transpose note by 12*octave counter
853
	movlw	SID_MVx_ARP_OCT_CTR
854
	movf	PLUSW2, W
855
	bz	SIDSE_Arp_NewNote_OctNoTrans
856
	mullw	12
857
SIDSE_Arp_NewNote_OctTrans
858
	movlw	SID_Vx_ARP_NOTE
859
	movf	PLUSW1, W
860
	addwf	PRODL, W
861
	movwf	PRODH
862
 
863
	;; if >0x6b, decrement by 12 until we are in 0x00..0x6b range again
864
	;; (range 0x6c..0x7f sets frequency to 0xffff...)
865
SIDSE_Arp_NewNote_OctTransSat
866
	movlw	0x6b
867
	cpfsgt	PRODH, ACCESS
868
	rgoto SIDSE_Arp_NewNote_OctTransOk
869
	movlw	-12
870
	addwf	PRODH, F
871
	rgoto	SIDSE_Arp_NewNote_OctTransSat
872
SIDSE_Arp_NewNote_OctTransOk
873
	movlw	SID_Vx_ARP_NOTE
874
	movff	PRODH, PLUSW1
875
SIDSE_Arp_NewNote_OctNoTrans
876
 
877
	;; forward gate set request if voice is active and gate not active
878
	movlw	SID_Vx_STATE
879
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SIDSE_Arp_NewNote_NoOn
880
SIDSE_Arp_NewNote_NoVAChk
881
	movlw	SID_Vx_STATE
882
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ	; ensure that gate won't be cleared by previous CLR_REQ
883
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_ACTIVE, ACCESS, SIDSE_Arp_NewNote_NoOn
884
SIDSE_Arp_NewNote_On
885
	;; set gate
886
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
887
 
888
	;; Note On ENV/LFO/... synchronisation via trigger matrix
889
	;; (static for Multi Engine)
890
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
891
	andlw	0x03
892
	bz	SIDSE_Arp_NewNote_Lead
893
SIDSE_Arp_NewNote_Multi
894
	;; only ENV attack, LFO sync and WT reset
895
	movf	SID_SE_ELEMENT_NUM, W, BANKED
896
	call	MIOS_HLP_GetBitORMask
897
	iorwf	SID_SE_TRG_EVNT_ENVA, F, BANKED
898
 
899
	movf	SID_SE_ELEMENT_NUM, W, BANKED
900
	addlw	2
901
	call	MIOS_HLP_GetBitORMask
902
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
903
 
904
	movlw	0x3f
905
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
906
	;; TODO: optional LFO resync!
907
	rgoto	SIDSE_Arp_NewNote_Cont
908
 
909
SIDSE_Arp_NewNote_Lead
910
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 0, WREG
379 tk 911
	andlw	0xc0		; (gates handled separately)
1 tk 912
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
913
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 1, WREG
914
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
915
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 2, WREG
916
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
917
SIDSE_Arp_NewNote_Cont
918
SIDSE_Arp_NewNote_NoOn
919
 
920
SIDSE_Arp_NoNewNote
921
 
922
SIDSE_Arp_End
923
	;; clear arp sync flag
924
	movlw	SID_MVx_ARP_STATE
925
	bcf	PLUSW2, SID_MV_ARP_STATE_SYNC_ARP
926
 
927
	return
928
 
929
 
930
 
931
;; --------------------------------------------------------------------------
932
;; This function handles the Voice Gate
933
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
934
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
935
;;     Voice number in SID_SE_ELEMENT_NUM
936
;;     If SIDSE_Gate_Drums is called: bit #4 of Waveform (disable bit) in IRQ_TMP1
937
;; OUT: ZERO flag set if pitch should be changed
938
;; --------------------------------------------------------------------------
939
SIDSE_Gate
940
	;; small variation between Lead/Bassline/Multi Engine, and Drum Engine:
941
	;; for Drum Engine the waveform is predefined in model table, and not
942
	;; part of the patch (drum engine has to call SIDSE_Gate_Drums with
943
	;; waveform[4] in IRQ_TMP1)
944
	movlw	SID_Ix_Vx_WAVEFORM
945
	movff	PLUSW0, IRQ_TMP1
946
 
947
SIDSE_Gate_Drums		; expecting waveform[4] in IRQ_TMP1
948
 
949
	;; transfer pointer to SIDx_Vx_FRQ_L register -> FSR2
950
	call	SIDSE_Hlp_GetSIDFrqPtr
951
 
952
	;; voice disable handling (allows to turn on/off voice via waveform parameter)
953
	movlw	SID_Vx_STATE
954
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_DISABLED, ACCESS, SIDSE_Gate_VoiceNotDisabled
955
SIDSE_Gate_VoiceDisabled
956
	BRA_IFSET IRQ_TMP1, 4, ACCESS, SIDSE_Gate_Voice_Cont	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
957
	movlw	SID_Vx_STATE
958
	bcf	PLUSW1, SID_V_STATE_VOICE_DISABLED
959
	btfsc	PLUSW1, SID_V_STATE_VOICE_ACTIVE
960
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
961
	rgoto	SIDSE_Gate_Voice_Cont
962
SIDSE_Gate_VoiceNotDisabled
963
	BRA_IFCLR IRQ_TMP1, 4, ACCESS, SIDSE_Gate_Voice_Cont	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
964
	movlw	SID_Vx_STATE
965
	bsf	PLUSW1, SID_V_STATE_VOICE_DISABLED
966
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
967
	;; 	rgoto	SIDSE_Gate_Voice_Cont
968
SIDSE_Gate_Voice_Cont
969
 
970
	;; if gate not active: ignore clear request
971
	movlw	SID_Vx_STATE
972
	btfss	PLUSW1, SID_V_STATE_GATE_ACTIVE
973
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
974
 
975
	;; gate set/clear request?
976
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_CLR_REQ, ACCESS, SIDSE_Gate_ClrReq
977
	BRA_IFSET PLUSW1, SID_V_STATE_GATE_SET_REQ, ACCESS, SIDSE_Gate_SetReq
978
	rgoto	SIDSE_Gate_Skip
979
SIDSE_Gate_ClrReq
980
	bcf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
981
 
982
	movlw	SIDx_V1_CTRL
983
	bcf	PLUSW2, 3	; SIDx_Vx_CTRL.3 is the test bit which allows to sync an oscillator
984
 
985
	;; clear SID gate flag (SIDx_Vx_CTRL.0) if GSA (gate stays active) function not enabled
986
	movlw	SID_Ix_Vx_FLAGS1
987
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_GSA, ACCESS, SIDSE_Gate_ClrReq_GSA
988
SIDSE_Gate_ClrReq_NoGSA
989
	movlw	SIDx_V1_CTRL
990
	bcf	PLUSW2, 0
991
SIDSE_Gate_ClrReq_GSA
992
 
993
	;; gate not active anymore
994
	movlw	SID_Vx_STATE
995
	bcf	PLUSW1, SID_V_STATE_GATE_ACTIVE
996
 
997
	;; sync with SID_SR handler
998
	movf	SID_SE_ELEMENT_NUM, W, BANKED
999
	call	MIOS_HLP_GetBitORMask
1000
	iorwf	SID_SE_SR_UPDATE_SYNC, F, BANKED	; (cleared by SID_SR_Handler)
1001
 
1002
	rgoto	SIDSE_Gate_End
1003
 
1004
SIDSE_Gate_SetReq
1005
	;; skip so long SRs haven't been updated
1006
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1007
	call	MIOS_HLP_GetBitORMask
1008
	andwf	SID_SE_SR_UPDATE_SYNC, W, BANKED
1009
	bnz	SIDSE_Gate_Skip
1010
 
1011
	;; don't set gate if oscillator disabled
1012
	BRA_IFSET IRQ_TMP1, 4, ACCESS, SIDSE_Gate_SetReqSkp	; IRQ_TMP1 == SID_Ix_Vx_WAVEFORM
1013
 
1014
	;; temporary shift FSR1 to SID_Vx_SET_DELAY_CTR_L for easier handling
1015
	movlw	SID_Vx_SET_DELAY_CTR_L
1016
	addwf	FSR1L, F
1017
 
1018
	;; delay note so long 16bit delay counter != 0
1019
	movf	POSTINC1, W
1020
	iorwf	POSTDEC1, W
1021
	bz	SIDSE_Gate_SetReq_NoDelay
1022
SIDSE_Gate_SetReq_Delay
1023
	;; increment counter, set it to zero on overrun (no delay anymore)
1024
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1025
	andlw	0x03
1026
	xorlw	0x02
1027
	bnz	SIDSE_Gate_SetReq_Delay_LBM
1028
SIDSE_Gate_SetReq_Delay_D
1029
	clrf	IRQ_TMP3	; not available for drum engine
1030
	rgoto	SIDSE_Gate_SetReq_Delay_Cont
1031
SIDSE_Gate_SetReq_Delay_LBM
1032
	movlw	SID_Ix_Vx_DELAY
1033
	movff	PLUSW0, IRQ_TMP3; incrementer is the same like used for envelopes
1034
SIDSE_Gate_SetReq_Delay_Cont
1035
 
1036
	;; if ABW (ADSR bug workaround) active: use at least 30 ms delay
1037
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
1038
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_Gate_SetReq_DelayNoA
1039
SIDSE_Gate_SetReq_DelayABW
1040
	movlw	25
1041
	addwf	IRQ_TMP3, F
1042
	skpnc
1043
	setf	IRQ_TMP3
1044
SIDSE_Gate_SetReq_DelayNoA
1045
 
1046
	movlw	0x80		; curve *must* be disabled!
1047
	call	SIDSE_Hlp_ENV_GetBendedValue	; incrementer in MIOS_PARAMETER[12]
1048
	movf	MIOS_PARAMETER1, W
1049
	addwf	POSTINC1, F
1050
	movf	MIOS_PARAMETER2, W
1051
	addwfc	POSTDEC1, F
1052
	bc	SIDSE_Gate_SetReq_DelayOv
1053
	movlw	-SID_Vx_SET_DELAY_CTR_L	; switch back to SID_Vx_CTR_L
1054
	addwf	FSR1L, F
1055
#if 0
1056
	rgoto	SIDSE_Gate_End
1057
#else
1058
	;; experimental: don't modify frequency so long delay is active!
1059
	;; this is especially to avoid, that a new note frequency will already be set before the envelope is released
1060
	rgoto	SIDSE_Gate_End_NoPitch
1061
#endif
1062
SIDSE_Gate_SetReq_DelayOv
1063
	;; overrun: clear counter to disable delay
1064
	clrf	POSTINC1
1065
	clrf	POSTDEC1
1066
SIDSE_Gate_SetReq_NoDelay
1067
	movlw	-SID_Vx_SET_DELAY_CTR_L	; switch back to SID_Vx_CTR_L
1068
	addwf	FSR1L, F
1069
 
1070
	;; now acknowledge the set request
1071
	movlw	SID_Vx_STATE
1072
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
1073
 
1074
	;; if ABW (ADSR bug workaround) function active: update ADSR registers now!
1075
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
1076
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_Gate_SetReq_NoABW
1077
SIDSE_Gate_SetReq_ABW
1078
	movlw	SID_Ix_Vx_AD
1079
	movff	PLUSW0, PRODL
1080
	movlw	SIDx_V1_ENV_AD
1081
	movff	PRODL, PLUSW2
1082
 
1083
	;; accent only used in bassline and drum mode
1084
	;; force sustain to maximum if accent active
1085
	movlw	SID_Ix_Vx_SR
1086
	movff	PLUSW0, PRODL
1087
	movlw	SID_Vx_STATE
1088
	BRA_IFCLR PLUSW1, SID_V_STATE_ACCENT, ACCESS, SIDSE_Gate_SetReq_ABW_NoAcc
1089
SIDSE_Gate_SetReq_ABW_Acc
1090
	movlw	0xf0
1091
	iorwf	PRODL, F
1092
SIDSE_Gate_SetReq_ABW_NoAcc
1093
	movlw	SIDx_V1_ENV_SR
1094
	movff	PRODL, PLUSW2
1095
SIDSE_Gate_SetReq_NoABW
1096
 
1097
	;; branch for phase synchronisation: set test flag instead of gate
1098
	;; a special handler in sid_sr.inc will take care about the rest
1099
 
1100
	;; different handling depending on selected engine:
362 tk 1101
	;; lead and bassline engine: global sync for all voices with phase shift
1 tk 1102
	;; multi engine has individual flag for each instrument
1103
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1104
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Gate_SetReq_Sync_DM
1105
SIDSE_Gate_SetReq_Sync_LB
1106
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Gate_SetReq_Sync_B
1107
SIDSE_Gate_SetReq_Sync_L
362 tk 1108
SIDSE_Gate_SetReq_Sync_B
1 tk 1109
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_PHASE, WREG
1110
	andlw	0xff
1111
	bz	SIDSE_Gate_SetReq_NoSync
1112
	rgoto	SIDSE_Gate_SetReq_Sync_Cont
1113
 
362 tk 1114
#if 0
1 tk 1115
SIDSE_Gate_SetReq_Sync_B
1116
	movlw	SID_Ix_B_Vx_FLAGS2
1117
	BRA_IFCLR PLUSW0, SID_I_M_V_FLAGS2_PHASE, ACCESS, SIDSE_Gate_SetReq_NoSync
1118
	rgoto	SIDSE_Gate_SetReq_NoSync
362 tk 1119
#endif
1 tk 1120
 
1121
SIDSE_Gate_SetReq_Sync_DM
1122
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Gate_SetReq_Sync_M
1123
SIDSE_Gate_SetReq_Sync_D
1124
	;; synchronisation requested in SIDSE_D_NOTE_Restart
1125
	rgoto	SIDSE_Gate_SetReq_NoSync
1126
 
1127
SIDSE_Gate_SetReq_Sync_M
1128
	movlw	SID_Ix_M_Vx_FLAGS2
1129
	BRA_IFCLR PLUSW0, SID_I_M_V_FLAGS2_PHASE, ACCESS, SIDSE_Gate_SetReq_NoSync
1130
	;; 	rgoto	SIDSE_Gate_SetReq_Sync_Cont
1131
 
1132
SIDSE_Gate_SetReq_Sync_Cont
1133
	;; set SID test flag (SIDx_Vx_CTRL.3), ensure that gate flag not set
1134
	movlw	SIDx_V1_CTRL
1135
	bsf	PLUSW2, 3
1136
	bcf	PLUSW2, 0
1137
 
1138
	;; notify sync request
1139
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1140
	call	MIOS_HLP_GetBitORMask
1141
	iorwf	SID_SE_PHASE_SYNC_REQ, F, BANKED
1142
 
1143
	rgoto	SIDSE_Gate_SetReq_NoGate
1144
 
1145
SIDSE_Gate_SetReq_NoSync
1146
	;; set SID gate flag (SIDx_Vx_CTRL.0)
1147
	movlw	SIDx_V1_CTRL
1148
	bsf	PLUSW2, 0
1149
 
1150
SIDSE_Gate_SetReq_NoGate
1151
SIDSE_Gate_SetReqSkp
1152
	movlw	SID_Vx_STATE
1153
	bsf	PLUSW1, SID_V_STATE_GATE_ACTIVE
1154
 
1155
SIDSE_Gate_End
1156
SIDSE_Gate_Skip
1157
	iorlw	0xff		; clear ZERO flag (-> pitch should be changed)
1158
	return
1159
 
1160
 
1161
SIDSE_Gate_End_NoPitch
1162
	andlw	0x00		; set ZERO flag (-> pitch should not be changed)
1163
	return
1164
 
1165
 
1166
;; --------------------------------------------------------------------------
1167
;; This function handles the Voice Pitch
1168
;; IN: pointer to SID_Ix_e_SxVy_BASE in FSR0 (patch record)
1169
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
1170
;;     Voice number in SID_SE_ELEMENT_NUM
1171
;; --------------------------------------------------------------------------
1172
SIDSE_Pitch
1173
	;; ------------------------------------------------------------------
1174
	;; Transpose MIDI Note
1175
	;; ------------------------------------------------------------------
1176
SIDSE_Pitch_Transp
1177
	;; if arp mode is active: use SID_Vx_ARP_NOTE, otherwise SID_Vx_NOTE
1178
	movlw	SID_Ix_Vx_ARP_MODE
1179
	BRA_IFCLR PLUSW0, SID_I_V_ARP_MODE_ENABLE, ACCESS, SIDSE_Pitch_Transp_NoArp
1180
SIDSE_Pitch_Transp_Arp
1181
	movlw	SID_Vx_ARP_NOTE
1182
	rgoto	SIDSE_Pitch_Transp_Cont
1183
SIDSE_Pitch_Transp_NoArp
1184
	movlw	SID_Vx_NOTE
1185
	;; 	rgoto	SIDSE_Pitch_Transp_Cont
1186
SIDSE_Pitch_Transp_Cont
1187
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1188
 
368 tk 1189
	;; pointer to MIDI voice -> FSR2
1 tk 1190
	lfsr	FSR2, SID_MV1_BASE
1191
	movlw	SID_Vx_ASSIGNED_MV
1192
	movf	PLUSW1, W
1193
	mullw	SID_MVx_RECORD_LEN
1194
	movf	PRODL, W
1195
	addwf	FSR2L, F
1196
 
362 tk 1197
	;; copy transpose value to IRQ_TMP2 (will be modified by bassline engine depending on voice)
1198
	movlw	SID_Ix_Vx_TRANSPOSE
1199
	movff	PLUSW0, IRQ_TMP2
1200
 
1 tk 1201
	;; add voice based transpose to MIDI voice based transpose and saturate
1202
	;; if lead engine: transpose value taken from first MIDI voice!
1203
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1204
	andlw	0x03
1205
	xorlw	0x01
1206
	bnz	SIDSE_Pitch_Transp_NoBassline
1207
SIDSE_Pitch_Transp_Bassline
362 tk 1208
	;; get transpose value depending on voice number
1209
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1210
	bz	SIDSE_Pitch_Transp_Bassline_V1L
1211
	addlw	-1
1212
	bz	SIDSE_Pitch_Transp_Bassline_V2L
1213
	addlw	-1
1214
	bz	SIDSE_Pitch_Transp_Bassline_V3L
1215
	addlw	-1
1216
	bz	SIDSE_Pitch_Transp_Bassline_V1R
1217
	addlw	-1
1218
	bz	SIDSE_Pitch_Transp_Bassline_V2R
1219
	;; 	rgoto	SIDSE_Pitch_Transp_Bassline_V3R
1220
 
1221
SIDSE_Pitch_Transp_Bassline_V3L	; octave transpose based on SID_Ix_B_V3_OCT_TRANSPOSE
1222
SIDSE_Pitch_Transp_Bassline_V3R
1223
	;; change transposed note to static note?
1224
	movlw	SID_Ix_B_V3_STATIC_NOTE
1225
	movf	PLUSW0, W
1226
	bz	SIDSE_Pitch_Transp_Bassline_V3RT
1227
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1228
SIDSE_Pitch_Transp_Bassline_V3RT
1229
	movlw	SID_Ix_B_V3_OCT_TRANSPOSE
1230
	rgoto	SIDSE_Pitch_Transp_Bassline_V23C
1231
 
1232
SIDSE_Pitch_Transp_Bassline_V2L	; octave transpose based on SID_Ix_B_V2_OCT_TRANSPOSE
1233
SIDSE_Pitch_Transp_Bassline_V2R
1234
	;; change transposed note to static note?
1235
	movlw	SID_Ix_B_V2_STATIC_NOTE
1236
	movf	PLUSW0, W
1237
	bz	SIDSE_Pitch_Transp_Bassline_V2RT
1238
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1239
SIDSE_Pitch_Transp_Bassline_V2RT
1240
	movlw	SID_Ix_B_V2_OCT_TRANSPOSE
1241
SIDSE_Pitch_Transp_Bassline_V23C
1242
	movf	PLUSW0, W	; zero: no transpose
1243
	bz	SIDSE_Pitch_Transp_Bassline_Cont
1244
	movwf	IRQ_TMP3	; (to store sign in bit [2])
1245
	andlw	0x03		; transpose
1246
	BRA_IFCLR IRQ_TMP3, 2, ACCESS, SIDSE_Pitch_Transp_Bassline_NNeg	; revert if negative
1247
SIDSE_Pitch_Transp_Bassline_Neg
1248
	xorlw	0x03
1249
	addlw	1
1250
SIDSE_Pitch_Transp_Bassline_NNeg
1251
	mullw	12		; *12 notes
1252
	;; add/subtract based on sign
1253
	BRA_IFSET IRQ_TMP3, 2, ACCESS, SIDSE_Pitch_Transp_Bassline_N
1254
SIDSE_Pitch_Transp_Bassline_P
1255
	movf	PRODL, W
1256
	addwf	IRQ_TMP2, F
1257
	;; octavewise saturation
1258
SIDSE_Pitch_Transp_Bassline_PLop
1259
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Pitch_Transp_Bassline_Cont
1260
	movlw	-12
1261
	addwf	IRQ_TMP2, F
1262
	rgoto	SIDSE_Pitch_Transp_Bassline_PLop
1263
 
1264
SIDSE_Pitch_Transp_Bassline_N
1265
	comf	PRODL, W
1266
	addlw	1
1267
	addwf	IRQ_TMP2, F
1268
	;; octavewise saturation
1269
SIDSE_Pitch_Transp_Bassline_NLop
1270
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Pitch_Transp_Bassline_Cont
1271
	movlw	12
1272
	addwf	IRQ_TMP2, F
1273
	rgoto	SIDSE_Pitch_Transp_Bassline_NLop
1274
 
1275
SIDSE_Pitch_Transp_Bassline_V1L	; SID_Ix_Vx_TRANSPOSE already in IRQ_TMP2
1276
SIDSE_Pitch_Transp_Bassline_V1R
1277
SIDSE_Pitch_Transp_Bassline_Cont
1278
 
368 tk 1279
	;; if WTO enabled, note is transposed via MIDI voice 3/4
1 tk 1280
	movlw	SID_Ix_B_Vx_FLAGS2
368 tk 1281
	BRA_IFCLR PLUSW0, SID_I_B_V_FLAGS2_WT_ONLY, ACCESS, SIDSE_Pitch_Transp_NoBasslineSeq
1282
	;; no transpose if channel disabled (to ensure compatibility with older ensemble settings)
1283
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_MIDI_CHANNEL
1284
	movf	PLUSW2, W
1285
	andlw	0xf0
1286
	bnz	SIDSE_Pitch_Transp_NoIns34Trans
1287
SIDSE_Pitch_Transp_Ins34Trans
1288
	;; copy transpose value of midi voice into IRQ_TMP1
1289
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_TRANSPOSE
1290
	movff	PLUSW2, IRQ_TMP1
1291
	;; and if note has been played: use it for transpose as well
1292
	movlw	2*SID_MVx_RECORD_LEN + SID_MVx_NOTE_STACK_0
1293
	movf	PLUSW2, W
1294
	andlw	0x7f
1295
	bz	SIDSE_Pitch_Transp_Ins34TransNoN
1296
	addlw	-0x3c		; (decrement base note C-3)
1297
	addwf	IRQ_TMP1, F
1298
	BRA_IFCLR IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransNoO ; saturation?
1299
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvN ; saturate depending on sign
1300
SIDSE_Pitch_Transp_Ins34TransOvP
1301
	movlw	-12
1302
	addwf	IRQ_TMP1, F
1303
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvP
1304
	rgoto	SIDSE_Pitch_Transp_Ins34TransOvC
1305
SIDSE_Pitch_Transp_Ins34TransOvN
1306
	movlw	12
1307
	addwf	IRQ_TMP1, F
1308
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Ins34TransOvN
1309
	;; 	rgoto	SIDSE_Pitch_Transp_Ins34TransOvC
1310
SIDSE_Pitch_Transp_Ins34TransOvC
1311
SIDSE_Pitch_Transp_Ins34TransNoO
1312
SIDSE_Pitch_Transp_Ins34TransNoN
1313
	rgoto	SIDSE_Pitch_Transp_Bassline_Seq
1314
 
1315
SIDSE_Pitch_Transp_NoIns34Trans
1316
	movlw	0x40		; no transpose for bassline sequencer
1 tk 1317
	movwf	IRQ_TMP1
1318
	rgoto	SIDSE_Pitch_Transp_Bassline_Seq
368 tk 1319
 
1 tk 1320
SIDSE_Pitch_Transp_NoBassline
368 tk 1321
	xorlw	0x01				; (reverse engine setting)
1322
	bnz	SIDSE_Pitch_Transp_NoLead	; (if engine != 0)
1 tk 1323
SIDSE_Pitch_Transp_Lead
1324
	lfsr	FSR2, SID_MV1_BASE
368 tk 1325
SIDSE_Pitch_Transp_NoBasslineSeq
1 tk 1326
SIDSE_Pitch_Transp_NoLead
1327
	movlw	SID_MVx_TRANSPOSE
1328
	movff	PLUSW2, IRQ_TMP1
1329
SIDSE_Pitch_Transp_Bassline_Seq
362 tk 1330
	movf	IRQ_TMP2, W	; SID_Ix_Vx_TRANSPOSE
1 tk 1331
	addwf	IRQ_TMP1, W
1332
	sublw	0x80
1333
	xorlw	0xff
1334
	movwf	IRQ_TMP1
1335
 
1336
	;; transpose note
1337
	addwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1338
	addlw	1
1339
	BRA_IFCLR WREG, 7, ACCESS, SIDSE_Pitch_Transp_NoOverflow
368 tk 1340
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_N
1341
SIDSE_Pitch_Transp_Overflow_P
1342
	addlw	-12		; octavewise saturation
1343
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_P
1344
	rgoto	SIDSE_Pitch_Transp_Overflow_Cont
1345
 
1346
SIDSE_Pitch_Transp_Overflow_N
1347
	addlw	12		; octavewise saturation
1348
	BRA_IFSET WREG, 7, ACCESS, SIDSE_Pitch_Transp_Overflow_N
1349
	;; 	rgoto	SIDSE_Pitch_Transp_Overflow_Cont
1350
 
1351
SIDSE_Pitch_Transp_Overflow_Cont
1 tk 1352
SIDSE_Pitch_Transp_NoOverflow
1353
	movwf	SID_SE_TRANSPOSED_NOTE, BANKED
1354
 
1355
 
1356
	;; ------------------------------------------------------------------
1357
	;; Glissando Handling
1358
	;; ------------------------------------------------------------------
1359
	movlw	SID_Vx_OLD_TRANSP_NOTE		; store new transposed note?
1360
	movf	PLUSW1, W
1361
	cpfseq	SID_SE_TRANSPOSED_NOTE, BANKED
1362
	rgoto SIDSE_Pitch_GlissNewNote
1363
	rgoto	SIDSE_Pitch_GlissNoNewNote
1364
SIDSE_Pitch_GlissNewNote
1365
	movlw	SID_Vx_OLD_TRANSP_NOTE		; store new transposed note!
1366
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1367
 
1368
	;; init portamento/glissando counter if glissando active
1369
	movlw	SID_Ix_Vx_FLAGS1
1370
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_GlissNoNewNote
1371
	movlw	SID_Vx_PORTA_CTR_L
1372
	setf	PLUSW1		; force overrun
1373
	movlw	SID_Vx_PORTA_CTR_H
1374
	setf	PLUSW1
1375
SIDSE_Pitch_GlissNoNewNote
1376
 
1377
	;; portamento active?
1378
	movlw	SID_Vx_STATE
1379
	BRA_IFCLR PLUSW1, SID_V_STATE_PORTA_ACTIVE, ACCESS, SIDSE_Pitch_Gliss_Final
1380
 
1381
	;; glissando active?
1382
	movlw	SID_Ix_Vx_FLAGS1
1383
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Gliss_Final
1384
 
1385
	;; get portamento multiplier from envelope table -> MUL_A
1386
	;; this one is used for "constant time glide" and "normal portamento"
1387
	movlw	SID_Ix_Vx_PORTAMENTO
1388
	movf	PLUSW0, W
1389
	skpnz
1390
	rgoto	SIDSE_Pitch_Gliss_Final	; if rate has been changed to zero, set target frequency and finish portamento
1391
	clrc
1392
	rrf	WREG, W		; make it faster
1393
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
1394
	tblrd*+				; transfer table entry to MUL_A_[LH]
1395
	movff	TABLAT, MUL_A_L
1396
	tblrd*+
1397
	movff	TABLAT, MUL_A_H
1398
 
1399
	;; increment portamento counter by MUL_A_[LH], result in MUL_A_[LH]
1400
	movlw	SID_Vx_PORTA_CTR_L
1401
	movf	PLUSW1, W
1402
	addwf	MUL_A_L, F, BANKED
1403
	movlw	SID_Vx_PORTA_CTR_H
1404
	movf	PLUSW1, W
1405
	addwfc	MUL_A_H, F, BANKED
1406
	bc	SIDSE_Pitch_Gliss_Ov
1407
SIDSE_Pitch_Gliss_NoOv
1408
	;; store new counter and continue with current note
1409
	movlw	SID_Vx_PORTA_CTR_L
1410
	movff	MUL_A_L, PLUSW1
1411
	movlw	SID_Vx_PORTA_CTR_H
1412
	movff	MUL_A_H, PLUSW1
1413
	movlw	SID_Vx_TRANSP_NOTE
1414
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1415
	rgoto	SIDSE_Pitch_Gliss_End
1416
 
1417
SIDSE_Pitch_Gliss_Ov
1418
	;; reset portamento/glissando counter
1419
	movlw	SID_Vx_PORTA_CTR_L
1420
	clrf	PLUSW1
1421
	movlw	SID_Vx_PORTA_CTR_H
1422
	clrf	PLUSW1
1423
 
1424
	;; increment/decrement note
1425
	movlw	SID_Vx_TRANSP_NOTE
1426
	movf	PLUSW1, W
1427
	movwf	IRQ_TMP1
1428
	cpfsgt	SID_SE_TRANSPOSED_NOTE, BANKED
1429
	rgoto SIDSE_Pitch_Gliss_Dec
1430
SIDSE_Pitch_Gliss_Inc
1431
	incf	IRQ_TMP1, F	; increment note and check if final value reached
1432
	rgoto	SIDSE_Pitch_Gliss_Inc_Cont
1433
SIDSE_Pitch_Gliss_Dec
1434
	decf	IRQ_TMP1, F	; decrement note and check if final value reached
1435
	;; 	rgoto	SIDSE_Pitch_Gliss_Inc_Cont
1436
 
1437
SIDSE_Pitch_Gliss_Inc_Cont
1438
	BRA_IFSET IRQ_TMP1, 7, ACCESS, SIDSE_Pitch_Gliss_Final
1439
	movf	IRQ_TMP1, W
1440
	cpfseq	SID_SE_TRANSPOSED_NOTE, BANKED
1441
	rgoto SIDSE_Pitch_Gliss_NewNote
1442
	rgoto	SIDSE_Pitch_Gliss_Final
1443
SIDSE_Pitch_Gliss_NewNote
1444
	movff	IRQ_TMP1, SID_SE_TRANSPOSED_NOTE
1445
	movlw	SID_Vx_TRANSP_NOTE
1446
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1447
	rgoto	SIDSE_Pitch_Gliss_End
1448
 
1449
SIDSE_Pitch_Gliss_Final
1450
	movlw	SID_Vx_OLD_TRANSP_NOTE	; target note reached
1451
	movff	PLUSW1, SID_SE_TRANSPOSED_NOTE
1452
	movlw	SID_Vx_TRANSP_NOTE
1453
	movff	SID_SE_TRANSPOSED_NOTE, PLUSW1
1454
 
1455
	;; deactivate porta active gate if glissando active
1456
	movlw	SID_Ix_Vx_FLAGS1
1457
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Gliss_End
1458
	movlw	SID_Vx_STATE
1459
	bcf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
1460
SIDSE_Pitch_Gliss_End
1461
 
1462
	;; ------------------------------------------------------------------
1463
	;; Determine Target frequency depending on transposed note
1464
	;; ------------------------------------------------------------------
1465
SIDSE_Pitch_InitTargetFrq
1466
	clrf	SID_SE_TARGET_FRQ_L, BANKED
1467
	clrc
1468
	rlf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1469
	movwf	SID_SE_TARGET_FRQ_H, BANKED
1470
 
1471
	;; ------------------------------------------------------------------
1472
	;; Increase/Decrease target frequency by pitchrange depending on
1473
	;; Pitchbender and Finetune value
1474
	;; ------------------------------------------------------------------
1475
 
1476
	;; skip Pitchbender+Finetune processing if PITCHRANGE == zero
1477
	movlw	SID_Ix_Vx_PITCHRANGE
1478
	movf	PLUSW0, W
1479
	skpnz
1480
	rgoto	SIDSE_Pitch_NoOffset
1481
SIDSE_Pitch_Offset
1482
	;; determine scale multipler (9 bit signed value) -> MUL_B_L
1483
	clrf	MUL_B_L, BANKED
1484
	clrf	MUL_B_H, BANKED
1485
 
1486
	;; multi/bassline/drum engine: take pitchbender value from MIDI voice (pointer still in FSR2)
1487
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
1488
	BRA_IFSET WREG, 1, ACCESS, SIDSE_Pitch_PB_DM
1489
SIDSE_Pitch_PB_LB
1490
	BRA_IFSET WREG, 0, ACCESS, SIDSE_Pitch_PB_B
1491
SIDSE_Pitch_PB_L
1492
	movlw	SID_Vx_PITCHBENDER
1493
	movf	PLUSW1, W
1494
	rgoto	SIDSE_Pitch_PB_Cont
1495
 
1496
SIDSE_Pitch_PB_B
1497
SIDSE_Pitch_PB_DM
1498
	movlw	SID_MVx_PITCHBENDER
1499
	movf	PLUSW2, W
1500
	;; 	rgoto	SIDSE_Pitch_PB_Cont
1501
 
1502
SIDSE_Pitch_PB_Cont
1503
	movwf	IRQ_TMP1
1504
	bz	SIDSE_Pitch_NoPitchBender
1505
SIDSE_Pitch_PitchBender
1506
	clrc
1507
	rlf	IRQ_TMP1, W
1508
	addwf	MUL_B_L, F, BANKED
1509
	movlw	0x00
1510
	btfsc	IRQ_TMP1, 7
1511
	movlw 0xff
1512
	addwfc	MUL_B_H, F, BANKED
1513
SIDSE_Pitch_NoPitchBender
1514
 
1515
	movlw	SID_Ix_Vx_FINETUNE
1516
	movf	PLUSW0, W
376 tk 1517
	movwf	IRQ_TMP1
1 tk 1518
	xorlw	0x80
1519
	bz	SIDSE_Pitch_NoFinetune
1520
SIDSE_Pitch_Finetune
1521
	clrc
1522
	rlf	IRQ_TMP1, W
1523
	addwf	MUL_B_L, F, BANKED
1524
	movlw	0x00
1525
	btfss	IRQ_TMP1, 7
1526
	movlw 0xff
1527
	addwfc	MUL_B_H, F, BANKED
1528
SIDSE_Pitch_NoFinetune
1529
 
1530
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
362 tk 1531
	andlw	0x02	; mask is valid for lead and bassline engine
1 tk 1532
	bnz	SIDSE_Pitch_NoDetune
1533
	SET_BSR	SID_PATCH_BUFFER_SHADOW
1534
	movf	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_OSC_DETUNE, W, BANKED
1535
	SET_BSR	SID_BASE
1536
	bz	SIDSE_Pitch_NoDetune
1537
SIDSE_Pitch_Detune
1538
	movwf	IRQ_TMP1
1539
	;; additional detuning depending on SID channel and oscillator
362 tk 1540
	;; Left OSC1: +detune/4   (lead only, 0 in bassline mode)
1541
	;; Right OSC1: -detune/4  (lead only, 0 in bassline mode)
1 tk 1542
	;; Left OSC2: +detune
1543
	;; Right OSC2: -detune
1544
	;; Left OSC3: -detune
1545
	;; Right OSC3: +detune
1546
 
1547
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Pitch_Detune_45
1548
SIDSE_Pitch_Detune_0123
1549
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Pitch_Detune_23
1550
SIDSE_Pitch_Detune_01
1551
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_1
1552
SIDSE_Pitch_Detune_0	; SIDL, OSC1
362 tk 1553
	;; in mono or bassline mode: don't detune OSC1, so that at least one oscillator runs at the target frequency!
1554
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG				; check for mono
1 tk 1555
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_Pitch_NoDetune
362 tk 1556
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG			; check for bassline
1557
	andlw	0x03
1558
	xorlw	0x01
1559
	bz	SIDSE_Pitch_NoDetune
1560
 
1 tk 1561
	clrc
1562
	rrf	IRQ_TMP1, F
1563
	clrc
1564
	rrf	IRQ_TMP1, F
1565
	rgoto	SIDSE_Pitch_Detune_Add
1566
SIDSE_Pitch_Detune_1	; SIDL, OSC2
1567
	rgoto	SIDSE_Pitch_Detune_Add
1568
 
1569
SIDSE_Pitch_Detune_23
1570
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_3
1571
SIDSE_Pitch_Detune_2	; SIDL, OSC3
1572
	rgoto	SIDSE_Pitch_Detune_Sub
1573
SIDSE_Pitch_Detune_3	; SIDR, OSC1
362 tk 1574
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG			; check for bassline
1575
	andlw	0x03
1576
	xorlw	0x01
1577
	bz	SIDSE_Pitch_NoDetune
1578
 
1 tk 1579
	clrc
1580
	rrf	IRQ_TMP1, F
1581
	clrc
1582
	rrf	IRQ_TMP1, F
1583
	rgoto	SIDSE_Pitch_Detune_Sub
1584
 
1585
SIDSE_Pitch_Detune_45
1586
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Pitch_Detune_5
1587
SIDSE_Pitch_Detune_4	; SIDR, OSC2
1588
	rgoto	SIDSE_Pitch_Detune_Sub
1589
SIDSE_Pitch_Detune_5	; SIDR, OSC3
1590
	rgoto	SIDSE_Pitch_Detune_Add
1591
 
1592
SIDSE_Pitch_Detune_Sub
1593
	comf	IRQ_TMP1, W
1594
	addlw	1
1595
	addwf	MUL_B_L, F, BANKED
1596
	movf	IRQ_TMP1, W
1597
	skpz
1598
	movlw	0xff
1599
	addwfc	MUL_B_H, F, BANKED
1600
	rgoto	SIDSE_Pitch_Detune_Cont
1601
 
1602
SIDSE_Pitch_Detune_Add
1603
	movf	IRQ_TMP1, W
1604
	addwf	MUL_B_L, F, BANKED
1605
	movlw	0x00
1606
	addwfc	MUL_B_H, F, BANKED
1607
	;; 	rgoto	SIDSE_Pitch_Detune_Cont
1608
SIDSE_Pitch_Detune_Cont
1609
SIDSE_Pitch_NoDetune
1610
 
1611
 
1612
	;; skip tuning if scale multiplier is zero
1613
	movf	MUL_B_L, W, BANKED
1614
	iorwf	MUL_B_H, W, BANKED
1615
	bz	SIDSE_Pitch_NoOffset
1616
 
1617
	;; get f_in[target], save it in MIOS_PARAMETER[12]
1618
	;; add pitchrange depending on direction with saturation
1619
	BRA_IFSET MUL_B_H, 7, BANKED, SIDSE_Pitch_Frq_Dec
1620
SIDSE_Pitch_Frq_Inc
1621
	movlw	SID_Ix_Vx_PITCHRANGE
1622
	movf	PLUSW0, W
1623
	addwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1624
	btfsc	WREG, 7
1625
	movlw 0x7f
1626
	rgoto	SIDSE_Pitch_Frq_Inc_Cont
1627
SIDSE_Pitch_Frq_Dec
1628
	movlw	SID_Ix_Vx_PITCHRANGE
1629
	movf	PLUSW0, W
1630
	subwf	SID_SE_TRANSPOSED_NOTE, W, BANKED
1631
	btfsc	WREG, 7
1632
	movlw 0x00
1633
SIDSE_Pitch_Frq_Inc_Cont
1634
 
398 tk 1635
SIDSE_Pitch_Frq_TuneFrq
1 tk 1636
	clrf	MIOS_PARAMETER1
1637
	clrc
1638
	rlf	WREG, W
1639
	movwf	MIOS_PARAMETER2
1640
 
1641
	;; add and multiply to target frequency
1642
SIDSE_Pitch_Frq_AddMul
1643
	BRA_IFSET MUL_B_H, 7, BANKED, SIDSE_Pitch_Frq_AddMul_Neg
1644
SIDSE_Pitch_Frq_AddMul_Pos
1645
	;; calc MUL_A_[LH] = MIOS_PARAMETER[12] - SID_Vx_FRQ_[LH]
1646
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
1647
	subwf	MIOS_PARAMETER1, W
1648
	movwf	MUL_A_L, BANKED
1649
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
1650
	subwfb	MIOS_PARAMETER2, W
1651
	movwf	MUL_A_H, BANKED
1652
 
1653
	;; ensure that bit #15 (sign) not set
1654
	BRA_IFCLR MUL_A_H, 7, BANKED, SIDSE_Pitch_Frq_AddMul_Cont
1655
	setf	MUL_A_L, BANKED
1656
	movlw	0x7f
1657
	movwf	MUL_A_H, BANKED
1658
	rgoto	SIDSE_Pitch_Frq_AddMul_Cont
1659
 
1660
SIDSE_Pitch_Frq_AddMul_Neg
1661
	;; calc MUL_A_[LH] = SID_Vx_FRQ_[LH] - MIOS_PARAMETER[12]
1662
	movf	MIOS_PARAMETER1, W
1663
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
1664
	movwf	MUL_A_L, BANKED
1665
	movf	MIOS_PARAMETER2, W
1666
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1667
	movwf	MUL_A_H, BANKED
1668
	;; 	rgoto	SIDSE_Pitch_Frq_AddMul_Cont
1669
 
1670
SIDSE_Pitch_Frq_AddMul_Cont
1671
	;; calc MUL_R_[12] = MUL_A_[LH] * MUL_B_[LH]
1672
	call	MATH_MUL16_16_SIGNED
1673
 
1674
	;; SID_Vx_FRQ += signed result[23:8]
1675
	movf	MUL_R_1, W, BANKED
1676
	addwf	SID_SE_TARGET_FRQ_L, F, BANKED
1677
	movf	MUL_R_2, W, BANKED
1678
	addwfc	SID_SE_TARGET_FRQ_H, F, BANKED
1679
 
1680
SIDSE_Pitch_NoOffset
1681
 
1682
	;; ------------------------------------------------------------------
1683
	;; pitch modulation
1684
	;; ------------------------------------------------------------------
1685
	rcall	SIDSE_Hlp_Pitch_Mod
1686
 
1687
	;; ------------------------------------------------------------------
1688
	;; Portamento Handling
1689
	;; ------------------------------------------------------------------
1690
 
398 tk 1691
	;; transfer current linear frequency (stored in voice array) to SID_SE_LINEAR_FRQ_[LH]
1692
	movlw	SID_Vx_LINEAR_FRQ_L
1693
	movff	PLUSW1, SID_SE_LINEAR_FRQ_L
1694
	movlw	SID_Vx_LINEAR_FRQ_H
1695
	movff	PLUSW1, SID_SE_LINEAR_FRQ_H
1 tk 1696
 
1697
SIDSE_Pitch_Porta
1698
	;; whenever target frequency has been changed, update portamento frequency
1699
	movlw	SID_Vx_OLD_TARGET_FRQ_L
1700
	movf	PLUSW1, W
1701
	cpfseq	SID_SE_TARGET_FRQ_L, BANKED
398 tk 1702
	rgoto	SIDSE_Pitch_Porta_Update
1 tk 1703
	movlw	SID_Vx_OLD_TARGET_FRQ_H
1704
	movf	PLUSW1, W
1705
	cpfseq	SID_SE_TARGET_FRQ_H, BANKED
398 tk 1706
	rgoto	SIDSE_Pitch_Porta_Update
1 tk 1707
	rgoto	SIDSE_Pitch_Porta_NoUpdate
1708
SIDSE_Pitch_Porta_Update
1709
	;; memorize new target frequency
1710
	movlw	SID_Vx_OLD_TARGET_FRQ_L
1711
	movff	SID_SE_TARGET_FRQ_L, PLUSW1
1712
	movlw	SID_Vx_OLD_TARGET_FRQ_H
1713
	movff	SID_SE_TARGET_FRQ_H, PLUSW1
1714
 
398 tk 1715
	;; store current linear frequency (SID_SE_LINEAR_FRQ_[LH]) into SID_Vx_PORTA_FRQ_[LH]
1 tk 1716
	movlw	SID_Vx_PORTA_FRQ_L
398 tk 1717
	movff	SID_SE_LINEAR_FRQ_L, PLUSW1
1 tk 1718
	movlw	SID_Vx_PORTA_FRQ_H
398 tk 1719
	movff	SID_SE_LINEAR_FRQ_H, PLUSW1
1 tk 1720
 
398 tk 1721
	;; reset portamento counter
1 tk 1722
	;; skip if glissando active
1723
	movlw	SID_Ix_Vx_FLAGS1
1724
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_NoUpdate
1725
	movlw	SID_Vx_PORTA_CTR_L
1726
	clrf	PLUSW1
1727
	movlw	SID_Vx_PORTA_CTR_H
1728
	clrf	PLUSW1
1729
SIDSE_Pitch_Porta_NoUpdate
1730
 
1731
	;; skip the rest if portamento not active
1732
	movlw	SID_Vx_STATE
1733
	BRA_IFCLR PLUSW1, SID_V_STATE_PORTA_ACTIVE, ACCESS, SIDSE_Pitch_Porta_Final
1734
 
1735
	;; skip if glissando active
1736
	movlw	SID_Ix_Vx_FLAGS1
1737
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_Final
1738
 
1739
	;; get portamento multiplier from envelope table -> MUL_A
1740
	;; this one is used for "constant time glide" and "normal portamento"
1741
	movlw	SID_Ix_Vx_PORTAMENTO
1742
	movf	PLUSW0, W
1743
	skpnz
1744
	rgoto	SIDSE_Pitch_Porta_Final	; if rate has been changed to zero, set target frequency and finish portamento
1745
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
1746
	tblrd*+				; transfer table entry to MUL_A_[LH]
1747
	movff	TABLAT, MUL_A_L
1748
	tblrd*+
1749
	movff	TABLAT, MUL_A_H
1750
 
1751
	;; branch depending on portamento mode
1752
	movlw	SID_Ix_Vx_FLAGS1
1753
	BRA_IFCLR PLUSW0, SID_I_V_FLAGS1_PORTA_CTG, ACCESS, SIDSE_Pitch_Porta_Norm
1754
 
1755
	;; ------------------------------------------------------------------
1756
	;; constant glide time
1757
SIDSE_Pitch_Porta_Const
1758
 
1759
	;; increment portamento counter by MUL_A_[LH], result in MUL_A_[LH]
1760
	movlw	SID_Vx_PORTA_CTR_L
1761
	movf	PLUSW1, W
1762
	addwf	MUL_A_L, F, BANKED
1763
	movlw	SID_Vx_PORTA_CTR_H
1764
	movf	PLUSW1, W
1765
	addwfc	MUL_A_H, F, BANKED
1766
	bnc	SIDSE_Pitch_Porta_Const_NoOv
1767
SIDSE_Pitch_Porta_Const_Ov
1768
	;; if value >= 0xffff target reached, saturate
1769
	setf	MUL_A_L, BANKED
1770
	setf	MUL_A_H, BANKED
1771
SIDSE_Pitch_Porta_Const_NoOv
1772
 
1773
	;; transfer back new counter value to original registers
1774
	;; portamento counter value -> MUL_A_[LH]
1775
	movlw	SID_Vx_PORTA_CTR_L
1776
	movff	MUL_A_L, PLUSW1
1777
	movlw	SID_Vx_PORTA_CTR_H
1778
	movff	MUL_A_H, PLUSW1
1779
 
1780
	;; get difference between target and previous frequency -> IRQ_TMP[12]
1781
	movlw	SID_Vx_PORTA_FRQ_L
1782
	movf	PLUSW1, W
1783
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
1784
	movwf	IRQ_TMP1
1785
	movlw	SID_Vx_PORTA_FRQ_H
1786
	movf	PLUSW1, W
1787
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1788
	movwf	IRQ_TMP2
1789
 
1790
	;; convert IRQ_TMP[12] to absolute value
1791
	call	SIDSE_Hlp_GetAbs16
1792
	;; result in IRQ_TMP[12], sign in IRQ_TMP3[0]
1793
	;; increment four to ensure that target will be reached
1794
	movlw	4
1795
	addwf	IRQ_TMP1, F
1796
	movlw	0
1797
	addwfc	IRQ_TMP2, F
1798
	movff	IRQ_TMP1, MUL_B_L
1799
	movff	IRQ_TMP2, MUL_B_H
1800
 
1801
	;; calc MUL_A_[LH] * MUL_B_[LH]
1802
	call	MATH_MUL16_16
1803
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
1804
 
1805
	;; branch depending on direction
1806
	BRA_IFSET IRQ_TMP3, 0, ACCESS, SIDSE_Pitch_Porta_Const_Down
1807
SIDSE_Pitch_Porta_Const_Up
1808
	;; add scaled value to starting frequency
1809
	movlw	SID_Vx_PORTA_FRQ_L
1810
	movf	PLUSW1, W
1811
	addwf	MUL_R_2, W, BANKED
398 tk 1812
	movwf	SID_SE_LINEAR_FRQ_L, BANKED
1 tk 1813
	movlw	SID_Vx_PORTA_FRQ_H
1814
	movf	PLUSW1, W
1815
	addwfc	MUL_R_3, W, BANKED
398 tk 1816
	movwf	SID_SE_LINEAR_FRQ_H, BANKED
1 tk 1817
 
1818
	;; continue at normal portamento routine
1819
	rgoto	SIDSE_Pitch_Porta_Const_Up_Cont
1820
 
1821
SIDSE_Pitch_Porta_Const_Down
1822
	;; subtract scaled value from starting frequency
1823
	movlw	SID_Vx_PORTA_FRQ_L
398 tk 1824
	movff	PLUSW1, PRODL
1 tk 1825
	movlw	SID_Vx_PORTA_FRQ_H
398 tk 1826
	movff	PLUSW1, PRODH
1 tk 1827
 
1828
	movf	MUL_R_2, W, BANKED
398 tk 1829
	subwf	PRODL, W
1830
	movwf	SID_SE_LINEAR_FRQ_L, BANKED
1 tk 1831
	movf	MUL_R_3, W, BANKED
398 tk 1832
	subwfb	PRODH, W
1833
	movwf	SID_SE_LINEAR_FRQ_H, BANKED
1 tk 1834
 
1835
	;; continue at normal portamento routine
1836
	rgoto	SIDSE_Pitch_Porta_Const_Down_C
1837
 
1838
 
1839
	;; ------------------------------------------------------------------
1840
	;; "normal" portamento mode (non-constant glide time)
1841
SIDSE_Pitch_Porta_Norm
1842
	;; get current frequency -> MUL_B
398 tk 1843
	movff	SID_SE_LINEAR_FRQ_L, MUL_B_L
1844
	movff	SID_SE_LINEAR_FRQ_H, MUL_B_H
1 tk 1845
 
1846
	;; multiply MUL_A * MUL_B
1847
	call	MATH_MUL16_16
1848
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
1849
	;; ensure that result is != 0
1850
	movf	MUL_R_2, W, BANKED
1851
	iorwf	MUL_R_3, W, BANKED
1852
	skpnz
1853
	incf	MUL_R_2, F, BANKED
1854
 
398 tk 1855
	;; SID_Vx_LINEAR_FRQ += result (depending on Portamento Direction)
1 tk 1856
 
1857
	;; branch depending on portamento direction
1858
	;; check if value > current value
1859
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1860
	subwf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1861
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
398 tk 1862
	subwfb	SID_SE_LINEAR_FRQ_H, W, BANKED
1 tk 1863
	bc	SIDSE_Pitch_Porta_Norm_Down
1864
 
1865
SIDSE_Pitch_Porta_Norm_Up
398 tk 1866
	movf	MUL_R_2, W, BANKED
1867
	addwf	SID_SE_LINEAR_FRQ_L, F, BANKED
1 tk 1868
	movf	MUL_R_3, W, BANKED
398 tk 1869
	addwfc	SID_SE_LINEAR_FRQ_H, F, BANKED
1 tk 1870
 
1871
SIDSE_Pitch_Porta_Const_Up_Cont		; re-used by "constant glide" option
1872
	;; check if value > MAX_VALUE
398 tk 1873
	movf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1874
	subwf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1875
	movf	SID_SE_LINEAR_FRQ_H, W, BANKED
1 tk 1876
	subwfb	SID_SE_TARGET_FRQ_H, W, BANKED
1877
	bc	SIDSE_Pitch_Porta_End	; branch to end if MAX_VALUE not reached
1878
	rgoto	SIDSE_Pitch_Porta_Final	; final value reached
1879
 
1880
SIDSE_Pitch_Porta_Norm_Down
1881
	movf	MUL_R_2, W
398 tk 1882
	subwf	SID_SE_LINEAR_FRQ_L, F, BANKED
1 tk 1883
	movf	MUL_R_3, W, BANKED
398 tk 1884
	subwfb	SID_SE_LINEAR_FRQ_H, F, BANKED
1 tk 1885
 
1886
SIDSE_Pitch_Porta_Const_Down_C	; re-used by "constant glide" option
1887
	;; check if value < MIN_VALUE
1888
	movf	SID_SE_TARGET_FRQ_L, W, BANKED
398 tk 1889
	subwf	SID_SE_LINEAR_FRQ_L, W, BANKED
1 tk 1890
	movf	SID_SE_TARGET_FRQ_H, W, BANKED
398 tk 1891
	subwfb	SID_SE_LINEAR_FRQ_H, W, BANKED
1892
	bc	SIDSE_Pitch_Porta_End	; branch if MIN_VALUE not reached
1 tk 1893
	;; final value reached
1894
 
1895
SIDSE_Pitch_Porta_Final
398 tk 1896
	;; copy target frequency to SID_SE_LINEAR_FRQ_[LH] and finish portamento
1897
	movff	SID_SE_TARGET_FRQ_L, SID_SE_LINEAR_FRQ_L
1898
	movff	SID_SE_TARGET_FRQ_H, SID_SE_LINEAR_FRQ_H
1899
 
1900
	;; deactivate porta active gate if glissando not active
1901
	movlw	SID_Ix_Vx_FLAGS1
1902
	BRA_IFSET PLUSW0, SID_I_V_FLAGS1_PORTA_GLISSANDO, ACCESS, SIDSE_Pitch_Porta_End
1903
	movlw	SID_Vx_STATE
1904
 	bcf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
1905
SIDSE_Pitch_Porta_End
1906
 
1907
 
1908
	;; ------------------------------------------------------------------
1909
	;; Linear Frequency -> SID Frequency conversion
1910
	;; ------------------------------------------------------------------
1911
SIDSE_Pitch_FrqConvert
399 tk 1912
	movlw	SID_Vx_STATE2	; (for multi-engine to takeover portamento)
1913
	BRA_IFSET PLUSW1, SID_V_STATE2_FORCE_FRQ_RECALC, ACCESS, SIDSE_Pitch_FrqConvert_Changed
1914
 
398 tk 1915
	;; check if linear frequency has been changed
1916
	movlw	SID_Vx_LINEAR_FRQ_L
1917
	movf	PLUSW1, W
1918
	xorwf	SID_SE_LINEAR_FRQ_L, W, BANKED
1919
	bnz	SIDSE_Pitch_FrqConvert_Changed
1920
	movlw	SID_Vx_LINEAR_FRQ_H
1921
	movf	PLUSW1, W
1922
	xorwf	SID_SE_LINEAR_FRQ_H, W, BANKED
1923
	bz	SIDSE_Pitch_FrqConvert_End
1924
SIDSE_Pitch_FrqConvert_Changed
399 tk 1925
	movlw	SID_Vx_STATE2
1926
	bcf	PLUSW1, SID_V_STATE2_FORCE_FRQ_RECALC
398 tk 1927
 
1928
	;; store new linear frequency value into SID_Vx_LINEAR_FRQ_[LH]
1929
	movlw	SID_Vx_LINEAR_FRQ_L
1930
	movff	SID_SE_LINEAR_FRQ_L, PLUSW1
1931
	movlw	SID_Vx_LINEAR_FRQ_H
1932
	movff	SID_SE_LINEAR_FRQ_H, PLUSW1
1933
 
1934
	;; transfer pointer to SIDx_Vx_FRQ_L register -> FSR2
1935
	call	SIDSE_Hlp_GetSIDFrqPtr
1936
 
391 tk 1937
	;; convert upper 7 bit of 16bit linear frequency to SID frequency value
398 tk 1938
	rrf	SID_SE_LINEAR_FRQ_H, W, BANKED
391 tk 1939
	andlw	0x7f
1940
	addlw	21
1941
	btfsc	WREG, 7; the note value
398 tk 1942
	movlw	0x7f
391 tk 1943
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; determine table address
1944
	tblrd*+				; transfer table entry to SID_FRQ_[LH]
1945
	movff	TABLAT, POSTINC2
1946
	movff	TABLAT, MUL_A_L
1947
	tblrd*+
1948
	movff	TABLAT, POSTDEC2
1949
	movff	TABLAT, MUL_A_H
1950
 
1951
	tblrd*+				; for interpolation: transfer next table entry to MUL_B_[LH]
1952
	movff	TABLAT, MUL_B_L
1953
	tblrd*+
1954
	movff	TABLAT, MUL_B_H
1955
 
1956
	;; calculate difference: MUL_A_[LH] = MUL_B_[LH] - MUL_A_[LH]
1957
	movf	MUL_A_L, W, BANKED
1958
	subwf	MUL_B_L, W, BANKED
1959
	movwf	MUL_A_L, BANKED
1960
	movf	MUL_A_H, W, BANKED
1961
	subwfb	MUL_B_H, W, BANKED
1962
	movwf	MUL_A_H, BANKED
1963
 
398 tk 1964
	;; use bit 8:1 of 16bit linear frequency for linear scaling between two semitones
1965
	rrf	SID_SE_LINEAR_FRQ_H, W, BANKED
1966
	rrf	SID_SE_LINEAR_FRQ_L, W, BANKED
391 tk 1967
	movwf	MUL_B_L, BANKED
1968
 
398 tk 1969
	;; 16*8 multiplication
1970
	call	MATH_MUL16_8
391 tk 1971
 
1972
	;; add result to SID frequency registers
398 tk 1973
	movf	MUL_R_1, W, BANKED
1974
	addwf	POSTINC2, F
391 tk 1975
	movf	MUL_R_2, W, BANKED
1976
	addwfc	POSTDEC2, F
398 tk 1977
SIDSE_Pitch_FrqConvert_End
1 tk 1978
 
1979
 
1980
	;; ------------------------------------------------------------------
1981
	;; K2A Function
1982
	;; ------------------------------------------------------------------
1983
 
1984
	;; forward key value to AOUT if enabled
1985
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
1986
	BRA_IFCLR WREG, SID_ENS_CTRL2_K2A, ACCESS, SIDSE_Pitch_Key_NoAOUT
1987
SIDSE_Pitch_Key_AOUT
1988
	;; get channel assignment (0: channel disabled)
1989
	movlw	LOW(SIDSE_KEY_EXT_ASSG_TABLE)
1990
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
1991
	movwf	TBLPTRL
1992
	clrf	TBLPTRH
1993
	movlw	HIGH(SIDSE_KEY_EXT_ASSG_TABLE)
1994
	addwfc	TBLPTRH, F
1995
	clrf    TBLPTRU
1996
        movlw   UPPER(SIDSE_KEY_EXT_ASSG_TABLE)
1997
	addwfc	TBLPTRU, F
1998
	tblrd*+
1999
	movf	TABLAT, W
2000
	bz	SIDSE_Pitch_Key_NoAOUT	; channel assignment disabled
2001
 
136 tk 2002
	;; copy key value to MIOS_PARAMETER[12]
2003
	clrf	MIOS_PARAMETER1
1 tk 2004
	clrc
2005
	rlf	SID_SE_TRANSPOSED_NOTE, W, BANKED
136 tk 2006
	movwf	MIOS_PARAMETER2
1 tk 2007
 
136 tk 2008
	;; forward MIOS_PARAMETER[12] to channel #TABLAT-1
1 tk 2009
	decf	TABLAT, W
136 tk 2010
	call	AOUT_Pin16bitSet
2011
	SET_BSR	SID_BASE
1 tk 2012
 
2013
	;; notify that channel has already been updated by K2A function
2014
	decf	TABLAT, W
2015
	call	MIOS_HLP_GetBitORMask
2016
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2017
SIDSE_Pitch_Key_NoAOUT
2018
 
2019
	;; ------------------------------------------------------------------
2020
	;; O2A Function
2021
	;; ------------------------------------------------------------------
2022
 
398 tk 2023
	;; forward linear frequency value to AOUT if enabled
1 tk 2024
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2025
	BRA_IFCLR WREG, SID_ENS_CTRL2_O2A, ACCESS, SIDSE_Pitch_Osc_NoAOUT
2026
SIDSE_Pitch_Osc_AOUT
2027
	;; get channel assignment (0: channel disabled)
2028
	movlw	LOW(SIDSE_OSC_EXT_ASSG_TABLE)
2029
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
2030
	movwf	TBLPTRL
2031
	clrf	TBLPTRH
2032
	movlw	HIGH(SIDSE_OSC_EXT_ASSG_TABLE)
2033
	addwfc	TBLPTRH, F
2034
	clrf    TBLPTRU
2035
        movlw   UPPER(SIDSE_OSC_EXT_ASSG_TABLE)
2036
	addwfc	TBLPTRU, F
2037
	tblrd*+
2038
	movf	TABLAT, W
2039
	bz	SIDSE_Pitch_Osc_NoAOUT	; channel assignment disabled
2040
 
136 tk 2041
	;; copy oscillator frequency to MIOS_PARAMETER[12]
398 tk 2042
	movff	SID_SE_LINEAR_FRQ_L, MIOS_PARAMETER1
2043
	movff	SID_SE_LINEAR_FRQ_H, MIOS_PARAMETER2
1 tk 2044
 
136 tk 2045
	;; forward MIOS_PARAMETER[12] to channel #TABLAT-1
1 tk 2046
	decf	TABLAT, W
136 tk 2047
	call	AOUT_Pin16bitSet
2048
	SET_BSR	SID_BASE
1 tk 2049
 
2050
	;; notify that channel has already been updated by O2A function
2051
	decf	TABLAT, W
2052
	call	MIOS_HLP_GetBitORMask
2053
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2054
SIDSE_Pitch_Osc_NoAOUT
2055
 
2056
	return
2057
 
2058
 
2059
	;; AOUT assignments for K2A
2060
SIDSE_KEY_EXT_ASSG_TABLE
2061
	db	DEFAULT_K2A_OSC1_L_AOUT, DEFAULT_K2A_OSC2_L_AOUT
2062
	db	DEFAULT_K2A_OSC3_L_AOUT, DEFAULT_K2A_OSC1_R_AOUT
2063
	db	DEFAULT_K2A_OSC2_L_AOUT, DEFAULT_K2A_OSC3_R_AOUT
2064
 
2065
	;; AOUT assignments for O2A
2066
SIDSE_OSC_EXT_ASSG_TABLE
2067
	db	DEFAULT_O2A_OSC1_L_AOUT, DEFAULT_O2A_OSC2_L_AOUT
2068
	db	DEFAULT_O2A_OSC3_L_AOUT, DEFAULT_O2A_OSC1_R_AOUT
2069
	db	DEFAULT_O2A_OSC2_L_AOUT, DEFAULT_O2A_OSC3_R_AOUT
2070
 
2071
 
2072
;; --------------------------------------------------------------------------
2073
;; This function handles the Pulsewidth of a voice
2074
;; IN: pointer to SID_Ix_L_SxVy_BASE in FSR0 (patch record)
2075
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
2076
;;     Voice number in SID_SE_ELEMENT_NUM
2077
;;     If SIDSE_PW_Drums is called: 16bit pulsewidth in IRQ_TMP[12]
2078
;; --------------------------------------------------------------------------
2079
SIDSE_PW
2080
	;; small variation between Lead/Bassline/Multi Engine, and Drum Engine:
2081
	;; for Drum Engine the pulsewidth is predefined in model table, and not
2082
	;; part of the patch (drum engine has to call SIDSE_PW_Drums with
2083
	;; 16bit pulsewidth in IRQ_TMP[12]
2084
 
362 tk 2085
	;; bassline engine: select OSC2/3 pulsewidth depending on voice
2086
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
2087
	andlw	0x03
2088
	xorlw	0x01
2089
	bnz	SIDSE_PW_NoBassline
2090
SIDSE_PW_Bassline
2091
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2092
	bz	SIDSE_PW_Bassline_V1L
2093
	addlw	-1
2094
	bz	SIDSE_PW_Bassline_V2L
2095
	addlw	-1
2096
	bz	SIDSE_PW_Bassline_V3L
2097
	addlw	-1
2098
	bz	SIDSE_PW_Bassline_V1R
2099
	addlw	-1
2100
	bz	SIDSE_PW_Bassline_V2R
2101
	;; 	rgoto	SIDSE_PW_Bassline_V3R
2102
 
2103
SIDSE_PW_Bassline_V3L	; store SID_Ix_V_V3_PULSEWIDTH_[LH] in IRQ_TMP[12]
2104
SIDSE_PW_Bassline_V3R
2105
	movlw	SID_Ix_B_V3_PULSEWIDTH_L
2106
	movff	PLUSW0, IRQ_TMP1
2107
	movlw	SID_Ix_B_V3_PULSEWIDTH_H
2108
	rgoto	SIDSE_PW_Bassline_Cont
2109
 
2110
SIDSE_PW_Bassline_V2L	; store SID_Ix_V_V2_PULSEWIDTH_[LH] in IRQ_TMP[12]
2111
SIDSE_PW_Bassline_V2R
1 tk 2112
	;; store 12bit pulsewidth in IRQ_TMP[12]
362 tk 2113
	movlw	SID_Ix_B_V2_PULSEWIDTH_L
2114
	movff	PLUSW0, IRQ_TMP1
2115
	movlw	SID_Ix_B_V2_PULSEWIDTH_H
2116
	rgoto	SIDSE_PW_Bassline_Cont
2117
 
2118
SIDSE_PW_Bassline_V1L	; store SID_Ix_Vx_PULSEWIDTH_[LH] in IRQ_TMP[12]
2119
SIDSE_PW_Bassline_V1R
2120
SIDSE_PW_NoBassline
1 tk 2121
	movlw	SID_Ix_Vx_PULSEWIDTH_L
2122
	movff	PLUSW0, IRQ_TMP1
2123
	movlw	SID_Ix_Vx_PULSEWIDTH_H
362 tk 2124
SIDSE_PW_Bassline_Cont
1 tk 2125
	movf	PLUSW0, W
2126
	andlw	0x0f
2127
	movwf	IRQ_TMP2
2128
 
2129
	;; extend to 16bit
2130
	swapf	IRQ_TMP2, F
2131
	swapf	IRQ_TMP1, W
2132
	andlw	0x0f
2133
	iorwf	IRQ_TMP2, F
2134
	swapf	IRQ_TMP1, W
2135
	andlw	0xf0
2136
	movwf	IRQ_TMP1
2137
 
2138
SIDSE_PW_Drums
2139
	;; transfer pointer to SIDx_Vx_PW_L register -> FSR2
2140
	call	SIDSE_Hlp_GetSIDPWPtr
2141
 
2142
	;; calculate pointer to MOD target array -> FSR2
2143
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2144
	addlw	(SID_MOD_TARG_PW1_L-SID_MOD_TARG_BASE)/3
2145
	mullw	3
2146
	lfsr	FSR1, SID_MOD_TARG_BASE
2147
	movf	PRODL, W
2148
	addwf	FSR1L, F
2149
 
2150
	;; add modulation value to pulsewidth
2151
	movf	POSTINC1, W
2152
	addwf	IRQ_TMP1, F
2153
	movf	POSTINC1, W
2154
	addwfc	IRQ_TMP2, F
2155
 
2156
	;; saturate
2157
	BRA_IFSET INDF1, 7, ACCESS, SIDSE_PW_Mod_SatNeg
2158
SIDSE_PW_Mod_SatPos
2159
	movf	INDF1, W
2160
	bnz	SIDSE_PW_Mod_SatPos_Sat
2161
	bnc	SIDSE_PW_Mod_Sat_NoSat
2162
SIDSE_PW_Mod_SatPos_Sat
2163
	setf	IRQ_TMP1
2164
	setf	IRQ_TMP2
2165
	rgoto	SIDSE_PW_Mod_Sat_Cont
2166
SIDSE_PW_Mod_SatNeg
2167
	comf	INDF1, W
2168
	bnz	SIDSE_PW_Mod_SatNeg_Sat
2169
	bc	SIDSE_PW_Mod_Sat_NoSat
2170
SIDSE_PW_Mod_SatNeg_Sat
2171
	clrf	IRQ_TMP1
2172
	clrf	IRQ_TMP2
2173
	;; 	rgoto	SIDSE_PW_Mod_Sat_Cont
2174
SIDSE_PW_Mod_Sat_Cont
2175
SIDSE_PW_Mod_Sat_NoSat
2176
 
2177
	;; convert back to 12bit value -> IRQ_TMP[34]
2178
	swapf	IRQ_TMP1, W
2179
	andlw	0x0f
2180
	movwf	IRQ_TMP3
2181
	swapf	IRQ_TMP2, W
2182
	andlw	0xf0
2183
	iorwf	IRQ_TMP3, F
2184
	swapf	IRQ_TMP2, W
2185
	andlw	0x0f
2186
	movwf	IRQ_TMP4
2187
 
2188
	;; transfer to SID registers
2189
	movff	IRQ_TMP3, POSTINC2
2190
	movff	IRQ_TMP4, POSTDEC2
2191
 
2192
	;; forward pulsewidth to AOUT if enabled
2193
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2194
	BRA_IFCLR WREG, SID_ENS_CTRL2_P2A, ACCESS, SIDSE_PW_NoAOUT
2195
SIDSE_PW_AOUT
2196
	;; get channel assignment (0: channel disabled)
2197
	movlw	LOW(SIDSE_PW_EXT_ASSG_TABLE)
2198
	addwf	SID_SE_ELEMENT_NUM, W, BANKED
2199
	movwf	TBLPTRL
2200
	clrf	TBLPTRH
2201
	movlw	HIGH(SIDSE_PW_EXT_ASSG_TABLE)
2202
	addwfc	TBLPTRH, F
2203
	clrf    TBLPTRU
2204
        movlw   UPPER(SIDSE_PW_EXT_ASSG_TABLE)
2205
	addwfc	TBLPTRU, F
2206
	tblrd*+
2207
	movf	TABLAT, W
2208
	bz	SIDSE_PW_NoAOUT		; channel assignment disabled
2209
 
136 tk 2210
	;; forward IRQ_TMP[12] to channel #TABLAT-1
2211
	movff	IRQ_TMP1, MIOS_PARAMETER1
2212
	movff	IRQ_TMP2, MIOS_PARAMETER2
1 tk 2213
	decf	TABLAT, W
136 tk 2214
	call	AOUT_Pin16bitSet
2215
	SET_BSR	SID_BASE
1 tk 2216
 
2217
	;; notify that channel has already been updated by P2A function
2218
	decf	TABLAT, W
2219
	call	MIOS_HLP_GetBitORMask
2220
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2221
SIDSE_PW_NoAOUT
2222
	return
2223
 
2224
 
2225
	;; AOUT assignments for P2A
2226
SIDSE_PW_EXT_ASSG_TABLE
2227
	db	DEFAULT_P2A_OSC1_L_AOUT, DEFAULT_P2A_OSC2_L_AOUT
2228
	db	DEFAULT_P2A_OSC3_L_AOUT, DEFAULT_P2A_OSC1_R_AOUT
2229
	db	DEFAULT_P2A_OSC2_L_AOUT, DEFAULT_P2A_OSC3_R_AOUT
2230
 
2231
;; --------------------------------------------------------------------------
2232
;; This function handles the Filter
2233
;; IN: pointer to SID_Ix_L_SxF_BASE in FSR0 (patch record)
2234
;;     pointer to SID_MOD_TARG_FILx_L in FSR1 (modulation target)
2235
;;     pointer to SIDx_BASE in FSR2 (SID registers)
2236
;;     Filter number in SID_SE_ELEMENT_NUM
2237
;; --------------------------------------------------------------------------
2238
SIDSE_Filter
2239
	;; store 12bit cutoff in IRQ_TMP[12]
2240
	movlw	SID_Ix_L_Fx_CUTOFF_L
2241
	movff	PLUSW0, IRQ_TMP1
2242
	movlw	SID_Ix_L_Fx_CUTOFF_H
2243
	movf	PLUSW0, W
2244
	andlw	0x0f
2245
	movwf	IRQ_TMP2
2246
 
2247
	;; extend to 16bit
2248
	swapf	IRQ_TMP2, F
2249
	swapf	IRQ_TMP1, W
2250
	andlw	0x0f
2251
	iorwf	IRQ_TMP2, F
2252
	swapf	IRQ_TMP1, W
2253
	andlw	0xf0
2254
	movwf	IRQ_TMP1
2255
 
2256
	;; pointer to SID_MOD_TARG_FILx_L already in FSR1
2257
	;; multiplty target value by 2 (for easy to realize extreme modulation results)
2258
	;; -> IRQ_TMP[345]
2259
	movf	INDF1, W
2260
	addwf	POSTINC1, W
2261
	movwf	IRQ_TMP3
2262
	movf	INDF1, W
2263
	addwfc	POSTINC1, W
2264
	movwf	IRQ_TMP4
2265
	movf	INDF1, W
2266
	addwfc	POSTINC1, W
2267
	movwf	IRQ_TMP5
2268
 
2269
	;; add modulation value to cutoff
2270
	movf	IRQ_TMP3, W
2271
	addwf	IRQ_TMP1, F
2272
	movf	IRQ_TMP4, W
2273
	addwfc	IRQ_TMP2, F
2274
 
2275
	;; saturate
2276
	BRA_IFSET IRQ_TMP5, 7, ACCESS, SIDSE_Filter_Mod_SatNeg
2277
SIDSE_Filter_Mod_SatPos
2278
	movf	IRQ_TMP5, W
2279
	bnz	SIDSE_Filter_Mod_SatPos_Sat
2280
	bnc	SIDSE_Filter_Mod_Sat_NoSat
2281
SIDSE_Filter_Mod_SatPos_Sat
2282
	setf	IRQ_TMP1
2283
	setf	IRQ_TMP2
2284
	rgoto	SIDSE_Filter_Mod_Sat_Cont
2285
SIDSE_Filter_Mod_SatNeg
2286
	comf	IRQ_TMP5, W
2287
	bnz	SIDSE_Filter_Mod_SatNeg_Sat
2288
	bc	SIDSE_Filter_Mod_Sat_NoSat
2289
SIDSE_Filter_Mod_SatNeg_Sat
2290
	clrf	IRQ_TMP1
2291
	clrf	IRQ_TMP2
2292
	;; 	rgoto	SIDSE_Filter_Mod_Sat_Cont
2293
SIDSE_Filter_Mod_Sat_Cont
2294
SIDSE_Filter_Mod_Sat_NoSat
2295
 
398 tk 2296
	;; bassline and lead engine: add keytracking * linear frequency value
1 tk 2297
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
2298
	andlw	0x03
340 tk 2299
	bz	SIDSE_Filter_KTr
1 tk 2300
	xorlw	0x01
2301
	bnz	SIDSE_Filter_KTr_Skip
2302
SIDSE_Filter_KTr
2303
	movlw	SID_Ix_L_Fx_KEYTRACK
2304
	movf	PLUSW0, W
2305
	bz	SIDSE_Filter_KTr_Skip
2306
	movwf	PRODL
2307
 
398 tk 2308
	;; linear frequency value -> PRODH
2309
	movff	SIDL_V1_BASE + SID_Vx_LINEAR_FRQ_H, PRODH
1 tk 2310
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
398 tk 2311
	movff	SIDR_V1_BASE + SID_Vx_LINEAR_FRQ_H, PRODH
340 tk 2312
 
2313
	;; if keytracking == 0xff: no multiplication required -> 100%
2314
	incf	PRODL, W
2315
	bnz	SIDSE_Filter_KTr_No100P
2316
SIDSE_Filter_KTr_100P
2317
	clrf	PRODL		; 100%, key value already in PRODH
2318
	rgoto	SIDSE_Filter_KTr_100P_Cont
2319
 
2320
SIDSE_Filter_KTr_No100P
2321
	incf	PRODL, F	; <100%
2322
	incf	PRODH, W
1 tk 2323
	mulwf	PRODL, ACCESS
2324
 
340 tk 2325
SIDSE_Filter_KTr_100P_Cont
2326
 
2327
	;; bias at C-3 (0x3c)
2328
	movlw	-(0x3c << 1)
2329
	addwf	PRODH, F
2330
 
2331
	;; add to filter and saturate if required
1 tk 2332
	movf	PRODL, W
2333
	addwf	IRQ_TMP1, F
2334
	movf	PRODH, W
2335
	addwfc	IRQ_TMP2, F
340 tk 2336
	BRA_IFSET PRODH, 7, ACCESS, SIDSE_Filter_KTr_SatNeg
2337
SIDSE_Filter_KTr_SatPos
2338
	bnc	SIDSE_Filter_KTr_Sat_End
1 tk 2339
	setf	IRQ_TMP1
2340
	setf	IRQ_TMP2
340 tk 2341
	rgoto	SIDSE_Filter_KTr_Sat_End
2342
 
2343
SIDSE_Filter_KTr_SatNeg
2344
	bc	SIDSE_Filter_KTr_Sat_End
2345
	clrf	IRQ_TMP1
2346
	clrf	IRQ_TMP2
2347
	;; 	rgoto	SIDSE_Filter_KTr_Sat_End
2348
SIDSE_Filter_KTr_Sat_End
1 tk 2349
SIDSE_Filter_KTr_Skip
2350
 
2351
 
340 tk 2352
	;; transform to log scale if enabled
2353
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
2354
	BRA_IFCLR WREG, SID_ENS_CTRL1_FIL_LOG, ACCESS, SIDSE_Filter_NoLog
2355
SIDSE_Filter_Log
2356
	rrf	IRQ_TMP2, W			; take only upper 7bit
2357
	andlw	0x7f
2358
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; re-use frequency table
2359
	tblrd*+
2360
	movff	TABLAT, IRQ_TMP1
2361
	tblrd*+
2362
	movff	TABLAT, IRQ_TMP2
2363
SIDSE_Filter_NoLog
2364
 
1 tk 2365
	;; copy SID_Gx_CALI_FIL[12]_[MIN|MAX]_[LH] into IRQ_TMP[34]/PROD[LH] depending on selected filter
2366
	BRA_IFSET SID_SE_ELEMENT_NUM, 0, BANKED, SIDSE_Filter_MinMax2
2367
SIDSE_Filter_MinMax1
2368
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MIN_L, IRQ_TMP3
2369
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MIN_H, IRQ_TMP4
2370
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MAX_L, PRODL
2371
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL1_MAX_H, PRODH
2372
	rgoto	SIDSE_Filter_MinMax_Cont
2373
SIDSE_Filter_MinMax2
2374
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MIN_L, IRQ_TMP3
2375
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MIN_H, IRQ_TMP4
2376
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MAX_L, PRODL
2377
	movff	SID_LOCAL_ENS + SID_ENSx_CALI_FIL2_MAX_H, PRODH
2378
	;; 	rgoto	SIDSE_Filter_MinMax_Cont
2379
SIDSE_Filter_MinMax_Cont
2380
 
2381
	;; scale between min/max value
2382
	movf	IRQ_TMP3, W	; SID_Gx_CALI_FIL1_MIN_L
2383
	subwf	PRODL, W	; SID_Gx_CALI_FIL1_MAX_L
2384
	movff	WREG, MUL_A_L
2385
	movf	IRQ_TMP4, W	; SID_Gx_CALI_FIL1_MIN_H
2386
	subwfb	PRODH, W	; SID_Gx_CALI_FIL1_MAX_H
2387
	movff	WREG, MUL_A_H
2388
	movff	IRQ_TMP1, MUL_B_L
2389
	movff	IRQ_TMP2, MUL_B_H
2390
	;; calc MUL_A_[LH] * MUL_B_[LH]
2391
	call	MATH_MUL16_16
2392
	;; result in MUL_R_2 (low-byte) and MUL_R_3 (high-byte)
2393
	movf	IRQ_TMP3, W	; SID_Gx_CALI_FIL1_MIN_L
2394
	addwf	MUL_R_2, W, BANKED
2395
	movwf	IRQ_TMP1
2396
	movf	IRQ_TMP4, W	; SID_Gx_CALI_FIL1_MIN_H
2397
	addwfc	MUL_R_3, W, BANKED
2398
	movwf	IRQ_TMP2
2399
 
2400
	;; optional interpolation
2401
	movlw	SID_Ix_L_Fx_CUTOFF_H
2402
	BRA_IFCLR PLUSW0, SID_I_F_FIP_ON, ACCESS, SIDSE_Filter_NoIP
2403
SIDSE_Filter_IP
2404
	lfsr	FSR1, FIP1_BASE
2405
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2406
	skpz
2407
	lfsr	FSR1, FIP2_BASE
2408
	rcall	SIDSE_Hlp_IP
2409
SIDSE_Filter_NoIP
2410
 
2411
	;; convert to 11bit value (SID format: 3 lowes bits in bit [2:0] of low-register)
2412
	swapf	IRQ_TMP1, W
2413
	rrf	WREG, W
2414
	andlw	0x07
2415
	movwf	IRQ_TMP3
2416
 
2417
	;; transfer to SID registers
2418
	movlw	SIDx_FC_L
2419
	movff	IRQ_TMP3, PLUSW2
2420
	movlw	SIDx_FC_H
2421
	movff	IRQ_TMP2, PLUSW2
2422
 
2423
	;; Forward CutOff and Resonance to AOUT if enabled
2424
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, WREG
2425
	BRA_IFCLR WREG, SID_ENS_CTRL2_F2A, ACCESS, SIDSE_Filter_NoAOUT
2426
SIDSE_Filter_AOUT
2427
	;; expecting 16bit value in IRQ_TMP[12] and pointer to AOUT register in FSR1
2428
#if DEFAULT_F2A_CUTOFF_L_AOUT == 0 || DEFAULT_F2A_CUTOFF_L_AOUT > 8
2429
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2430
	bz	SIDSE_Filter_AOUT_NoCutOff
2431
#endif
2432
#if DEFAULT_F2A_CUTOFF_R_AOUT == 0 || DEFAULT_F2A_CUTOFF_R_AOUT > 8
2433
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2434
	bz	SIDSE_Filter_AOUT_NoCutOff
2435
#endif
2436
 
136 tk 2437
	;; forward IRQ_TMP[12] to channel predefined channel
2438
	movff	IRQ_TMP1, MIOS_PARAMETER1
2439
	movff	IRQ_TMP2, MIOS_PARAMETER2
2440
	movlw	DEFAULT_F2A_CUTOFF_L_AOUT-1
1 tk 2441
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2442
	movlw	DEFAULT_F2A_CUTOFF_R_AOUT-1
2443
	call	AOUT_Pin16bitSet
2444
	SET_BSR	SID_BASE
1 tk 2445
 
2446
	;; notify that channel has already been updated by F2A function
2447
	;; (for faster handling, do this for all enabled channels each time this function is called)
2448
	movlw	0x00
2449
#if DEFAULT_F2A_CUTOFF_L_AOUT
2450
	iorlw	(1 << (DEFAULT_F2A_CUTOFF_L_AOUT-1))
2451
#endif
2452
#if DEFAULT_F2A_CUTOFF_R_AOUT
2453
	iorlw	(1 << (DEFAULT_F2A_CUTOFF_R_AOUT-1))
2454
#endif
2455
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2456
SIDSE_Filter_AOUT_NoCutOff
2457
 
2458
#if DEFAULT_F2A_RESONANCE_L_AOUT == 0 || DEFAULT_F2A_RESONANCE_L_AOUT > 8
2459
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2460
	bz	SIDSE_Filter_AOUT_NoResonance
2461
#endif
2462
#if DEFAULT_F2A_RESONANCE_R_AOUT == 0 || DEFAULT_F2A_RESONANCE_R_AOUT > 8
2463
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2464
	bz	SIDSE_Filter_AOUT_NoResonance
2465
#endif
2466
 
2467
	;; resonance (8bit)
2468
	movlw	SID_Ix_L_Fx_RESONANCE
136 tk 2469
	movff	PLUSW0, MIOS_PARAMETER2
2470
	clrf	MIOS_PARAMETER1
2471
	movlw	DEFAULT_F2A_RESONANCE_L_AOUT-1
1 tk 2472
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2473
	movlw	DEFAULT_F2A_RESONANCE_R_AOUT-1
2474
	call	AOUT_Pin16bitSet
2475
	SET_BSR	SID_BASE
1 tk 2476
 
2477
	;; notify that channel has already been updated by F2A function
2478
	;; (for faster handling, do this for all enabled channels each time this function is called)
2479
	movlw	0x00
2480
#if DEFAULT_F2A_RESONANCE_L_AOUT
2481
	iorlw	(1 << (DEFAULT_F2A_RESONANCE_L_AOUT-1))
2482
#endif
2483
#if DEFAULT_F2A_RESONANCE_R_AOUT
2484
	iorlw	(1 << (DEFAULT_F2A_RESONANCE_R_AOUT-1))
2485
#endif
2486
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2487
SIDSE_Filter_AOUT_NoResonance
2488
SIDSE_Filter_NoAOUT
2489
 
2490
	;; Channels and Resonance
2491
	movlw	SID_Ix_L_Fx_CHN_MODE
2492
	movf	PLUSW0, W
2493
	andlw	0x0f
2494
	movwf	PRODL
2495
	movlw	SID_Ix_L_Fx_RESONANCE
2496
	movf	PLUSW0, W
2497
	andlw	0xf0
2498
	iorwf	PRODL, F
2499
	movlw	SIDx_RES_FCHN
2500
	movff	PRODL, PLUSW2
2501
 
2502
	;; volume and filter mode
2503
 
2504
	;; volume can be modulated (result in IRQ_TMP[12])
2505
	clrf	IRQ_TMP1
2506
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_VOLUME, IRQ_TMP2
2507
	clrc
2508
	rlf	IRQ_TMP2, F
2509
 
2510
	;; calculate pointer to MOD target array -> FSR2
2511
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2512
	addlw	(SID_MOD_TARG_VOL1_L-SID_MOD_TARG_BASE)/3
2513
	mullw	3
2514
	lfsr	FSR1, SID_MOD_TARG_BASE
2515
	movf	PRODL, W
2516
	addwf	FSR1L, F
2517
	movf	POSTINC1, W
2518
	addwf	IRQ_TMP1, F
2519
	movf	POSTINC1, W
2520
	addwfc	IRQ_TMP2, F
2521
 
2522
	;; saturate
2523
	BRA_IFSET INDF1, 7, ACCESS, SIDSE_Filter_Mod_Vol_SatNeg
2524
SIDSE_Filter_Mod_Vol_SatPos
2525
	movf	INDF1, W
2526
	bnz	SIDSE_Filter_Mod_Vol_SatPos_Sat
2527
	bnc	SIDSE_Filter_Mod_Vol_NoSat
2528
SIDSE_Filter_Mod_Vol_SatPos_Sat
2529
	setf	IRQ_TMP1
2530
	setf	IRQ_TMP2
2531
	rgoto	SIDSE_Filter_Mod_Vol_Sat_Cont
2532
SIDSE_Filter_Mod_Vol_SatNeg
2533
	comf	INDF1, W
2534
	bnz	SIDSE_Filter_Mod_Vol_SatNeg_Sat
2535
	bc	SIDSE_Filter_Mod_Vol_NoSat
2536
SIDSE_Filter_Mod_Vol_SatNeg_Sat
2537
	clrf	IRQ_TMP1
2538
	clrf	IRQ_TMP2
2539
	;; 	rgoto	SIDSE_Filter_Mod_Vol_Sat_Cont
2540
SIDSE_Filter_Mod_Vol_Sat_Cont
2541
SIDSE_Filter_Mod_Vol_NoSat
2542
 
2543
	;; copy SID_Gx_CTRL1 to IRQ_TMP3 - we need this to check if V2A is enabled
2544
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL2, IRQ_TMP3
2545
 
2546
	;; patch volume -> PRODL
2547
	;; volume always maximum when V2A enabled
2548
	swapf	IRQ_TMP2, W
2549
	andlw	0x0f
2550
	btfsc	IRQ_TMP3, SID_ENS_CTRL2_V2A
2551
	movlw 0x0f
2552
	movwf	PRODL
2553
 
2554
	movlw	SID_Ix_L_Fx_CHN_MODE
2555
	movf	PLUSW0, W
2556
	andlw	0xf0
2557
	iorwf	PRODL, F
2558
	movlw	SIDx_MODE_VOL
2559
	movff	PRODL, PLUSW2
2560
 
2561
	;; Forward Volume to AOUT if enabled
2562
	BRA_IFCLR IRQ_TMP3, SID_ENS_CTRL2_V2A, ACCESS, SIDSE_Filter_Vol_NoAOUT
2563
SIDSE_Filter_Vol_AOUT
2564
	;; expecting 16bit value in IRQ_TMP[12] and pointer to AOUT register in FSR1
2565
#if DEFAULT_V2A_VOLUME_L_AOUT == 0 || DEFAULT_V2A_VOLUME_L_AOUT > 8
2566
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2567
	bz	SIDSE_Filter_Vol_NoAOUT
2568
#endif
2569
#if DEFAULT_V2A_VOLUME_R_AOUT == 0 || DEFAULT_V2A_VOLUME_R_AOUT > 8
2570
	decf	SID_SE_ELEMENT_NUM, W, BANKED
2571
	bz	SIDSE_Filter_Vol_NoAOUT
2572
#endif
2573
 
136 tk 2574
	movff	IRQ_TMP1, MIOS_PARAMETER1
2575
	movff	IRQ_TMP2, MIOS_PARAMETER2
2576
	movlw	DEFAULT_V2A_VOLUME_L_AOUT-1
1 tk 2577
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
136 tk 2578
	movlw	DEFAULT_V2A_VOLUME_R_AOUT-1
2579
	call	AOUT_Pin16bitSet
2580
	SET_BSR	SID_BASE
1 tk 2581
 
2582
	;; notify that channel has already been updated by V2A function
2583
	;; (for faster handling, do this for all enabled channels each time this function is called)
2584
	movlw	0x00
2585
#if DEFAULT_V2A_VOLUME_L_AOUT
2586
	iorlw	(1 << (DEFAULT_V2A_VOLUME_L_AOUT-1))
2587
#endif
2588
#if DEFAULT_V2A_VOLUME_R_AOUT
2589
	iorlw	(1 << (DEFAULT_V2A_VOLUME_R_AOUT-1))
2590
#endif
2591
	iorwf	SID_SE_EXT_ALLOCATED, F, BANKED
2592
SIDSE_Filter_Vol_NoAOUT
2593
 
2594
	return
2595
 
2596
 
2597
;; --------------------------------------------------------------------------
2598
;; This function handles the AOUTs
2599
;; Used by Bassline/Drum and Multi Engine
2600
;; IN: pointer to SID_Ix_EXT_PARx_L in FSR0 (patch record)
2601
;;     EXT number in SID_SE_ELEMENT_NUM
2602
;; --------------------------------------------------------------------------
2603
SIDSE_BDM_EXT
2604
	;; skip if any F2X function has already updated the AOUTx register
2605
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2606
	call	MIOS_HLP_GetBitORMask
2607
	andwf	SID_SE_EXT_ALLOCATED, W, BANKED
2608
	bnz	SIDSE_BDM_EXT_End
2609
 
136 tk 2610
	;; store 16bit offset in MIOS_PARAMETER[12]
2611
	movff	POSTINC0, MIOS_PARAMETER1
2612
	movff	POSTDEC0, MIOS_PARAMETER2
2613
	movf	SID_SE_ELEMENT_NUM, W, BANKED
2614
	call	AOUT_Pin16bitSet
2615
	SET_BSR	SID_BASE
1 tk 2616
 
2617
SIDSE_BDM_EXT_End
2618
	return
2619
 
2620
 
2621
;; --------------------------------------------------------------------------
2622
;; This function updates the 8 external switches (called once per update cycle)
2623
;; IN: -
2624
;; --------------------------------------------------------------------------
2625
SIDSE_EXT_Switches
136 tk 2626
	lfsr	FSR1, GATES			; for easier addressing
1 tk 2627
 
136 tk 2628
	;; copy switch state from patch to GATES
1 tk 2629
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_CUSTOM_SW, INDF1
2630
 
2631
	;; help macro to improve oversight
2632
SIDSE_EXT_SWITCHES_FORWARD MACRO addr, flag, out
2633
	;; overlay with various gate functions if enabled
2634
  IF out && (out <= 8)
2635
	bcf	INDF1, 	out-1
2636
	btfsc	addr, flag, BANKED
2637
	bsf	INDF1, 	out-1
2638
  ENDIF
2639
	ENDM
2640
 
2641
	SET_BSR	SIDL_V1_BASE			; BSR set to SIDx_Vx_BASE for direct access
2642
 
2643
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC1_L_OUT
2644
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC2_L_OUT
2645
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC3_L_OUT
2646
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC1_R_OUT
2647
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC2_R_OUT
2648
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_GATE_ACTIVE, DEFAULT_GATE_OSC3_R_OUT
2649
 
2650
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC1_L_OUT
2651
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC2_L_OUT
2652
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC3_L_OUT
2653
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC1_R_OUT
2654
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC2_R_OUT
2655
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_SLIDE, DEFAULT_SLIDE_OSC3_R_OUT
2656
 
2657
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V1_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC1_L_OUT
2658
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V2_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC2_L_OUT
2659
	SIDSE_EXT_SWITCHES_FORWARD SIDL_V3_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC3_L_OUT
2660
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V1_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC1_R_OUT
2661
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V2_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC2_R_OUT
2662
	SIDSE_EXT_SWITCHES_FORWARD SIDR_V3_BASE + SID_Vx_STATE, SID_V_STATE_ACCENT, DEFAULT_ACCENT_OSC3_R_OUT
2663
 
2664
	SET_BSR	SID_BASE			; switch BSR back to SID base
2665
	return
2666
 
2667
 
2668
;; --------------------------------------------------------------------------
2669
;; --------------------------------------------------------------------------
2670
;;  Help Functions which are used by all engines
2671
;; --------------------------------------------------------------------------
2672
;; --------------------------------------------------------------------------
2673
 
2674
;; --------------------------------------------------------------------------
2675
;; Help Function: Scale Depth (7bit signed value scales 15bit signed value)
2676
;; IN:  8bit signed depth value (+0x80) in WREG
2677
;;      15bit signed value in MUL_A_[LH]
2678
;; OUT: result in MUL_R_[123]
2679
;; USES: TABLAT
2680
;; --------------------------------------------------------------------------
2681
SIDSE_Hlp_ScaleDepth
2682
	movwf	TABLAT		; temporary store depth value in TABLAT
2683
 
2684
	rcall	SIDSE_Hlp_GetAbs8
2685
	clrc
2686
	rlf	WREG, W
2687
	movwf	MUL_B_L, BANKED
2688
	clrf	MUL_B_H, BANKED
2689
 
2690
	;; 16*16 multiplication, result in MUL_R_[0123]
2691
	call	MATH_MUL16_16_SIGNED
2692
 
2693
	;; invert result if required
2694
	BRA_IFSET TABLAT, 7, ACCESS, SIDSE_Hlp_ScaleDepth_Cont
2695
SIDSE_Hlp_ScaleDepth_Neg
2696
	comf	MUL_R_1, BANKED
2697
	comf	MUL_R_2, BANKED
2698
	comf	MUL_R_3, BANKED
2699
	incf	MUL_R_1, F, BANKED
2700
	skpnz
2701
	incf	MUL_R_2, F, BANKED
2702
	skpnz
2703
	incf	MUL_R_3, F, BANKED
2704
SIDSE_Hlp_ScaleDepth_Cont
2705
	return
2706
 
2707
 
2708
;; --------------------------------------------------------------------------
2709
;; Like SIDSE_Hlp_ScaleDepth, but depth is increased/decreased by SID_Ix_Vx_ACCENT
2710
;; if the SID_SE_STATE, SID_SE_STATE_ACCENT flag is set
2711
;; IN:  8bit signed depth value (+0x80) in WREG
2712
;;      15bit signed value in MUL_A_[LH]
2713
;;      pointer to patch structure in FSR0
2714
;; OUT: result in MUL_R_[123]
2715
;; USES: TABLAT
2716
;; --------------------------------------------------------------------------
2717
SIDSE_Hlp_ScaleDepthAcc
2718
	;; check accent flag
2719
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_ACCENT, BANKED, SIDSE_Hlp_ScaleDepth
2720
 
2721
	movwf	MUL_R_1, BANKED	; (used as temporary register)
2722
 
2723
	;; increase/decrease value by 0x40 and saturate
2724
	BRA_IFCLR WREG, 7, ACCESS, SIDSE_Hlp_ScaleDepthAcc_Neg
2725
SIDSE_Hlp_ScaleDepthAcc_Pos
2726
	movlw	SID_Ix_Vx_ACCENT
2727
	movf	PLUSW0, W
2728
	addwf	MUL_R_1, W, BANKED
2729
	btfss	WREG, 7
2730
	movlw 0xff
2731
	rgoto	SIDSE_Hlp_ScaleDepth
2732
SIDSE_Hlp_ScaleDepthAcc_Neg
2733
	movlw	SID_Ix_Vx_ACCENT
2734
	comf	PLUSW0, W
2735
	addlw	1
2736
	btfsc	WREG, 7
2737
	movlw 0x00
2738
	rgoto	SIDSE_Hlp_ScaleDepth
2739
 
2740
;; --------------------------------------------------------------------------
2741
;; Help Function: Get absolute value
2742
;; IN:  signed 16-bit value in IRQ_TMP[12]
2743
;; Out: unsigned absolute value in IRQ_TMP[12]
2744
;;      sign in IRQ_TMP3[0]
2745
;; --------------------------------------------------------------------------
2746
SIDSE_Hlp_GetAbs16
2747
	;; convert IRQ_TMP[12] to unsigned integer, keep sign in IRQ_TMP3[0]
2748
	clrf	IRQ_TMP3
2749
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_Hlp_GetABS16_Pos
2750
SIDSE_Hlp_GetABS16_Neg
2751
	bsf	IRQ_TMP3, 0	; memorize sign in IRQ_TMP3[0]
2752
	comf	IRQ_TMP1, F
2753
	comf	IRQ_TMP2, F
2754
	incf	IRQ_TMP1, F
2755
	skpnz
2756
	incf	IRQ_TMP2, F
2757
SIDSE_Hlp_GetABS16_Pos
2758
	return
2759
 
2760
 
2761
;; --------------------------------------------------------------------------
2762
;; Help Function which returns the absolute value
2763
;; IN:  8-bit signed value in WREG
2764
;; OUT:	absolute value (0x00-0x7f) in WREG
2765
;; --------------------------------------------------------------------------
2766
SIDSE_Hlp_GetAbs8
2767
	movf	WREG, W
2768
	skpnz
2769
	addlw	1
2770
	btfss	WREG, 7
2771
	sublw 0x80
2772
	andlw	0x7f
2773
	return
2774
 
2775
;; --------------------------------------------------------------------------
2776
;; Help Function for SIDSE_ENV to increase or decrease the ENV counter
2777
;; IN:  incr value in MIOS_PARAMETER[12]
2778
;;	target level in IRQ_TMP1
2779
;;      pointer to SID_ENVx_BASE in FSR1
2780
;; OUT:	zero flag set if max value reached
2781
;; --------------------------------------------------------------------------
2782
SIDSE_Hlp_ENV_IncrDecrCtr
2783
	;; if current level > target level, branch to decr function
2784
	movlw	SID_ENVx_CTR_H
2785
	movf	PLUSW1, W
2786
	cpfslt	IRQ_TMP1, ACCESS
2787
	rgoto SIDSE_Hlp_ENV_IncrCtr
2788
	rgoto	SIDSE_Hlp_ENV_DecrCtr
2789
 
2790
 
2791
;; --------------------------------------------------------------------------
2792
;; Help Function for SIDSE_ENV to increase the ENV counter
2793
;; IN:  incr value in MIOS_PARAMETER[12]
2794
;;	max level in IRQ_TMP1
2795
;;      pointer to SID_ENVx_BASE in FSR1
2796
;; OUT:	zero flag set if max value reached
2797
;; --------------------------------------------------------------------------
2798
SIDSE_Hlp_ENV_IncrCtr
2799
	;; add to ENV counter
2800
	movf	POSTINC1, W	; SID_ENVx_CTR_L
2801
	addwf	MIOS_PARAMETER1, F
2802
	movf	POSTDEC1, W	; SID_ENVx_CTR_H
2803
	addwfc	MIOS_PARAMETER2, F
2804
	bc	SIDSE_Hlp_ENV_IncrCtr_Max
2805
 
2806
	;; if value >= level: switch to next phase
2807
	movf	MIOS_PARAMETER1, W
2808
	sublw	0x00
2809
	movf	MIOS_PARAMETER2, W
2810
	subwfb	IRQ_TMP1, W
2811
	bc	SIDSE_Hlp_ENV_IncrCtr_NoMax
2812
 
2813
SIDSE_Hlp_ENV_IncrCtr_Max
2814
	;; write level to MIOS_PARAMETER[12]
2815
	movff	IRQ_TMP1, MIOS_PARAMETER2
2816
	clrf	MIOS_PARAMETER1
2817
 
2818
	andlw	0x00		; set zero flag and exit
2819
	return
2820
 
2821
SIDSE_Hlp_ENV_IncrCtr_NoMax
2822
	iorlw	0xff		; clear zero flag and exit
2823
	return
2824
 
2825
 
2826
;; --------------------------------------------------------------------------
2827
;; Help Function for SIDSE_ENV to decrease the ENV counter
2828
;; IN:  decr value in MIOS_PARAMETER[12]
2829
;;	min level in IRQ_TMP1
2830
;;      pointer to SID_ENVx_BASE in FSR1
2831
;; OUT:	zero flag set if min value reached
2832
;; --------------------------------------------------------------------------
2833
SIDSE_Hlp_ENV_DecrCtr
2834
	;; subtraction from ENV counter
2835
	movf	MIOS_PARAMETER1, W
2836
	subwf	POSTINC1, W	; SID_ENVx_CTR_L
2837
	movwf	MIOS_PARAMETER1
2838
	movf	MIOS_PARAMETER2, W
2839
	subwfb	POSTDEC1, W	; SID_ENVx_CTR_H
2840
	movwf	MIOS_PARAMETER2
2841
	bnc	SIDSE_Hlp_ENV_DecrCtr_Min
2842
 
2843
	;; if value < level: switch to next phase
2844
	movlw	0x00
2845
	subwf	MIOS_PARAMETER1, W
2846
	movf	IRQ_TMP1, W
2847
	subwfb	MIOS_PARAMETER2, W
2848
	bc	SIDSE_Hlp_ENV_DecrCtr_NoMin
2849
 
2850
SIDSE_Hlp_ENV_DecrCtr_Min
2851
	;; write level to MIOS_PARAMETER[12]
2852
	movff	IRQ_TMP1, MIOS_PARAMETER2
2853
	clrf	MIOS_PARAMETER1
2854
 
2855
	andlw	0x00		; set zero flag and exit
2856
	return
2857
 
2858
SIDSE_Hlp_ENV_DecrCtr_NoMin
2859
	iorlw	0xff		; clear zero flag and exit
2860
	return
2861
 
2862
;; --------------------------------------------------------------------------
2863
;; Help Function for SIDSE_ENV
2864
;; IN:  pointer to SID_Ix_L_ENVx_BASE in FSR0 (patch record)
2865
;;      pointer to SID_ENVx_BASE in FSR1
2866
;;      curve value in WREG (0x80: no curve)
2867
;;	MBFM_Ix_ENVx_ATTACKx/MBFM_Ix_ENVx_DECAYx or MBFM_Ix_ENVx_SUSTAINx in IRQ_TMP3
2868
;;
2869
;;      Can also be used to determine the delay increment value
2870
;;      In this case, only IRQ_TMP3 (Ix_xxx_Delay) is expected in IRQ_TMP3, and 0x80 in WREG (no curve!)
2871
;;
2872
;; OUT:	value which should be added to - or subtracted from - SID_ENVx_CTR_[LH]
2873
;;      low-byte in MIOS_PARAMETER1; high-byte in MIOS_PARAMETER2
2874
;; --------------------------------------------------------------------------
2875
SIDSE_Hlp_ENV_GetBendedValue
2876
	;; get curve parameter and store it in IRQ_TMP1
2877
	movwf	IRQ_TMP1
2878
	xorlw	0x80		; if != 0x80, we apply the curve, otherwise we have a linear waveform
2879
 	bnz	SIDSE_Hlp_ENV_GetBendedValue_Crv
2880
 
2881
	;; curve not selected, get value from ENV_TABLE
2882
	movf	IRQ_TMP3, W
2883
	TABLE_ADDR_MUL_W SID_ENV_TABLE, 2	; determine table address
2884
	tblrd*+				; transfer table entry to MUL_A_[LH]
2885
	movff	TABLAT, MIOS_PARAMETER1
2886
	tblrd*+
2887
	movff	TABLAT, MIOS_PARAMETER2
2888
	return
2889
 
2890
SIDSE_Hlp_ENV_GetBendedValue_Crv
2891
	;; copy current counter value to IRQ_TMP2
2892
	movlw	SID_ENVx_CTR_H
2893
	movff	PLUSW1, IRQ_TMP2
2894
 
878 tk 2895
	;; rightshift rate in IRQ_TMP3 (8bit -> 7bit value range)
1 tk 2896
	clrc
2897
	rrf	IRQ_TMP3, F
2898
 
2899
	;; feedback: calculate ABS8(CURVE) * ENV_x_CTR_H
2900
	movf	IRQ_TMP1, W		; get absolute value of curve parameter
2901
	rcall	SIDSE_Hlp_GetAbs8
2902
	btfsc	IRQ_TMP1, 7; invert if positive range (for more logical behaviour of positive/negative curve)
2903
	xorlw 0x7f
2904
	mulwf	IRQ_TMP2, ACCESS	; multiply with current counter value
2905
 
2906
	;; when CURVE parameter < 0x80: bend down, else up
2907
	BRA_IFCLR IRQ_TMP1, 7, ACCESS, SIDSE_Hlp_ENV_GetBendedValueDown
2908
SIDSE_Hlp_ENV_GetBendedValueUp
2909
	comf	IRQ_TMP3, F
2910
	bcf	IRQ_TMP3, 7
2911
	movf	PRODH, W
2912
	subwf	IRQ_TMP3, W
2913
	btfsc	WREG, 7
2914
	movlw 0x00
2915
	rgoto	SIDSE_Hlp_ENV_GetBendedValueCont
2916
 
2917
SIDSE_Hlp_ENV_GetBendedValueDown
2918
	comf	IRQ_TMP3, W
2919
	andlw	0x7f
2920
	addwf	PRODH, W
2921
	btfsc	WREG, 7
2922
	movlw 0x7f
2923
	;; 	rgoto	SIDSE_Hlp_ENV_GetBendedValue_Cont
2924
 
2925
SIDSE_Hlp_ENV_GetBendedValueCont
2926
	andlw	0x7f
2927
	TABLE_ADDR_MUL_W SID_FRQ_TABLE, 2	; determine table address
2928
	tblrd*+				; transfer table entry to MIOS_PARAMETER[12]
2929
	movff	TABLAT, MIOS_PARAMETER1
2930
	tblrd*+
2931
	movff	TABLAT, MIOS_PARAMETER2
2932
	return
2933
 
2934
 
2935
;; --------------------------------------------------------------------------
2936
;;  FUNCTION: SIDSE_Hlp_GetSIDFrqPtr
2937
;;  DESCRIPTION: returns pointer to SIDx_V1_FRQ_L register
2938
;;  IN: SID_SE_ELEMENT_NUM
2939
;;  OUT: pointer in FSR2
2940
;; --------------------------------------------------------------------------
2941
SIDSE_Hlp_GetSIDFrqPtr
2942
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Hlp_GetSIDFrqPtr_4567
2943
SIDSE_Hlp_GetSIDFrqPtr_0123
2944
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Hlp_GetSIDFrqPtr_23
2945
SIDSE_Hlp_GetSIDFrqPtr_01
2946
	lfsr	FSR2, SIDL_BASE + SIDx_V1_FRQ_L
2947
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2948
	lfsr	FSR2, SIDL_BASE + SIDx_V2_FRQ_L
2949
	return
2950
 
2951
SIDSE_Hlp_GetSIDFrqPtr_23
2952
	lfsr	FSR2, SIDL_BASE + SIDx_V3_FRQ_L
2953
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2954
	lfsr	FSR2, SIDR_BASE + SIDx_V1_FRQ_L
2955
	return
2956
 
2957
SIDSE_Hlp_GetSIDFrqPtr_4567
2958
	lfsr	FSR2, SIDR_BASE + SIDx_V2_FRQ_L
2959
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2960
	lfsr	FSR2, SIDR_BASE + SIDx_V3_FRQ_L
2961
	return
2962
 
2963
;; --------------------------------------------------------------------------
2964
;;  FUNCTION: SIDSE_Hlp_GetSIDPWPtr
2965
;;  DESCRIPTION: returns pointer to SIDx_V1_PW_L register
2966
;;  IN: SID_SE_ELEMENT_NUM
2967
;;  OUT: pointer in FSR2
2968
;; --------------------------------------------------------------------------
2969
SIDSE_Hlp_GetSIDPWPtr
2970
	BRA_IFSET SID_SE_ELEMENT_NUM, 2, BANKED, SIDSE_Hlp_GetSIDPWPtr_4567
2971
SIDSE_Hlp_GetSIDPWPtr_0123
2972
	BRA_IFSET SID_SE_ELEMENT_NUM, 1, BANKED, SIDSE_Hlp_GetSIDPWPtr_23
2973
SIDSE_Hlp_GetSIDPWPtr_01
2974
	lfsr	FSR2, SIDL_BASE + SIDx_V1_PW_L
2975
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2976
	lfsr	FSR2, SIDL_BASE + SIDx_V2_PW_L
2977
	return
2978
 
2979
SIDSE_Hlp_GetSIDPWPtr_23
2980
	lfsr	FSR2, SIDL_BASE + SIDx_V3_PW_L
2981
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2982
	lfsr	FSR2, SIDR_BASE + SIDx_V1_PW_L
2983
	return
2984
 
2985
SIDSE_Hlp_GetSIDPWPtr_4567
2986
	lfsr	FSR2, SIDR_BASE + SIDx_V2_PW_L
2987
	btfsc	SID_SE_ELEMENT_NUM, 0, BANKED
2988
	lfsr	FSR2, SIDR_BASE + SIDx_V3_PW_L
2989
	return
2990
 
2991
;; --------------------------------------------------------------------------
2992
;;  FUNCTION: SIDSE_Hlp_Pitch_Mod
2993
;; IN: frequency in SID_SE_TARGET_FRQ_[LH]
2994
;;     Signed Modulation offset in SID_MOD_TARG_PITCHx_[LHU]
2995
;;     Voice number in SID_SE_ELEMENT_NUM
2996
;; OUT: modulated frequency in SID_SE_TARGET_FRQ_[LH]
2997
;; --------------------------------------------------------------------------
2998
SIDSE_Hlp_Pitch_Mod
2999
	;; calculate pointer to MOD target array -> FSR2
3000
	movf	SID_SE_ELEMENT_NUM, W, BANKED
3001
	addlw	(SID_MOD_TARG_PITCH1_L-SID_MOD_TARG_BASE)/3
3002
	mullw	3
3003
	lfsr	FSR2, SID_MOD_TARG_BASE
3004
	movf	PRODL, W
3005
	addwf	FSR2L, F
3006
 
3007
	;; add modulation value to frequency
3008
	movff	POSTINC2, PRODL
3009
	movff	POSTINC2, PRODH
3010
	movff	POSTINC2, TABLAT
3011
 
398 tk 3012
#if 0
391 tk 3013
	;; value is divided by four for better usage of the depth range
1 tk 3014
	clrc
3015
	btfsc	TABLAT, 7
3016
	setc
3017
	rrf	TABLAT, F
3018
	rrf	PRODH, F
3019
	rrf	PRODL, F
3020
 
3021
	clrc
3022
	btfsc	TABLAT, 7
3023
	setc
3024
	rrf	TABLAT, F
3025
	rrf	PRODH, F
3026
	rrf	PRODL, F
391 tk 3027
#endif
1 tk 3028
 
3029
	movf	PRODL, W
3030
	addwf	SID_SE_TARGET_FRQ_L, F, BANKED
3031
	movf	PRODH, W
3032
	addwfc	SID_SE_TARGET_FRQ_H, F, BANKED
3033
 
3034
	;; saturate
3035
	BRA_IFSET TABLAT, 7, ACCESS, SIDSE_Hlp_Pitch_Mod_SatNeg
3036
SIDSE_Hlp_Pitch_Mod_SatPos
3037
	movf	TABLAT, W
3038
	bnz	SIDSE_Hlp_Pitch_Mod_SatPos_Sat
3039
	bnc	SIDSE_Hlp_Pitch_Mod_NoSat
3040
SIDSE_Hlp_Pitch_Mod_SatPos_Sat
3041
	setf	SID_SE_TARGET_FRQ_L, BANKED
3042
	setf	SID_SE_TARGET_FRQ_H, BANKED
3043
	rgoto	SIDSE_Hlp_Pitch_Mod_Sat_Cont
3044
SIDSE_Hlp_Pitch_Mod_SatNeg
3045
	comf	TABLAT, W
3046
	bnz	SIDSE_Hlp_Pitch_Mod_SatNeg_Sat
3047
	bc	SIDSE_Hlp_Pitch_Mod_NoSat
3048
SIDSE_Hlp_Pitch_Mod_SatNeg_Sat
3049
	clrf	SID_SE_TARGET_FRQ_L, BANKED
3050
	clrf	SID_SE_TARGET_FRQ_H, BANKED
3051
	;; 	rgoto	SIDSE_Hlp_Pitch_Mod_Sat_Cont
3052
SIDSE_Hlp_Pitch_Mod_Sat_Cont
3053
SIDSE_Hlp_Pitch_Mod_NoSat
3054
	return
3055
 
3056
;; --------------------------------------------------------------------------
3057
;; Help Function which interpolates a 16bit value
3058
;; IN:  base address of parameter set (FIPx_BASE) in FSR1
3059
;;      target value in IRQ_TMP[12]
3060
;; OUT:	interpolated value in IRQ_TMP[12]
3061
;; USES: PROD[LH]
3062
;; --------------------------------------------------------------------------
3063
SIDSE_Hlp_IP
3064
	;; shift-right target value (internally we have to calculate with a signed 16-bit value)
3065
	clrc
3066
	rrf	IRQ_TMP2, F
3067
	rrf	IRQ_TMP1, F
3068
 
3069
	;; check for new target value
3070
	movlw	FIPx_TARGET_VALUE_L
3071
	movf	PLUSW1, W
3072
	cpfseq	IRQ_TMP1, ACCESS
3073
	rgoto SIDSE_Hlp_IP_Change
3074
	movlw	FIPx_TARGET_VALUE_H
3075
	movf	PLUSW1, W
3076
	cpfseq	IRQ_TMP2, ACCESS
3077
	rgoto SIDSE_Hlp_IP_Change
3078
	rgoto	SIDSE_Hlp_IP_Cont
3079
SIDSE_Hlp_IP_Change
3080
	;; copy new target value
3081
	movlw	FIPx_TARGET_VALUE_L
3082
	movff	IRQ_TMP1, PLUSW1
3083
	movlw	FIPx_TARGET_VALUE_H
3084
	movff	IRQ_TMP2, PLUSW1
3085
 
3086
	;; calculate difference between current value and new target value
3087
	movlw	FIPx_VALUE_L
3088
	movf	PLUSW1, W
3089
	subwf	IRQ_TMP1, W
3090
	movwf	IRQ_TMP1
3091
	movlw	FIPx_VALUE_H
3092
	movf	PLUSW1, W
3093
	subwfb	IRQ_TMP2, W
3094
	movwf	IRQ_TMP2
3095
 
3096
	;; value which will be added on each step: diverence / 8
3097
	rrf	IRQ_TMP2, F
3098
	rrf	IRQ_TMP1, F
3099
	rrf	IRQ_TMP2, F
3100
	rrf	IRQ_TMP1, F
3101
	rrf	IRQ_TMP2, F
3102
	rrf	IRQ_TMP1, F
3103
 
3104
	movf	IRQ_TMP2, W
3105
	andlw	0x1f
3106
	btfsc	WREG, 4
3107
	iorlw 0xe0
3108
	movwf	IRQ_TMP2
3109
 
3110
	;; should be at least 1 (!)
3111
	movf	IRQ_TMP1, W
3112
	iorwf	IRQ_TMP2, W
3113
	skpnz
3114
	incf	IRQ_TMP1, F
3115
 
3116
	;; store divided value
3117
	movlw	FIPx_DIV_VALUE_L
3118
	movff	IRQ_TMP1, PLUSW1
3119
	movlw	FIPx_DIV_VALUE_H
3120
	movff	IRQ_TMP2, PLUSW1
3121
 
3122
SIDSE_Hlp_IP_Cont
3123
 
3124
	;; step handler
3125
 
3126
	;; copy current filter value into IRQ_TMP[12]
3127
	movlw	FIPx_VALUE_L
3128
	movff	PLUSW1, IRQ_TMP1
3129
	movlw	FIPx_VALUE_H
3130
	movff	PLUSW1, IRQ_TMP2
3131
 
3132
	;; do nothing if target value already reached
3133
	movlw	FIPx_TARGET_VALUE_L
3134
	movf	PLUSW1, W
3135
	cpfseq	IRQ_TMP1, ACCESS
3136
	rgoto SIDSE_Hlp_IP_Cont_Do
3137
	movlw	FIPx_TARGET_VALUE_H
3138
	movf	PLUSW1, W
3139
	cpfseq	IRQ_TMP2, ACCESS
3140
	rgoto SIDSE_Hlp_IP_Cont_Do
3141
	rgoto	SIDSE_Hlp_IP_End
3142
SIDSE_Hlp_IP_Cont_Do
3143
 
3144
	;; add div value to current value
3145
	movlw	FIPx_DIV_VALUE_L
3146
	movf	PLUSW1, W
3147
	addwf	IRQ_TMP1, F
3148
	movlw	FIPx_DIV_VALUE_H
3149
	movf	PLUSW1, W
3150
	addwfc	IRQ_TMP2, F
3151
 
3152
	;; end reached on overflow
3153
	BRA_IFSET IRQ_TMP2, 7, ACCESS, SIDSE_Hlp_IP_TargetReached
3154
 
3155
	;; end reached if value >= target value
3156
	movlw	FIPx_TARGET_VALUE_L
3157
	movf	PLUSW1, W
3158
	subwf	IRQ_TMP1, W
3159
	movlw	FIPx_TARGET_VALUE_H
3160
	movf	PLUSW1, W
3161
	subwfb	IRQ_TMP2, W
3162
 
3163
	;; branch depending on increment/decrement
3164
	movlw	FIPx_DIV_VALUE_H
3165
	BRA_IFSET PLUSW1, 7, ACCESS, SIDSE_Hlp_IP_Dec
3166
SIDSE_Hlp_IP_Inc
3167
	bnc	SIDSE_Hlp_IP_End
3168
	;; 	rgoto	SIDSE_Hlp_IP_TargetReached
3169
 
3170
SIDSE_Hlp_IP_TargetReached
3171
	movlw	FIPx_TARGET_VALUE_L
3172
	movff	PLUSW1, IRQ_TMP1
3173
	movlw	FIPx_TARGET_VALUE_H
3174
	movff	PLUSW1, IRQ_TMP2
3175
	rgoto	SIDSE_Hlp_IP_End
3176
 
3177
SIDSE_Hlp_IP_Dec
3178
	bc	SIDSE_Hlp_IP_End
3179
	rgoto	SIDSE_Hlp_IP_TargetReached
3180
 
3181
SIDSE_Hlp_IP_End
3182
	;; copy back IRQ_TMP[12] to FIPx_VALUE_[LH]
3183
	movlw	FIPx_VALUE_L
3184
	movff	IRQ_TMP1, PLUSW1
3185
	movlw	FIPx_VALUE_H
3186
	movff	IRQ_TMP2, PLUSW1
3187
 
3188
	;; left-shift result (it's 16bit unsigned again)
3189
	clrc
3190
	rlf	IRQ_TMP1, F
3191
	rlf	IRQ_TMP2, F
3192
 
3193
	return
3194