Subversion Repositories svn.mios

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
44 tk 1
; $Id: sid_se_m.inc 44 2008-01-30 21:39:30Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; Multi Engine
5
;
6
; Note: Bassline engine re-uses LFO/ENV/Note/Ext handler of Multi Engine!
7
;
8
; ==========================================================================
9
;
10
;  Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
11
;  Idea for ENV Curve Parameter and OSC synchronization by Jess D. Skov-Nielsen
12
;  Licensed for personal non-commercial use only.
13
;  All other rights reserved.
14
;
15
; ==========================================================================
16
 
17
 
18
;; --------------------------------------------------------------------------
19
;;  Multi Engine handler called by SIDSE_Handler (sid_se.inc)
20
;; --------------------------------------------------------------------------
21
SIDSE_M_Handler
22
	SET_BSR	SID_BASE		; prepare BSR for SID register access
23
 
24
	;; branch depending on cycle
25
	BRA_IFSET SID_STAT, SID_STAT_SE_CYCLE, ACCESS, SIDSE_M_Handler_Cycle2
26
 
27
SIDSE_M_Handler_Cycle1
28
	bsf	SID_STAT, SID_STAT_SE_CYCLE	; on next handler call we want to process the second cycle
29
 
30
	;; clear "allocated" notification for external AOUTs - flags will be set if X2A function active
31
	clrf	SID_SE_EXT_ALLOCATED, BANKED
32
 
33
	;; clear modulation targets
34
	movlw	((SID_MOD_TARG_CLEAR_END-SID_MOD_TARG_CLEAR_BEGIN)+1) & 0xff
35
	movwf	IRQ_TMP1
36
	lfsr	FSR0, SID_MOD_TARG_CLEAR_BEGIN
37
SIDSE_M_Handler_ModClearLoop
38
	clrf	POSTINC0
39
	decfsz	IRQ_TMP1, F
40
	rgoto	SIDSE_M_Handler_ModClearLoop
41
 
42
 
43
	;; ------------------------------------------------------------------
44
	;; 1st Cycle: LFOs
45
	;; ------------------------------------------------------------------
46
SIDSE_M_HANDLER_LFO_MACRO MACRO voice_base, patch_lfo_offset, lfo_base
47
	lfsr	FSR1, voice_base
48
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
49
	movlw	SID_Ix_M_Vx_VOICE_ASSGN
50
	movff	PLUSW0, SID_CURRENT_VOICE_ASSG
51
	movlw	patch_lfo_offset
52
	addwf	FSR0L, F
53
	movlw	0x00
54
	addwfc	FSR0H, F
55
	lfsr	FSR1, lfo_base
56
	call	SIDSE_M_LFO
57
	incf	SID_SE_ELEMENT_NUM, F, BANKED
58
	ENDM
59
 
60
	clrf	SID_SE_ELEMENT_NUM, BANKED
61
SIDSE_M_Handler_LFO_L
62
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V1_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO1_BASE
63
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V1_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO2_BASE
64
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V2_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO3_BASE
65
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V2_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO4_BASE
66
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V3_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO5_BASE
67
	SIDSE_M_HANDLER_LFO_MACRO SIDL_V3_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO6_BASE
68
 
69
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
70
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_Handler_LFO_NotR
71
SIDSE_M_Handler_LFO_R
72
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V1_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO7_BASE
73
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V1_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO8_BASE
74
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V2_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO9_BASE
75
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V2_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO10_BASE
76
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V3_BASE, SID_Ix_M_Vx_LFO1_MODE, SID_LFO11_BASE
77
	SIDSE_M_HANDLER_LFO_MACRO SIDR_V3_BASE, SID_Ix_M_Vx_LFO2_MODE, SID_LFO12_BASE
78
SIDSE_M_Handler_LFO_NotR
79
 
80
	;; ------------------------------------------------------------------
81
	;; 1st Cycle: Envelopes
82
	;; ------------------------------------------------------------------
83
SIDSE_M_HANDLER_ENV_MACRO MACRO voice_base, env_base
84
	lfsr	FSR1, voice_base
85
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
86
	lfsr	FSR1, env_base
87
	call	SIDSE_M_ENV
88
	incf	SID_SE_ELEMENT_NUM, F, BANKED
89
	ENDM
90
 
91
	;; accent feature not used by multi engine
92
	bcf	SID_SE_STATE, SID_SE_STATE_ACCENT, BANKED
93
 
94
	clrf	SID_SE_ELEMENT_NUM, BANKED
95
	SIDSE_M_HANDLER_ENV_MACRO SIDL_V1_BASE, SID_ENV1_BASE
96
	SIDSE_M_HANDLER_ENV_MACRO SIDL_V2_BASE, SID_ENV2_BASE
97
	SIDSE_M_HANDLER_ENV_MACRO SIDL_V3_BASE, SID_ENV3_BASE
98
 
99
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
100
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_Handler_ENV_NotR
101
SIDSE_M_Handler_ENV_R
102
	SIDSE_M_HANDLER_ENV_MACRO SIDR_V1_BASE, SID_ENV4_BASE
103
	SIDSE_M_HANDLER_ENV_MACRO SIDR_V2_BASE, SID_ENV5_BASE
104
	SIDSE_M_HANDLER_ENV_MACRO SIDR_V3_BASE, SID_ENV6_BASE
105
SIDSE_M_Handler_ENV_NotR
106
 
107
 
108
	;; ------------------------------------------------------------------
109
	;; 2nd Cycle: LED Matrix Update
110
	;; ------------------------------------------------------------------
111
	call	SIDSE_M_CS_LM
112
 
113
	rgoto	SIDSE_M_Handler_End
114
 
115
 
116
SIDSE_M_Handler_Cycle2
117
	bcf	SID_STAT, SID_STAT_SE_CYCLE	; on next handler call we want to process the first cycle
118
 
119
	;; ------------------------------------------------------------------
120
	;; 2nd Cycle: Clock Handler
121
	;; ------------------------------------------------------------------
122
	call	SIDSE_Clk
123
 
124
 
125
	;; ------------------------------------------------------------------
126
	;; 2nd Cycle: Wavetable Handler
127
	;; ------------------------------------------------------------------
128
SIDSE_M_HANDLER_WT_MACRO MACRO patch_base, wt_base
129
	lfsr	FSR0, patch_base
130
	lfsr	FSR2, wt_base
131
	rcall	SIDSE_M_WT
132
	incf	SID_SE_ELEMENT_NUM, F, BANKED
133
	ENDM
134
 
135
	clrf	SID_SE_ELEMENT_NUM, BANKED
136
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I1_BASE, SID_WT1_BASE
137
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I2_BASE, SID_WT2_BASE
138
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I3_BASE, SID_WT3_BASE
139
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I4_BASE, SID_WT4_BASE
140
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I5_BASE, SID_WT5_BASE
141
	SIDSE_M_HANDLER_WT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I6_BASE, SID_WT6_BASE
142
 
143
	;; clear all WT requests
144
	clrf	SID_SE_TRG_EVNT_U, BANKED
145
 
146
 
147
	;; ------------------------------------------------------------------
148
	;; 2nd Cycle: Arp Handler
149
	;; ------------------------------------------------------------------
150
SIDSE_M_HANDLER_ARP_MACRO MACRO midi_voice_base
151
	lfsr	FSR2, midi_voice_base
152
	rcall	SIDSE_M_Hlp_GetAssignedVoicePtr
153
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
154
	call	SIDSE_Arp
155
	incf	SID_SE_ELEMENT_NUM, F, BANKED
156
	ENDM
157
 
158
	clrf	SID_SE_ELEMENT_NUM, BANKED
159
SIDSE_M_Handler_Arp_L
160
	SIDSE_M_HANDLER_ARP_MACRO SID_MV1_BASE
161
	SIDSE_M_HANDLER_ARP_MACRO SID_MV2_BASE
162
	SIDSE_M_HANDLER_ARP_MACRO SID_MV3_BASE
163
 
164
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
165
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_Handler_Arp_NotR
166
SIDSE_M_Handler_Arp_R
167
	SIDSE_M_HANDLER_ARP_MACRO SID_MV4_BASE
168
	SIDSE_M_HANDLER_ARP_MACRO SID_MV5_BASE
169
	SIDSE_M_HANDLER_ARP_MACRO SID_MV6_BASE
170
SIDSE_M_Handler_Arp_NotR
171
 
172
 
173
	;; ------------------------------------------------------------------
174
	;; 2nd Cycle: check ENV/LFO/Note Sync requests
175
	;; ------------------------------------------------------------------
176
	call	SIDSE_M_Sync
177
 
178
 
179
	;; ------------------------------------------------------------------
180
	;; 2nd Cycle: Voices
181
	;; ------------------------------------------------------------------
182
SIDSE_M_HANDLER_NOTE_MACRO MACRO voice_base
183
	lfsr	FSR1, voice_base
184
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
185
	rcall	SIDSE_M_Note
186
	incf	SID_SE_ELEMENT_NUM, F, BANKED
187
	ENDM
188
 
189
	clrf	SID_SE_ELEMENT_NUM, BANKED
190
SIDSE_M_Handler_Note_L
191
	SIDSE_M_HANDLER_NOTE_MACRO SIDL_V1_BASE
192
	SIDSE_M_HANDLER_NOTE_MACRO SIDL_V2_BASE
