Subversion Repositories svn.mios

Rev

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