193
	SIDSE_M_HANDLER_NOTE_MACRO SIDL_V3_BASE
194
 
195
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
196
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_Handler_Note_NotR
197
SIDSE_M_Handler_Note_R
198
	SIDSE_M_HANDLER_NOTE_MACRO SIDR_V1_BASE
199
	SIDSE_M_HANDLER_NOTE_MACRO SIDR_V2_BASE
200
	SIDSE_M_HANDLER_NOTE_MACRO SIDR_V3_BASE
201
SIDSE_M_Handler_Note_NotR
202
 
203
	;; ------------------------------------------------------------------
204
	;; 2nd Cycle: Filter
205
	;; ------------------------------------------------------------------
206
 
207
SIDSE_M_Handler_Filter_L
208
	clrf	SID_SE_ELEMENT_NUM, BANKED
209
	lfsr	FSR0, SID_PATCH_BUFFER_SHADOW + SID_Ix_M_S1F_BASE
210
	lfsr	FSR1, SID_MOD_TARG_FIL1_L
211
	lfsr	FSR2, SIDL_BASE
212
	call	SIDSE_Filter
213
 
214
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
215
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_Handler_Filter_NotR
216
SIDSE_M_Handler_Filter_R
217
	incf	SID_SE_ELEMENT_NUM, F, BANKED
218
	lfsr	FSR0, SID_PATCH_BUFFER_SHADOW + SID_Ix_M_S2F_BASE
219
	lfsr	FSR1, SID_MOD_TARG_FIL2_L
220
	lfsr	FSR2, SIDR_BASE
221
	call	SIDSE_Filter
222
SIDSE_M_Handler_Filter_NotR
223
 
224
 
225
	;; ------------------------------------------------------------------
226
	;; 2nd Cycle: AOUTs (External/Extensions)
227
	;; ------------------------------------------------------------------
228
SIDSE_M_HANDLER_EXT_MACRO MACRO patch_base, aout_base
229
	lfsr	FSR0, patch_base
230
	lfsr	FSR1, aout_base
231
	call	SIDSE_BDM_EXT
232
	incf	SID_SE_ELEMENT_NUM, F, BANKED
233
	ENDM
234
 
235
	clrf	SID_SE_ELEMENT_NUM, BANKED
236
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR1_L, AOUT0_L
237
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR2_L, AOUT1_L
238
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR3_L, AOUT2_L
239
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR4_L, AOUT3_L
240
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR5_L, AOUT4_L
241
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR6_L, AOUT5_L
242
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR7_L, AOUT6_L
243
	SIDSE_M_HANDLER_EXT_MACRO SID_PATCH_BUFFER_SHADOW + SID_Ix_EXT_PAR8_L, AOUT7_L
244
 
245
 
246
	;; ------------------------------------------------------------------
247
	;; 2nd Cycle: External Switches
248
	;; ------------------------------------------------------------------
249
	call	SIDSE_EXT_Switches
250
 
251
 
252
	;; ------------------------------------------------------------------
253
	;; call temporary routine which updates static SID registers
254
	;; ------------------------------------------------------------------
255
 
256
	call	SIDSE_M_UpdateStatRegs
257
 
258
 
259
	;; ------------------------------------------------------------------
260
	;; clear FA/FB and FC synch request
261
	;; ------------------------------------------------------------------
262
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FA_REQ, BANKED
263
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FB_REQ, BANKED
264
	bcf	SID_SE_STATE, SID_SE_STATE_MIDI_CLK_FC_REQ, BANKED
265
 
266
SIDSE_M_Handler_End
267
	return
268
 
269
 
270
 
271
;; --------------------------------------------------------------------------
272
;;  FUNCTION: SIDSE_M_GetAssignedInsPtr
273
;;  DESCRIPTION: returns pointer to SID_Ix_M_Iy_BASE depending on assigned
274
;;  MIDI voice
275
;;  IN: pointer to SIDx_Vx_BASE in FSR1
276
;;  OUT: pointer to patch in FSR0
277
;; --------------------------------------------------------------------------
278
SIDSE_M_Hlp_GetAssignedInsPtr
279
	movlw	SID_Vx_ASSIGNED_MV
280
	movf	PLUSW1, W
281
	mullw	SID_Ix_M_I2_BASE - SID_Ix_M_I1_BASE
282
	lfsr	FSR0, SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I1_BASE
283
	movf	PRODL, W
284
	addwf	FSR0L, F
285
	movf	PRODH, W
286
	addwfc	FSR0H, F
287
	return
288
 
289
;; --------------------------------------------------------------------------
290
;;  FUNCTION: SIDSE_M_GetAssignedVoicePtr
291
;;  DESCRIPTION: returns pointer to SID_Vx_BASE depending on assigned voice
292
;;  IN: pointer to SIDx_MVx_BASE in FSR2
293
;;  OUT: pointer to voice in FSR1
294
;; --------------------------------------------------------------------------
295
SIDSE_M_Hlp_GetAssignedVoicePtr
296
	movlw	SID_MVx_LAST_VOICE
297
	movf	PLUSW2, W
298
	mullw	SID_Vx_RECORD_LEN
299
	lfsr	FSR1, SIDL_V1_BASE
300
	movf	PRODL, W
301
	addwf	FSR1L, F
302
	return
303
 
304
 
305
;; --------------------------------------------------------------------------
306
;;  Updates static SID registers
307
;;  (temporary)
308
;; --------------------------------------------------------------------------
309
SIDSE_M_UpdateStatRegs
310
SIDSE_M_UPDATESTAT_MACRO	MACRO voice_base, sid_base, swinsid_mode, swinsid_phase
311
	LOCAL	SIDSE_M_UpdateStatRegs_NoADSR
312
 
313
	lfsr	FSR1, voice_base
314
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
315
 
316
	movlw	0x09
317
	andwf	sid_base + SIDx_V1_CTRL, F, BANKED
318
	movlw	SID_Ix_Vx_WAVEFORM
319
	swapf	PLUSW0, W
320
	andlw	0xf6
321
	btfsc	WREG, 7; ensure that noise will not "lock on" like described in 6581 spec
322
	andlw 0x8f
323
	iorwf	sid_base + SIDx_V1_CTRL, F, BANKED
324
 
325
	;; if ABW (ADSR bug workaround) function active, update ADSR register only when the gate is set
326
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
327
	BRA_IFSET WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_M_UpdateStatRegs_NoADSR
328
	movlw	SID_Ix_Vx_AD
329
	movff	PLUSW0, sid_base + SIDx_V1_ENV_AD
330
	movlw	SID_Ix_Vx_SR
331
	movff	PLUSW0, sid_base + SIDx_V1_ENV_SR
332
SIDSE_M_UpdateStatRegs_NoADSR
333
#if ENABLE_SWINSID
334
	movlw	SID_Ix_Vx_SWINSID_MODE
335
	movff	PLUSW0, swinsid_mode
336
	movlw	SID_Ix_Vx_SWINSID_PHASE
337
	movff	PLUSW0, swinsid_phase
338
#endif
339
 
340
	ENDM
341
 
342
	SET_BSR	SIDL_BASE
343
 
344
	SIDSE_M_UPDATESTAT_MACRO SIDL_V1_BASE, SIDL_BASE + SIDx_V1_FRQ_L, SIDL_BASE + SIDx_SWINSID_V1_MODE, SIDL_BASE + SIDx_SWINSID_V1_PHASE
345
	SIDSE_M_UPDATESTAT_MACRO SIDL_V2_BASE, SIDL_BASE + SIDx_V2_FRQ_L, SIDL_BASE + SIDx_SWINSID_V2_MODE, SIDL_BASE + SIDx_SWINSID_V2_PHASE
346
	SIDSE_M_UPDATESTAT_MACRO SIDL_V3_BASE, SIDL_BASE + SIDx_V3_FRQ_L, SIDL_BASE + SIDx_SWINSID_V3_MODE, SIDL_BASE + SIDx_SWINSID_V3_PHASE
347
 
348
	;; in Mono mode: copy *ALL* SID registers (not only the static ones) over to SIDR
349
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
350
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_UpdateStatRegs_Mono
351
SIDSE_M_UpdateStatRegs_Stereo
352
	;; stereo mode:	most SIDs registers already updated, copy over the static ones
353
	SIDSE_M_UPDATESTAT_MACRO SIDR_V1_BASE, SIDR_BASE + SIDx_V1_FRQ_L, SIDR_BASE + SIDx_SWINSID_V1_MODE, SIDR_BASE + SIDx_SWINSID_V1_PHASE
354
	SIDSE_M_UPDATESTAT_MACRO SIDR_V2_BASE, SIDR_BASE + SIDx_V2_FRQ_L, SIDR_BASE + SIDx_SWINSID_V2_MODE, SIDR_BASE + SIDx_SWINSID_V2_PHASE
355
	SIDSE_M_UPDATESTAT_MACRO SIDR_V3_BASE, SIDR_BASE + SIDx_V3_FRQ_L, SIDR_BASE + SIDx_SWINSID_V3_MODE, SIDR_BASE + SIDx_SWINSID_V3_PHASE
356
	rgoto	SIDSE_M_UpdateStatRegs_End
357
 
358
 
359
SIDSE_M_UpdateStatRegs_Mono
360
	;; mono mode: copy over *all* SID registers of SIDL to SIDR
361
	lfsr	FSR1, SIDL_BASE
362
	lfsr	FSR2, SIDR_BASE
363
#if ENABLE_SWINSID
364
	movlw	0x20
365
#else
366
	movlw	SIDx_MODE_VOL+1
367
#endif
368
	movwf	PRODL		; (loop counter)
369
SIDSE_M_UpdateStatRegs_Mono_Loop
370
	movff	POSTINC1, POSTINC2
371
	decfsz	PRODL, F
372
	rgoto	SIDSE_M_UpdateStatRegs_Mono_Loop
373
 
374
SIDSE_M_UpdateStatRegs_End
375
	SET_BSR	SID_BASE
376
	return
377
 
378
 
379
;; --------------------------------------------------------------------------
380
;; This function handles the notes (gate/pitch/PW)
381
;; IN: pointer to SID_Ix_M_Iy_BASE in FSR0 (patch record)
382
;;     pointer to SIDx_Vx_BASE in FSR1 (voice record)
383
;;     Voice number in SID_SE_ELEMENT_NUM
384
;; --------------------------------------------------------------------------
385
SIDSE_M_Note
386
	call	SIDSE_Gate	; gate handler
387
	skpz			; returns ZERO flag cleared if pitch should not be changed
388
   	call	SIDSE_Pitch	; pitch handler
389
	goto	SIDSE_PW	; pulsewidth handler
390
 
391
 
392
;; --------------------------------------------------------------------------
393
;; This function handles the wavetables
394
;; IN: pointer to SID_Ix_M_Iy_BASE in FSR0 (patch record)
395
;;     pointer to SID_WTx_BASE in FSR2 (wt record)
396
;;     WT number in SID_SE_ELEMENT_NUM
397
;; --------------------------------------------------------------------------
398
SIDSE_M_WT
399
	;; clear temporary WT flags
400
	bcf	SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED
401
 
402
	;; check if WT reset requested
403
	movf	SID_SE_ELEMENT_NUM, W, BANKED
404
	call	MIOS_HLP_GetBitORMask
405
	andwf	SID_SE_TRG_EVNT_U, W, BANKED
406
	bz	SIDSE_M_WT_NoDivReset
407
SIDSE_M_WT_DivReset
408
	;; next clock event will increment div to 0
409
	movlw	SID_WTx_DIV_CTR
410
	setf	PLUSW2
411
	;; next step will increment to start position
412
	movlw	SID_Ix_M_Vx_WT_BEGIN
413
	movf	PLUSW0, W
414
	andlw	0x7f
415
	addlw	-1
416
	movwf	PRODL
417
	movlw	SID_WTx_POS
418
	movff	PRODL, PLUSW2
419
	;; request next step
420
	bsf	SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED
421
SIDSE_M_WT_NoDivReset
422
 
423
	;; check for clock sync event
424
	BRA_IFCLR SID_SE_TRG_EVNT_U, 7, BANKED, SIDSE_M_WT_NoClk
425
SIDSE_M_WT_Clk
426
	;; increment clock divider
427
	;; reset divider if it already has reached the target value
428
	movlw	SID_WTx_DIV_CTR
429
	incf	PLUSW2, W
430
	movwf	PRODL
431
 
432
	;; reset once max value is reached
433
	movlw	SID_Ix_M_Vx_WT_SPEED
434
	movf	PLUSW0, W
435
	andlw	0x3f
436
	cpfsgt	PRODL, ACCESS
437
	rgoto SIDSE_M_WT_Clk_NoOv
438
SIDSE_M_WT_Clk_Ov
439
	clrf	PRODL
440
	;; request next step
441
	bsf	SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED
442
SIDSE_M_WT_Clk_NoOv
443
	;; transfer new divider value into WTx register
444
	movlw	SID_WTx_DIV_CTR
445
	movff	PRODL, PLUSW2
446
SIDSE_M_WT_NoClk
447
 
448
	;; skip if no new step requested
449
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_WT_NEW_STEP_REQ, BANKED, SIDSE_M_WT_End
450
 
451
	;; skip if position is 0xaa (notifies oneshot -> WT stopped)
452
	movlw	SID_WTx_POS
453
	movf	PLUSW2, W
454
	xorlw	0xaa
455
	bz	SIDSE_M_WT_End
456
 
457
SIDSE_M_WT_NextStep
458
	;; increment position counter, reset at end position
459
	movlw	SID_WTx_POS
460
	incf	PLUSW2, W
461
	movwf	PRODL
462
	movlw	SID_Ix_M_Vx_WT_END
463
	movf	PLUSW0, W
464
	andlw	0x7f
465
	cpfsgt	PRODL, ACCESS
466
	rgoto SIDSE_M_WT_NextStep_NoOv
467
SIDSE_M_WT_NextStep_Ov
468
	;; if one-shot mode: set position to 0xaa, WT is stopped now!
469
	movlw	SID_Ix_M_Vx_WT_LOOP
470
	BRA_IFCLR PLUSW0, 7, ACCESS, SIDSE_M_WT_NextStep_Ov_NoOneShot
471
SIDSE_M_WT_NextStep_Ov_OneShot
472
	movlw	0xaa
473
	movwf	PRODL
474
	movlw	SID_WTx_POS
475
	movff	PRODL, PLUSW2
476
	rgoto	SIDSE_M_WT_End
477
 
478
SIDSE_M_WT_NextStep_Ov_NoOneShot
479
	movlw	SID_Ix_M_Vx_WT_LOOP
480
	movf	PLUSW0, W
481
	andlw	0x7f
482
	movwf	PRODL
483
SIDSE_M_WT_NextStep_NoOv
484
	;; transfer back to position counter
485
	movlw	SID_WTx_POS
486
	movff	PRODL, PLUSW2
487
 
488
	;; "play" the step
489
	;; (entry point for SIDSE_M_WT_MOD_...)
490
SIDSE_M_WT_PlayStep
491
	;; get pointer to WT value
492
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_WAVETABLE
493
	movlw	SID_WTx_POS
494
	movf	PLUSW2, W
495
	andlw	0x7f
496
	addwf	FSR1L, F
497
 
498
	;; store value in MIOS_PARAMETER1
499
	movff	INDF1, MIOS_PARAMETER1
500
 
501
	;; store SIDs which should be modified in MIOS_PARAMETER3[1:0], and instrument in MIOS_PARAMETER[6:4]
502
	swapf	SID_SE_ELEMENT_NUM, W, BANKED
503
	andlw	0xf0
504
	iorlw	0x03
505
	movwf	MIOS_PARAMETER3
506
	;; call WT Parameter Handler
507
	movlw	SID_Ix_M_Vx_WT_ASSGN
508
	movf	PLUSW0, W
509
	call	SID_PARIN_SetWT
510
 
511
SIDSE_M_WT_End
512
	return
513
 
514
 
515
;; --------------------------------------------------------------------------
516
;; This function syncs the LFOs/ENVs and Notes
517
;; IN: -
518
;; --------------------------------------------------------------------------
519
SIDSE_M_Sync
520
 
521
SIDSE_M_SYNC_ENV_MACRO	MACRO	evnt_a, evnt_a_flag, evnt_r, evnt_r_flag, env_base
522
	lfsr	FSR1, env_base
523
	CALL_IFSET evnt_r, evnt_r_flag, BANKED, SIDSE_M_ENV_TrgRelease
524
	bcf	evnt_r, evnt_r_flag, BANKED
525
	CALL_IFSET evnt_a, evnt_a_flag, BANKED, SIDSE_M_ENV_Restart
526
	bcf	evnt_a, evnt_a_flag, BANKED
527
	ENDM
528
 
529
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 0, SID_SE_TRG_EVNT_ENVR, 0, SID_ENV1_BASE
530
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 1, SID_SE_TRG_EVNT_ENVR, 1, SID_ENV2_BASE
531
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 2, SID_SE_TRG_EVNT_ENVR, 2, SID_ENV3_BASE
532
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 3, SID_SE_TRG_EVNT_ENVR, 3, SID_ENV4_BASE
533
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 4, SID_SE_TRG_EVNT_ENVR, 4, SID_ENV5_BASE
534
	SIDSE_M_SYNC_ENV_MACRO SID_SE_TRG_EVNT_ENVA, 5, SID_SE_TRG_EVNT_ENVR, 5, SID_ENV6_BASE
535
 
536
 
537
SIDSE_M_SYNC_LFO_MACRO	MACRO	evnt, evnt_flag, voice_base, lfo1_base, lfo2_base
538
	LOCAL	SIDSE_M_SYNC_LFO_Skip
539
	LOCAL	SIDSE_M_SYNC_LFO1_Skip
540
	LOCAL	SIDSE_M_SYNC_LFO2_Skip
541
 
542
	BRA_IFCLR evnt, evnt_flag, BANKED, SIDSE_M_SYNC_LFO_Skip
543
	bcf	evnt, evnt_flag, BANKED
544
 
545
	lfsr	FSR1, voice_base
546
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
547
 
548
	movlw	SID_Ix_M_Vx_LFO1_MODE
549
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_SYNC_M, ACCESS, SIDSE_M_SYNC_LFO1_Skip
550
	addwf	FSR0L, F
551
	movlw	0
552
	addwfc	FSR0H, F
553
	lfsr	FSR1, lfo1_base
554
	call	SIDSE_M_LFO_Restart
555
SIDSE_M_SYNC_LFO1_Skip
556
 
557
	lfsr	FSR1, voice_base
558
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
559
 
560
	movlw	SID_Ix_M_Vx_LFO2_MODE
561
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_SYNC_M, ACCESS, SIDSE_M_SYNC_LFO2_Skip
562
	addwf	FSR0L, F
563
	movlw	0
564
	addwfc	FSR0H, F
565
	lfsr	FSR1, lfo2_base
566
	call	SIDSE_M_LFO_Restart
567
SIDSE_M_SYNC_LFO2_Skip
568
 
569
SIDSE_M_SYNC_LFO_Skip
570
	incf	SID_SE_ELEMENT_NUM, F, BANKED
571
	ENDM
572
 
573
	clrf	SID_SE_ELEMENT_NUM, BANKED
574
SIDSE_M_SYNC_LFO_NotL
575
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L1, SIDL_V1_BASE, SID_LFO1_BASE, SID_LFO2_BASE
576
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L2, SIDL_V2_BASE, SID_LFO3_BASE, SID_LFO4_BASE
577
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L3, SIDL_V3_BASE, SID_LFO5_BASE, SID_LFO6_BASE
578
 
579
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
580
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_SYNC_LFO_NotR
581
SIDSE_M_SYNC_LFO_R
582
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L4, SIDR_V1_BASE, SID_LFO7_BASE, SID_LFO8_BASE
583
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L5, SIDR_V2_BASE, SID_LFO9_BASE, SID_LFO10_BASE
584
	SIDSE_M_SYNC_LFO_MACRO SID_SE_TRG_EVNT_H, SID_TRG_TARGET_H_L6, SIDR_V3_BASE, SID_LFO11_BASE, SID_LFO12_BASE
585
SIDSE_M_SYNC_LFO_NotR
586
 
587
 
588
SIDSE_M_SYNC_NOTE_MACRO	MACRO	evnt, evnt_flag, voice_base
589
	LOCAL	SIDSE_M_SYNC_NOTE_Skip
590
 
591
	BRA_IFCLR evnt, evnt_flag, BANKED, SIDSE_M_SYNC_NOTE_Skip
592
	lfsr	FSR1, voice_base
593
	rcall	SIDSE_M_Hlp_GetAssignedInsPtr
594
	call	SIDSE_M_NOTE_Restart
595
	bcf	evnt, evnt_flag, BANKED
596
SIDSE_M_SYNC_NOTE_Skip
597
	incf	SID_SE_ELEMENT_NUM, F, BANKED
598
	ENDM
599
 
600
	clrf	SID_SE_ELEMENT_NUM, BANKED
601
SIDSE_M_SYNC_Note_L
602
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O1L, SIDL_V1_BASE
603
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O2L, SIDL_V2_BASE
604
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O3L, SIDL_V3_BASE
605
 
606
	movff	SID_LOCAL_ENS + SID_ENSx_CTRL1, WREG
607
	BRA_IFSET WREG, SID_ENS_CTRL1_MONO, ACCESS, SIDSE_M_SYNC_Note_NotR
608
SIDSE_M_SYNC_Note_R
609
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O1R, SIDR_V1_BASE
610
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O2R, SIDR_V2_BASE
611
	SIDSE_M_SYNC_NOTE_MACRO SID_SE_TRG_EVNT_L, SID_TRG_TARGET_L_O3R, SIDR_V3_BASE
612
SIDSE_M_SYNC_Note_NotR
613
 
614
	return
615
 
616
 
617
;; --------------------------------------------------------------------------
618
;; This function handles the LFOs (the SIDSE_M_LFO_Restart function restarts a LFO)
619
;; IN: pointer to SID_Ix_LFOx_BASE in FSR0 (patch record)
620
;;     pointer to SID_LFOx_BASE in FSR1
621
;;     LFO number in SID_SE_ELEMENT_NUM
622
;;     Voice assignment in SID_CURRENT_VOICE_ASSG
623
;; --------------------------------------------------------------------------
624
SIDSE_M_LFO_Restart
625
	;; if oneshot mode: don't take sync mode into account if we already had a overrun condition
626
	movlw	SID_Ix_LFOx_MODE
627
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_M_LFO_Restart_NoOneShot
628
SIDSE_M_LFO_Restart_OneShot
629
	movf	SID_SE_ELEMENT_NUM, W, BANKED
630
	call	MIOS_HLP_GetBitORMask
631
	andwf	SID_SE_LFO_OVERRUN, W, BANKED
632
	bnz	SIDSE_M_LFO_Restart_OneShot_Cont
633
	;; no overrun occured yet - check for sync
634
SIDSE_M_LFO_Restart_NoOneShot
635
 
636
SIDSE_M_LFO_Restart_OneShot_Cont
637
	;; reset counter (take phase into account)
638
	movlw	0x00
639
	movwf	POSTINC1	; SID_LFOx_CTR_L
640
	movlw	SID_Ix_LFOx_PHASE
641
	movff	PLUSW0, POSTDEC1; SID_LFOx_CTR_H
642
 
643
	;; clear overrun flag (for oneshot mode)
644
	movf	SID_SE_ELEMENT_NUM, W, BANKED
645
	call	MIOS_HLP_GetBitANDMask
646
	andwf	SID_SE_LFO_OVERRUN, F, BANKED
647
 
648
	;; check if LFO should be delayed - set delay counter to 0x0001 in this case, else to 0x0000
649
	movlw	SID_LFOx_DELAY_CTR_H	; high byte always reset to 0
650
	clrf	PLUSW1
651
 
652
	movlw	SID_Ix_LFOx_DELAY
653
	clrf	PRODL			; low byte set to 1 if delay != 0
654
	movf	PLUSW0, W
655
	skpz
656
	incf	PRODL, F
657
	movlw	SID_LFOx_DELAY_CTR_L
658
	movff	PRODL, PLUSW1
659
 
660
	;; continue at waveform calculation
661
	rgoto	SIDSE_M_LFO_Restart_Cont
662
 
663
;; --------------------------------------------------------------------------
664
SIDSE_M_LFO			; normal LFO entry
665
	;; skip if LFO not enabled
666
	movlw	SID_Ix_LFOx_MODE
667
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ENABLE, ACCESS, SIDSE_M_LFO_End
668
 
669
	;; temporary shift FSR1 to SID_LFOx_DELAY_CTR_L for easier handling
670
	movlw	SID_LFOx_DELAY_CTR_L
671
	addwf	FSR1L, F
672
 
673
	;; delay LFO so long 16bit delay counter != 0
674
	movf	POSTINC1, W
675
	iorwf	POSTDEC1, W
676
	bz	SIDSE_M_LFO_NoDelay
677
SIDSE_M_LFO_Delay
678
	;; increment counter, set it to zero on overrun (no delay anymore)
679
	movlw	SID_Ix_LFOx_DELAY
680
	movff	PLUSW0, IRQ_TMP3; incrementer is the same like used for envelopes
681
	movlw	0x80		; curve *must* be disabled!
682
	call	SIDSE_Hlp_ENV_GetBendedValue	; incrementer in MIOS_PARAMETER[12]
683
	movf	MIOS_PARAMETER1, W
684
	addwf	POSTINC1, F
685
	movf	MIOS_PARAMETER2, W
686
	addwfc	POSTDEC1, F
687
	bc	SIDSE_M_LFO_DelayOv
688
	rgoto	SIDSE_M_LFO_End
689
SIDSE_M_LFO_DelayOv
690
	;; overrun: clear counter to disable delay
691
	clrf	POSTINC1
692
	clrf	POSTDEC1
693
SIDSE_M_LFO_NoDelay
694
	movlw	-SID_LFOx_DELAY_CTR_L	; switch back to SID_LFOx_CTR_L
695
	addwf	FSR1L, F
696
 
697
	;; implementation: a LFO is just a 16bit ramp which is mapped to a waveform
698
 
699
	;; clear LFO overrun flag
700
	bcf	SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED
701
 
702
	;; in oneshot mode: check if overrun already occured
703
	movlw	SID_Ix_LFOx_MODE
704
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_M_LFO_NoOneShotChk
705
SIDSE_M_LFO_OneShotChk
706
	movf	SID_SE_ELEMENT_NUM, W, BANKED
707
	call	MIOS_HLP_GetBitORMask
708
	andwf	SID_SE_LFO_OVERRUN, W, BANKED
709
	bz	SIDSE_M_LFO_NoOneShotChk
710
	;; set counter to maximum value and continue at waveform calculation
711
	setf	POSTINC1
712
	setf	POSTDEC1
713
	rgoto	SIDSE_M_LFO_OneShot_Cont
714
SIDSE_M_LFO_NoOneShotChk
715
 
716
	;; if clock sync enabled: only increment on clock events
717
	movlw	SID_Ix_LFOx_MODE
718
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_CLKSYNC, ACCESS, SIDSE_M_LFO_NoClkSync
719
SIDSE_M_LFO_ClkSync
720
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_M_LFO_NoClk_Cont
721
SIDSE_M_LFO_NoClkSync
722
 
723
	;; increment 16bit counter by given rate
724
	movlw	SID_Ix_LFOx_RATE
725
	movff	PLUSW0, IRQ_TMP1
726
 
727
	;; if LFO synched via clock, replace 245-255 by MIDI clock optimized incrementers
728
	movlw	SID_Ix_LFOx_MODE
729
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_CLKSYNC, ACCESS, SIDSE_M_LFO_Rate_NoClkSync
730
SIDSE_M_LFO_Rate_ClkSync
731
	movf	IRQ_TMP1, W
732
	addlw	-245
733
	bnc	SIDSE_M_LFO_Rate_NoClkSyncValues
734
	TABLE_ADDR_MUL_W SID_LFO_TABLE_MCLK, 2
735
	rgoto	SIDSE_M_LFO_Rate_ClkSync_Cont
736
SIDSE_M_LFO_Rate_NoClkSyncValues
737
SIDSE_M_LFO_Rate_NoClkSync
738
 
739
	movf	IRQ_TMP1, W
740
	TABLE_ADDR_MUL_W SID_LFO_TABLE, 2
741
SIDSE_M_LFO_Rate_ClkSync_Cont
742
	tblrd*+
743
	movf	TABLAT, W
744
	addwf	POSTINC1, F	; SID_LFOx_CTR_L
745
	tblrd*+
746
	movf	TABLAT, W
747
	addwfc	POSTDEC1, F	; SID_LFOx_CTR_H
748
	bnc	SIDSE_M_LFO_NoOverrun
749
 
750
SIDSE_M_LFO_Overrun
751
	;; required for S&H function below, will be cleared with each run
752
	bsf	SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED
753
 
754
	;; required for one-shot mode, will be cleared with next gate trigger
755
	movf	SID_SE_ELEMENT_NUM, W, BANKED
756
	call	MIOS_HLP_GetBitORMask
757
	iorwf	SID_SE_LFO_OVERRUN, F, BANKED
758
 
759
	;; in oneshot mode: ensure that counter is set to maximum value
760
	movlw	SID_Ix_LFOx_MODE
761
	BRA_IFCLR PLUSW0, SID_I_LFO_MODE_ONESHOT, ACCESS, SIDSE_M_LFO_OverrunNoOneShot
762
SIDSE_M_LFO_OverrunOneShot
763
	setf	POSTINC1
764
	setf	POSTDEC1
765
SIDSE_M_LFO_OverrunNoOneShot
766
SIDSE_M_LFO_NoOverrun
767
 
768
SIDSE_M_LFO_OneShot_Cont		; entry point for oneshot function (if overrun already occured)
769
SIDSE_M_LFO_NoClk_Cont		; entry point for clock sync function (no clock event)
770
SIDSE_M_LFO_Restart_Cont		; entry point for restart function
771
 
772
	;; temporary store SID_LFOx_CTR_[LH] in IRQ_TMP[12]
773
	movff	POSTINC1, IRQ_TMP1
774
	movff	POSTDEC1, IRQ_TMP2
775
 
776
	;; map to waveform
777
	;; result in MUL_A_[LH]
778
	movlw	SID_Ix_LFOx_MODE ; waveform selection in bit [6:4]
779
	swapf	PLUSW0, W
780
	BRA_IFSET WREG, 3, ACCESS, SIDSE_M_LFO_Wav89ABCDEF
781
SIDSE_M_LFO_Wav01234567
782
	BRA_IFSET WREG, 2, ACCESS, SIDSE_M_LFO_Wav4567
783
SIDSE_M_LFO_Wav0123
784
	BRA_IFSET WREG, 1, ACCESS, SIDSE_M_LFO_Wav23
785
SIDSE_M_LFO_Wav01
786
	BRA_IFSET WREG, 0, ACCESS, SIDSE_M_LFO_Wav1
787
 
788
	;; ------------------------------------------------------------------
789
SIDSE_M_LFO_Wav0	; Sine
790
	;; sine table contains a quarter of a sine,
791
	;; we have to negate/mirror it depending on the mapped counter value
792
	rlf	IRQ_TMP1, W
793
	rlf	IRQ_TMP2, W
794
	btfsc	IRQ_TMP2, 6
795
	xorlw 0x7f
796
	andlw	0x7f
797
	TABLE_ADDR_MUL_W SID_SIN_TABLE, 2
798
	tblrd*+
799
	movff	TABLAT, MUL_A_L
800
	tblrd*+
801
	movff	TABLAT, MUL_A_H
802
 
803
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_M_LFO_Wav0_NoNeg
804
SIDSE_M_LFO_Wav0_Neg
805
	comf	MUL_A_L, F, BANKED
806
	comf	MUL_A_H, F, BANKED
807
	incf	MUL_A_L, F, BANKED
808
	skpnz
809
	incf	MUL_A_H, F, BANKED
810
SIDSE_M_LFO_Wav0_NoNeg
811
 
812
	rgoto	SIDSE_M_LFO_Wav_Cont
813
 
814
	;; ------------------------------------------------------------------
815
SIDSE_M_LFO_Wav1	; Triangle
816
	;; similar to sine, but linear waveform
817
	clrc
818
	rlf	IRQ_TMP1, W
819
	movwf	MUL_A_L, BANKED
820
	rlf	IRQ_TMP2, W
821
	andlw	0x7f
822
	movwf	MUL_A_H, BANKED
823
 
824
	BRA_IFCLR IRQ_TMP2, 6, ACCESS, SIDSE_M_LFO_Wav1_NoNeg1
825
SIDSE_M_LFO_Wav1_Neg1
826
	comf	MUL_A_L, BANKED
827
	comf	MUL_A_H, BANKED
828
	incf	MUL_A_L, F, BANKED
829
	skpnz
830
	incf	MUL_A_H, F, BANKED
831
	bcf	MUL_A_H, 7, BANKED
832
SIDSE_M_LFO_Wav1_NoNeg1
833
 
834
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_M_LFO_Wav1_NoNeg2
835
SIDSE_M_LFO_Wav1_Neg2
836
	comf	MUL_A_L, F, BANKED
837
	comf	MUL_A_H, F, BANKED
838
	incf	MUL_A_L, F, BANKED
839
	skpnz
840
	incf	MUL_A_H, F, BANKED
841
SIDSE_M_LFO_Wav1_NoNeg2
842
 
843
	rgoto	SIDSE_M_LFO_Wav_Cont
844
 
845
SIDSE_M_LFO_Wav23
846
	BRA_IFSET WREG, 0, ACCESS, SIDSE_M_LFO_Wav3
847
	;; ------------------------------------------------------------------
848
SIDSE_M_LFO_Wav2	; Saw
849
	;; this one is simple - it's "counter-0x8000"
850
	movlw	0x00
851
	subwf	IRQ_TMP1, W
852
	movwf	MUL_A_L, BANKED
853
	movlw	0x80
854
	subwfb	IRQ_TMP2, W
855
	movwf	MUL_A_H, BANKED
856
 
857
	rgoto	SIDSE_M_LFO_Wav_Cont
858
 
859
	;; ------------------------------------------------------------------
860
SIDSE_M_LFO_Wav3	; Pulse
861
	;; this one is even more simple
862
	movlw	0x00
863
	btfsc	IRQ_TMP2, 7
864
	movlw 0xff
865
	movwf	MUL_A_L, BANKED
866
	movlw	0x80
867
	btfsc	IRQ_TMP2, 7
868
	movlw 0x7f
869
	movwf	MUL_A_H, BANKED
870
 
871
	rgoto	SIDSE_M_LFO_Wav_Cont
872
 
873
SIDSE_M_LFO_Wav4567
874
	BRA_IFSET WREG, 1, ACCESS, SIDSE_M_LFO_Wav67
875
SIDSE_M_LFO_Wav45
876
	BRA_IFSET WREG, 0, ACCESS, SIDSE_M_LFO_Wav5
877
 
878
	;; ------------------------------------------------------------------
879
SIDSE_M_LFO_Wav4	; Random
880
	;; only on LFO overrun:
881
	BRA_IFCLR SID_SE_STATE, SID_SE_STATE_LFO_OVERRUN, BANKED, SIDSE_M_LFO_End
882
 
883
	;; generate new random number and copy it to MUL_A_[LH]
884
	call	SID_RND_GenRandomNumber
885
	movff	SID_RANDOM_SEED_L, MUL_A_L
886
	movff	SID_RANDOM_SEED_L, MUL_A_H
887
 
888
	rgoto	SIDSE_M_LFO_Wav_Cont
889
 
890
	;; ------------------------------------------------------------------
891
SIDSE_M_LFO_Wav5	; positive sine
892
	;; sine table contains a quarter of a sine,
893
	;; we have to negate/mirror it depending on the mapped counter value
894
	movf	IRQ_TMP2, W
895
	btfsc	IRQ_TMP2, 7
896
	xorlw 0x7f
897
	andlw	0x7f
898
	TABLE_ADDR_MUL_W SID_SIN_TABLE, 2
899
	tblrd*+
900
	movff	TABLAT, MUL_A_L
901
	tblrd*+
902
	movff	TABLAT, MUL_A_H
903
 
904
	rgoto	SIDSE_M_LFO_Wav_Cont
905
 
906
 
907
SIDSE_M_LFO_Wav67
908
	BRA_IFSET WREG, 0, ACCESS, SIDSE_M_LFO_Wav7
909
 
910
	;; ------------------------------------------------------------------
911
SIDSE_M_LFO_Wav6	; positive triangle
912
	movff	IRQ_TMP1, MUL_A_L
913
	movff	IRQ_TMP2, MUL_A_H
914
 
915
	BRA_IFCLR IRQ_TMP2, 7, ACCESS, SIDSE_M_LFO_Wav6_NoNeg
916
SIDSE_M_LFO_Wav6_Neg
917
	comf	MUL_A_L, BANKED
918
	comf	MUL_A_H, BANKED
919
	incf	MUL_A_L, F, BANKED
920
	skpnz
921
	incf	MUL_A_H, F, BANKED
922
	bcf	MUL_A_H, 7, BANKED
923
SIDSE_M_LFO_Wav6_NoNeg
924
 
925
	rgoto	SIDSE_M_LFO_Wav_Cont
926
 
927
	;; ------------------------------------------------------------------
928
SIDSE_M_LFO_Wav7	; positive saw
929
	clrc
930
	rrf	IRQ_TMP2, W
931
	movwf	MUL_A_H, BANKED
932
	rrf	IRQ_TMP1, W
933
	movwf	MUL_A_L, BANKED
934
 
935
	rgoto	SIDSE_M_LFO_Wav_Cont
936
 
937
	;; ------------------------------------------------------------------
938
SIDSE_M_LFO_Wav89ABCDEF	; positive pulse
939
	movlw	0x00
940
	btfsc	IRQ_TMP2, 7
941
	movlw 0xff
942
	movwf	MUL_A_L, BANKED
943
	movlw	0x00
944
	btfsc	IRQ_TMP2, 7
945
	movlw 0x7f
946
	movwf	MUL_A_H, BANKED
947
 
948
	rgoto	SIDSE_M_LFO_Wav_Cont
949
SIDSE_M_LFO_Wav_Cont
950
 
951
 
952
	;; result in MUL_A_[LH]
953
	;; range: +/- 0x7fff
954
 
955
SIDSE_M_LFO_MOD_Pitch
956
	;; scale MOD source by depth
957
	movlw	SID_Ix_M_Vx_LFO1_DEPTH_P-SID_Ix_M_Vx_LFO1_MODE
958
	movf	PLUSW0, W
959
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
960
	bz	SIDSE_M_LFO_MOD_Pitch_End
961
	xorlw	0x80
962
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
963
 
964
	;; pointer to SID_MOD_TARG_PITCHx_L -> FSR2
965
	lfsr	FSR2, SID_MOD_TARG_PITCH1_L
966
	clrc
967
	rrf	SID_SE_ELEMENT_NUM, W, BANKED
968
	mullw	3
969
	movf	PRODL, W
970
	addwf	FSR2L, F
971
 
972
	;; reduce intensity of pitch modulation
973
	clrc
974
	btfsc	MUL_R_3, 7
975
	setc
976
	rrf	MUL_R_3, F
977
	rrf	MUL_R_2, F
978
	rrf	MUL_R_1, F
979
 
980
	clrc
981
	btfsc	MUL_R_3, 7
982
	setc
983
	rrf	MUL_R_3, F
984
	rrf	MUL_R_2, F
985
	rrf	MUL_R_1, F
986
 
987
	movf	MUL_R_1, W, BANKED
988
	addwf	POSTINC2, F
989
	movf	MUL_R_2, W, BANKED
990
	addwfc	POSTINC2, F
991
	movf	MUL_R_3, W, BANKED
992
	addwfc	POSTINC2, F
993
SIDSE_M_LFO_MOD_Pitch_End
994
 
995
 
996
SIDSE_M_LFO_MOD_PW
997
	;; scale MOD source by depth
998
	movlw	SID_Ix_M_Vx_LFO1_DEPTH_PW-SID_Ix_M_Vx_LFO1_MODE
999
	movf	PLUSW0, W
1000
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
1001
	bz	SIDSE_M_LFO_MOD_PW_End
1002
	xorlw	0x80
1003
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1004
 
1005
	;; pointer to SID_MOD_TARG_PWx_L -> FSR2
1006
	lfsr	FSR2, SID_MOD_TARG_PW1_L
1007
	clrc
1008
	rrf	SID_SE_ELEMENT_NUM, W, BANKED
1009
	mullw	3
1010
	movf	PRODL, W
1011
	addwf	FSR2L, F
1012
 
1013
	movf	MUL_R_1, W, BANKED
1014
	addwf	POSTINC2, F
1015
	movf	MUL_R_2, W, BANKED
1016
	addwfc	POSTINC2, F
1017
	movf	MUL_R_3, W, BANKED
1018
	addwfc	POSTINC2, F
1019
SIDSE_M_LFO_MOD_PW_End
1020
 
1021
 
1022
SIDSE_M_LFO_MOD_FIL
1023
	;; scale MOD source by depth
1024
	movlw	SID_Ix_M_Vx_LFO1_DEPTH_F-SID_Ix_M_Vx_LFO1_MODE
1025
	movf	PLUSW0, W
1026
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
1027
	bz	SIDSE_M_LFO_MOD_FIL_End
1028
#if 0
1029
	xorlw	0x80
1030
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1031
 
1032
	;; branch depending on voice
1033
	movlw	2*3
1034
	cpfslt	SID_SE_ELEMENT_NUM, BANKED
1035
	rgoto SIDSE_M_LFO_MOD_FIL_R
1036
SIDSE_M_LFO_MOD_FIL_L
1037
	rcall	SIDSE_M_LFO_MOD_FIL_TrgL_Sub
1038
	rgoto	SIDSE_M_LFO_MOD_FIL_End
1039
 
1040
SIDSE_M_LFO_MOD_FIL_R
1041
	rcall	SIDSE_M_LFO_MOD_FIL_TrgR_Sub
1042
	;; 	rgoto	SIDSE_M_LFO_MOD_FIL_End
1043
#else
1044
 
1045
	;; TK: intention is to ensure, that only the LFO of the last assigned voice
1046
	;; modulates the filter for more logical results (the results were not obvious
1047
	;; when all 6 LFOs modulated the filters...)
1048
 
1049
	;; get assigned MIDI voice
1050
	lfsr	FSR2, SIDL_V1_BASE
1051
	rrf	SID_SE_ELEMENT_NUM, W, BANKED
1052
	andlw	0x7f
1053
	movwf	TABLAT		; (temporary store voice number in TABLAT)
1054
	mullw	SID_Vx_RECORD_LEN
1055
	movf	PRODL, W
1056
	addlw	SID_Vx_ASSIGNED_MV
1057
	addwf	FSR2L, F
1058
	movf	INDF2, W
1059
 
1060
	;; get last voice of MIDI instrument
1061
	lfsr	FSR2, SID_MV1_BASE
1062
	mullw	SID_MVx_RECORD_LEN
1063
	movf	PRODL, W
1064
	addlw	SID_MVx_LAST_VOICE
1065
	addwf	FSR2L, F
1066
	movf	INDF2, W
1067
 
1068
	;; don't modulate if current LFO not part of last voice
1069
	cpfseq	TABLAT, ACCESS
1070
	rgoto SIDSE_M_LFO_MOD_FIL_End
1071
 
1072
	;; scale depth
1073
	movlw	SID_Ix_M_Vx_LFO1_DEPTH_F-SID_Ix_M_Vx_LFO1_MODE
1074
	movf	PLUSW0, W
1075
	call	SIDSE_Hlp_ScaleDepth	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1076
 
1077
	;; add to modulation target depending on instrument specific voice assignment
1078
	movf	SID_CURRENT_VOICE_ASSG, W, BANKED
1079
	andlw	0x0f
1080
	bz	SIDSE_M_LFO_MOD_FIL_TrgLR  ; LR
1081
	addlw	-1
1082
	bz	SIDSE_M_LFO_MOD_FIL_TrgL   ; L only
1083
	addlw	-1
1084
	bz	SIDSE_M_LFO_MOD_FIL_TrgR   ; R only
1085
	addlw	-1
1086
	bz	SIDSE_M_LFO_MOD_FIL_TrgL   ; O1
1087
	addlw	-1
1088
	bz	SIDSE_M_LFO_MOD_FIL_TrgL   ; O2
1089
	addlw	-1
1090
	bz	SIDSE_M_LFO_MOD_FIL_TrgL   ; O3
1091
	rgoto	SIDSE_M_LFO_MOD_FIL_TrgR   ; O4..O6
1092
 
1093
SIDSE_M_LFO_MOD_FIL_TrgLR
1094
	rcall	SIDSE_M_LFO_MOD_FIL_TrgL_Sub
1095
	rcall	SIDSE_M_LFO_MOD_FIL_TrgR_Sub
1096
	rgoto	SIDSE_M_LFO_MOD_FIL_End
1097
 
1098
SIDSE_M_LFO_MOD_FIL_TrgL
1099
	rcall	SIDSE_M_LFO_MOD_FIL_TrgL_Sub
1100
	rgoto	SIDSE_M_LFO_MOD_FIL_End
1101
 
1102
SIDSE_M_LFO_MOD_FIL_TrgR
1103
	rcall	SIDSE_M_LFO_MOD_FIL_TrgR_Sub
1104
	;; 	rgoto	SIDSE_M_LFO_MOD_FIL_End
1105
#endif
1106
SIDSE_M_LFO_MOD_FIL_End
1107
 
1108
SIDSE_M_LFO_End
1109
	return
1110
 
1111
;; subroutine for adding modulation result to FIL1_L target
1112
SIDSE_M_LFO_MOD_FIL_TrgL_Sub
1113
	;; transfer to FIL1
1114
	lfsr	FSR2, SID_MOD_TARG_FIL1_L
1115
	movf	MUL_R_1, W, BANKED
1116
	addwf	POSTINC2, F
1117
	movf	MUL_R_2, W, BANKED
1118
	addwfc	POSTINC2, F
1119
	movf	MUL_R_3, W, BANKED
1120
	addwfc	POSTINC2, F
1121
	return
1122
	rgoto	SIDSE_M_LFO_MOD_FIL_End
1123
 
1124
;; subroutine for adding modulation result to FIL1_R target
1125
SIDSE_M_LFO_MOD_FIL_TrgR_Sub
1126
	;; transfer to FIL2
1127
	lfsr	FSR2, SID_MOD_TARG_FIL2_L
1128
	movf	MUL_R_1, W, BANKED
1129
	addwf	POSTINC2, F
1130
	movf	MUL_R_2, W, BANKED
1131
	addwfc	POSTINC2, F
1132
	movf	MUL_R_3, W, BANKED
1133
	addwfc	POSTINC2, F
1134
	return
1135
 
1136
 
1137
;; --------------------------------------------------------------------------
1138
;; This function handles the Envelopes
1139
;; IN: pointer to SID_Ix_M_ENVx_BASE in FSR0 (patch record)
1140
;;     pointer to SID_ENVx_BASE in FSR1
1141
;;     ENV number in SID_SE_ELEMENT_NUM
1142
;;     SID_SE_STATE.SID_SE_STATE_ACCENT flag increases depth (only used by bassline)
1143
;; --------------------------------------------------------------------------
1144
SIDSE_M_ENV
1145
	;; if clock sync enabled: only increment on clock events
1146
	movlw	SID_Ix_M_Vx_ENV_MODE
1147
	BRA_IFCLR PLUSW0, SID_I_ENV_MODE_CLKSYNC, ACCESS, SIDSE_M_ENV_NoClkSync
1148
SIDSE_M_ENV_ClkSync
1149
	BRA_IFSET SID_SE_STATE, SID_SE_STATE_GLOBAL_CLK_EVENT, BANKED, SIDSE_M_ENV_ClkSync_Cont
1150
	;; transfer current ENV counter into MIOS_PARAMETER[12]
1151
	movff	POSTINC1, MIOS_PARAMETER1
1152
	movff	POSTDEC1, MIOS_PARAMETER2
1153
	rgoto	SIDSE_M_ENV_Cont
1154
SIDSE_M_ENV_NoClkSync
1155
SIDSE_M_ENV_ClkSync_Cont
1156
 
1157
	;; branch depending on EG state
1158
	movlw	SID_ENVx_STATE
1159
	BRA_IFSET PLUSW1, SID_ENV_STATE_RELEASE2, ACCESS, SIDSE_M_ENV_End
1160
	BRA_IFSET PLUSW1, SID_ENV_STATE_RELEASE1, ACCESS, SIDSE_M_ENV_Release
1161
	BRA_IFCLR PLUSW1, SID_ENV_STATE_ATTACK1, ACCESS, SIDSE_M_ENV_End
1162
	BRA_IFSET PLUSW1, SID_ENV_STATE_SUSTAIN, ACCESS, SIDSE_M_ENV_Sustain
1163
	BRA_IFSET PLUSW1, SID_ENV_STATE_DECAY2, ACCESS, SIDSE_M_ENV_Decay
1164
 
1165
SIDSE_M_ENV_Attack
1166
 
1167
	;; in attack phase we have to increase the EG counter
1168
	;; attack rate in IRQ_TMP3
1169
	movlw	SID_Ix_M_Vx_ENV_ATTACK
1170
	movf	PLUSW0, W
1171
	movwf	IRQ_TMP3
1172
	;; get final rate depending on curve setting
1173
	movlw	SID_Ix_M_Vx_ENV_CURVE
1174
	movf	PLUSW0, W
1175
	call	SIDSE_Hlp_ENV_GetBendedValue
1176
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1177
	;; final attack level is 0xff
1178
	movlw	0xff
1179
	movwf	IRQ_TMP1
1180
	;; increment counter
1181
	call	SIDSE_Hlp_ENV_IncrCtr
1182
	;; we've reached the level once the zero bit set
1183
	bnz	SIDSE_M_ENV_Cont
1184
 
1185
	;; switch to next phase
1186
	movlw	SID_ENVx_STATE
1187
	bsf	PLUSW1, SID_ENV_STATE_DECAY2
1188
	rgoto	SIDSE_M_ENV_Cont
1189
 
1190
SIDSE_M_ENV_Decay
1191
	;; in decay phase we have to increase/decrease the EG counter depending on the current level
1192
	;; decay rate in WREG
1193
	;; if accent flag set, use alternative ENC_DECAY_A parameter (bassline only)
1194
	movlw	SID_Ix_M_Vx_ENV_DECAY
1195
	btfsc	SID_SE_STATE, SID_SE_STATE_ACCENT, BANKED
1196
	movlw SID_Ix_B_Vx_ENV_DECAY_A
1197
	movff	PLUSW0, IRQ_TMP3
1198
 
1199
	;; get final rate depending on curve setting
1200
	movlw	SID_Ix_M_Vx_ENV_CURVE
1201
	movf	PLUSW0, W
1202
	call	SIDSE_Hlp_ENV_GetBendedValue
1203
	;; result: low byte in MIOS_PARAMETER1, high byte in MIOS_PARAMETER2
1204
	;; store final sustain in IRQ_TMP1
1205
	movlw	SID_Ix_M_Vx_ENV_SUSTAIN
1206
	movff	PLUSW0, IRQ_TMP1
1207
	;; incr/decr counter
1208
	call	SIDSE_Hlp_ENV_IncrDecrCtr
1209
	;; we've reached the level once the zero bit set
1210
	bnz	SIDSE_M_ENV_Cont
1211
 
1212
	;; switch to next phase
1213
	movlw	SID_ENVx_STATE
1214
	bsf	PLUSW1, SID_ENV_STATE_SUSTAIN
1215
 
1216
 
1217
SIDSE_M_ENV_Sustain
1218
	;; write sustain value into counter (again)
1219
	movlw	SID_Ix_M_Vx_ENV_SUSTAIN
1220
	movff	PLUSW0, MIOS_PARAMETER2
1221
	clrf	MIOS_PARAMETER1
1222
 
1223
	rgoto	SIDSE_M_ENV_Cont
1224
 
1225
 
1226
SIDSE_M_ENV_Release
1227
	;; in the release phase we have to decrease the EG counter until it reaches 0
1228
	;; release rate in WREG
1229
	movlw	SID_Ix_M_Vx_ENV_RELEASE
1230
	movff	PLUSW0, IRQ_TMP3
1231
	;; get release rate depending on curve setting
1232
	movlw	SID_Ix_M_Vx_ENV_CURVE
1233
	movf	PLUSW0, W
1234
	call	SIDSE_Hlp_ENV_GetBendedValue
1235
	;; target level: 0
1236
	clrf	IRQ_TMP1
1237
	;; decr counter
1238
	call	SIDSE_Hlp_ENV_DecrCtr
1239
 
1240
	;; we've reached the level once the zero bit set
1241
	bnz	SIDSE_M_ENV_Cont
1242
 
1243
	;; switch to final phase
1244
	movlw	SID_ENVx_STATE
1245
	bsf	PLUSW1, SID_ENV_STATE_RELEASE2
1246
 
1247
	;; 	rgoto	SIDSE_M_ENV_Cont
1248
 
1249
SIDSE_M_ENV_Cont
1250
	;; copy MIOS_PARAMETER[12] to SID_ENVx_CTR_[LH]
1251
	movff	MIOS_PARAMETER1, POSTINC1
1252
	movff	MIOS_PARAMETER2, POSTDEC1
1253
 
1254
	;; skip ENV mapping if result is zero
1255
	movf	MIOS_PARAMETER1, W
1256
	iorwf	MIOS_PARAMETER2, W
1257
	bz	SIDSE_M_ENV_Cont_Zero
1258
 
1259
	;; transfer ENV value to MUL_A_[LH], range: +/- 0x7fff
1260
	clrc
1261
	rrf	MIOS_PARAMETER2, W
1262
	movwf	MUL_A_H, BANKED
1263
	rrf	MIOS_PARAMETER1, W
1264
	movwf	MUL_A_L, BANKED
1265
 
1266
 
1267
SIDSE_M_ENV_MOD_Pitch
1268
	;; scale MOD source by depth
1269
	movlw	SID_Ix_M_Vx_ENV_DEPTH_P
1270
	movf	PLUSW0, W
1271
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
1272
	bz	SIDSE_M_ENV_MOD_Pitch_End
1273
	xorlw	0x80
1274
	call	SIDSE_Hlp_ScaleDepthAcc	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1275
 
1276
	;; pointer to SID_MOD_TARG_PITCHx_L -> FSR2
1277
	lfsr	FSR2, SID_MOD_TARG_PITCH1_L
1278
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1279
	mullw	3
1280
	movf	PRODL, W
1281
	addwf	FSR2L, F
1282
 
1283
	movf	MUL_R_1, W, BANKED
1284
	addwf	POSTINC2, F
1285
	movf	MUL_R_2, W, BANKED
1286
	addwfc	POSTINC2, F
1287
	movf	MUL_R_3, W, BANKED
1288
	addwfc	POSTINC2, F
1289
SIDSE_M_ENV_MOD_Pitch_End
1290
 
1291
 
1292
SIDSE_M_ENV_MOD_PW
1293
	;; scale MOD source by depth
1294
	movlw	SID_Ix_M_Vx_ENV_DEPTH_PW
1295
	movf	PLUSW0, W
1296
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
1297
	bz	SIDSE_M_ENV_MOD_PW_End
1298
	xorlw	0x80
1299
	call	SIDSE_Hlp_ScaleDepthAcc	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1300
 
1301
	;; pointer to SID_MOD_TARG_PWx_L -> FSR2
1302
	lfsr	FSR2, SID_MOD_TARG_PW1_L
1303
	movf	SID_SE_ELEMENT_NUM, W, BANKED
1304
	mullw	3
1305
	movf	PRODL, W
1306
	addwf	FSR2L, F
1307
 
1308
	movf	MUL_R_1, W, BANKED
1309
	addwf	POSTINC2, F
1310
	movf	MUL_R_2, W, BANKED
1311
	addwfc	POSTINC2, F
1312
	movf	MUL_R_3, W, BANKED
1313
	addwfc	POSTINC2, F
1314
SIDSE_M_ENV_MOD_PW_End
1315
 
1316
 
1317
SIDSE_M_ENV_MOD_FIL
1318
	;; scale MOD source by depth
1319
	movlw	SID_Ix_M_Vx_ENV_DEPTH_F
1320
	movf	PLUSW0, W
1321
	xorlw	0x80		; skip if depth is 0x80 (-> 0)
1322
	bz	SIDSE_M_ENV_MOD_FIL_End
1323
	xorlw	0x80
1324
	call	SIDSE_Hlp_ScaleDepthAcc	; 15bit signed value in MUL_A_[LH], result in MUL_R_[123], uses IRQ_TMP1
1325
 
1326
	;; branch depending on voice
1327
	movlw	3
1328
	cpfslt	SID_SE_ELEMENT_NUM, BANKED
1329
	rgoto SIDSE_M_ENV_MOD_FIL_R
1330
SIDSE_M_ENV_MOD_FIL_L
1331
	;; transfer to FIL1
1332
	lfsr	FSR2, SID_MOD_TARG_FIL1_L
1333
	movf	MUL_R_1, W, BANKED
1334
	addwf	POSTINC2, F
1335
	movf	MUL_R_2, W, BANKED
1336
	addwfc	POSTINC2, F
1337
	movf	MUL_R_3, W, BANKED
1338
	addwfc	POSTINC2, F
1339
	rgoto	SIDSE_M_ENV_MOD_FIL_End
1340
 
1341
SIDSE_M_ENV_MOD_FIL_R
1342
	;; transfer to FIL2
1343
	lfsr	FSR2, SID_MOD_TARG_FIL2_L
1344
	movf	MUL_R_1, W, BANKED
1345
	addwf	POSTINC2, F
1346
	movf	MUL_R_2, W, BANKED
1347
	addwfc	POSTINC2, F
1348
	movf	MUL_R_3, W, BANKED
1349
	addwfc	POSTINC2, F
1350
	;; 	rgoto	SIDSE_M_ENV_MOD_FIL_End
1351
SIDSE_M_ENV_MOD_FIL_End
1352
 
1353
 
1354
SIDSE_M_ENV_Cont_Zero
1355
SIDSE_M_ENV_End
1356
	return
1357
 
1358
 
1359
;; --------------------------------------------------------------------------
1360
;;  FUNCTION: SIDSE_M_ENV_Restart
1361
;;  DESCRIPTION: help function which restarts a single ENV
1362
;;  IN: SID_ENV[123456]_BASE in FSR1
1363
;; --------------------------------------------------------------------------
1364
SIDSE_M_ENV_Restart
1365
	movlw	(1 << SID_ENV_STATE_ATTACK1)	; start at attack phase
1366
	movwf	PRODL
1367
	movlw	SID_ENVx_STATE
1368
	movff	PRODL, PLUSW1
1369
 
1370
	;; no delay supported for multi engine - always clear delay counter
1371
	movlw	SID_ENVx_DELAY_CTR_H	; high byte always reset to 0
1372
	clrf	PLUSW1
1373
	movlw	SID_ENVx_DELAY_CTR_L	; low byte always reset to 0
1374
	clrf	PLUSW1
1375
	return
1376
 
1377
;; --------------------------------------------------------------------------
1378
;;  FUNCTION: SIDSE_M_ENV_TrgRelease
1379
;;  DESCRIPTION: help function which starts release phase of a single ENV
1380
;;  IN: SID_ENV[123456]_BASE in FSR1
1381
;; --------------------------------------------------------------------------
1382
SIDSE_M_ENV_TrgRelease
1383
	movlw	SID_ENVx_STATE
1384
	bsf	PLUSW1, SID_ENV_STATE_RELEASE1
1385
	return
1386
 
1387
;; --------------------------------------------------------------------------
1388
;;  FUNCTION: SIDSE_M_Note_Restart
1389
;;  DESCRIPTION: help function which restarts the delay counter for voices
1390
;;               and requests an active gate
1391
;;  IN: patch base in FSR0, voice base in FSR1, osc number in SID_SE_ELEMENT_NUM
1392
;; --------------------------------------------------------------------------
1393
SIDSE_M_NOTE_Restart
1394
	;; request gate if voice is active (and request clear for proper ADSR handling)
1395
	;; set gate only if voice is active!
1396
	movlw	SID_Vx_STATE
1397
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
1398
	btfsc	PLUSW1, SID_V_STATE_VOICE_ACTIVE
1399
	bsf	PLUSW1, SID_V_STATE_GATE_SET_REQ
1400
 
1401
	;; check if voice should be delayed - set delay counter to 0x0001 in this case, else to 0x0000
1402
	movlw	SID_Vx_SET_DELAY_CTR_H	; high byte always reset to 0
1403
	clrf	PLUSW1
1404
 
1405
	movlw	SID_Ix_Vx_DELAY
1406
	clrf	PRODL			; low byte set to 1 if delay != 0
1407
	movf	PLUSW0, W
1408
	skpz
1409
	incf	PRODL, F
1410
 
1411
	;; delay also if ABW (ADSR bug workaround) option active
1412
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_OPT1_FLAGS, WREG
1413
	BRA_IFCLR WREG, SID_I_OPT1_FLAGS_ABW, ACCESS, SIDSE_M_NOTE_Restart_NoABW
1414
SIDSE_M_NOTE_Restart_ABW
1415
	movlw	0x01
1416
	movwf	PRODL
1417
 
1418
	;; clear ADSR registers, so that the envelope gets completely released
1419
	call	SIDSE_Hlp_GetSIDFrqPtr
1420
	movlw	SIDx_V1_ENV_AD
1421
	clrf	PLUSW2
1422
	movlw	SIDx_V1_ENV_SR
1423
	clrf	PLUSW2
1424
SIDSE_M_NOTE_Restart_NoABW
1425
 
1426
	movlw	SID_Vx_SET_DELAY_CTR_L
1427
	movff	PRODL, PLUSW1
1428
	return
1429
 
1430
 
1431
;; --------------------------------------------------------------------------
1432
;; This function updates the LED matrix
1433
;; For basslines, this is interrupt driven for fastest update time
1434
;; only used when master is selected
1435
;; IN: -
1436
;; --------------------------------------------------------------------------
1437
SIDSE_M_CS_LM
1438
 
1439
	;; if slave is selected: exit (update done in CS_MENU_LED_Update_ModMatrix)
1440
	btfss	CS_MENU_SELECTED_SID_FLAGS, 0
1441
	return
1442
 
1443
	;; exit if not in meter mode
1444
	btfss	CS_MENU_MODE, CS_MENU_MODE_MATRIX_METER_DISP
1445
	return
1446
 
1447
	;; also used by drum mode!
1448
SIDSE_D_CS_LM_Meter_ReUse
1449
 
1450
	;; activate level meters
1451
	bsf	CS_STAT2, CS_STAT2_LEVEL_METERS
1452
 
1453
	;; trigger level meter whenever gate is active
1454
	SET_BSR	SIDL_BASE
1455
SIDSE_M_CS_LM_L
1456
	movlw	0x3f
1457
	btfsc	SIDL_BASE + SIDx_V1_CTRL, 0, BANKED
1458
	movff	WREG, METER_VALUES1
1459
	btfsc	SIDL_BASE + SIDx_V2_CTRL, 0, BANKED
1460
	movff	WREG, METER_VALUES2
1461
	btfsc	SIDL_BASE + SIDx_V3_CTRL, 0, BANKED
1462
	movff	WREG, METER_VALUES3
1463
 
1464
	movlw	0x3f
1465
	btfsc	SIDR_BASE + SIDx_V1_CTRL, 0, BANKED
1466
	movff	WREG, METER_VALUES4
1467
	btfsc	SIDR_BASE + SIDx_V2_CTRL, 0, BANKED
1468
	movff	WREG, METER_VALUES5
1469
	btfsc	SIDR_BASE + SIDx_V3_CTRL, 0, BANKED
1470
	movff	WREG, METER_VALUES6
1471
 
1472
	;; clear remaining meter values
1473
	SET_BSR	METER_VALUES0
1474
	clrf	METER_VALUES0, BANKED
1475
	clrf	METER_VALUES7, BANKED
1476
	SET_BSR	SID_BASE
1477
 
1478
	return
1479