Subversion Repositories svn.mios

Rev

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

Rev Author Line No. Line
44 tk 1
; $Id: sid_midi_l.inc 1122 2013-04-20 12:37:28Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; MIDI Interface part for Lead Engine
5
;
6
; ==========================================================================
7
;
8
;  Copyright 1998-2007 Thorsten Klose (tk@midibox.org)
9
;  Licensed for personal non-commercial use only.
10
;  All other rights reserved.
11
;
12
; ==========================================================================
13
 
14
 
15
;; enable this switch for superpoly handling as described in MIDIbox forum
16
#define SUPERPOLY_EXPERIMENT 1
17
 
18
;; --------------------------------------------------------------------------
19
;;  This function is called to forward a Note On event to the synthesizer
20
;;  Input:
21
;;     o MIDI Voice in SID_CURRENT_MIDI_VOICE
22
;;     o MIDI channel in SID_CURRENT_CHANNEL
23
;;     o note number in SID_MIDI_PARAMETER1
24
;;     o velocity in SID_MIDI_PARAMETER2
25
;; --------------------------------------------------------------------------
26
SID_MIDI_L_NoteOn
27
	SET_BSR	SID_BASE
28
 
29
	;; lead engine works only with settings of first MIDI voice
30
	clrf	SID_CURRENT_MIDIVOICE, BANKED
31
	lfsr	FSR0, SID_MV1_BASE
32
 
33
	;; check if MIDI channel and split zone matches
34
	call	SID_MIDI_Hlp_ChkChnAndSplit
35
	bnz	SID_MIDI_L_NoteOn_End
36
 
37
#if SUPERPOLY_EXPERIMENT
38
	;; enabled when SID_ENSx_SUPERPOLY_CTRL[2:0] > 0 and number <= SID number
39
	movff	SID_LOCAL_ENS + SID_ENSx_SUPERPOLY_CTRL, WREG
40
	andlw	0x07
41
	bz	SID_MIDI_L_NoteOn_NoSuperPoly
42
	cpfslt	SID_MIDI_DEVICE, ACCESS
653 tk 43
	rgoto	SID_MIDI_L_NoteOn_NoSuperPoly
1 tk 44
SID_MIDI_L_NoteOn_SuperPoly
653 tk 45
	;; NEW:	exit if slave -> it's directly controlled from master via MBNET!
46
	movf	SID_MIDI_DEVICE, W
47
	bnz	SID_MIDI_L_NoteOn_End
48
 
49
	;; check if MIDI note already played
50
	lfsr	FSR1, SID_SUPERPOLY_VOICE_NOTE_TAB
51
	clrf	SID_CURRENT_VOICE, BANKED
52
SID_MIDI_L_NoteOn_SuperPolyLoop
53
	movf	INDF1, W
54
	xorwf	SID_MIDI_PARAMETER1, W, BANKED
55
	bz	SID_MIDI_L_NoteOn_SP_NoteFound
56
	movf	POSTINC1, W			; switch to next table entry
57
	incf	SID_CURRENT_VOICE, F, BANKED	; switch to next voice
58
	BRA_IFCLR SID_CURRENT_VOICE, 2, BANKED, SID_MIDI_L_NoteOn_SuperPolyLoop
59
 
60
	;; not already played:
1 tk 61
	;; get the next free voice
653 tk 62
	movff	SID_LOCAL_ENS + SID_ENSx_SUPERPOLY_CTRL, WREG
63
	andlw	0x07
1 tk 64
	swapf	WREG, W				; use default voice assignment mode, number of voices given by SUPERPOLY_CTRL[2:0], copied to VOICE_ASSG[6:4]
65
	movwf	SID_CURRENT_VOICE_ASSG, BANKED
66
	call	SID_VOICE_Get			; call voice allocation handler, new voice in SID_CURRENT_VOICE
67
	;; store note number of voice locally (required for release mechanism)
68
	lfsr	FSR1, SID_SUPERPOLY_VOICE_NOTE_TAB
69
	movf	SID_CURRENT_VOICE, W, BANKED
70
	movff	SID_MIDI_PARAMETER1, PLUSW1
653 tk 71
 
72
SID_MIDI_L_NoteOn_SP_NoteFound
73
	;; NEW: if not master voice: forward to slave via MBNET
1 tk 74
	movf	SID_CURRENT_VOICE, W, BANKED
653 tk 75
	bz	SID_MIDI_L_NoteOn_SuperPoly_M
76
SID_MIDI_L_NoteOn_SuperPoly_S
77
	movwf	CS_MENU_SID
78
	IRQ_ENABLE		; we can already IRQs enable again to avoid MIDI buffer overrun
79
				; which are notified with "F0 00 00 7E 40 00 0E 0B 00 F7"
80
	call	CS_MENU_MBNET_Tx_SP_Note
81
	rgoto	SID_MIDI_L_NoteOn_End
82
 
83
	;; directly called from SID_MBNET_RxSpecial_SPNOTE for SuperPoly slave control
84
SID_MIDI_L_NoteOn_SuperPoly_M
85
SID_MIDI_L_NoteOn_Direct
86
 
1 tk 87
	;; note stack has to be emptied to avoid "hanging notes" - the final superpoly
88
	;; implementation has to stack *all* incoming notes, not only the ones played by the SID voice
89
	SET_BSR	SID_MV1_BASE
90
	clrf	SID_MV1_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
91
	clrf	SID_MV2_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
92
	clrf	SID_MV3_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
93
	clrf	SID_MV4_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
94
	clrf	SID_MV5_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
95
	clrf	SID_MV6_BASE + SID_MVx_NOTE_STACK_PTR, BANKED
96
	clrf	SID_MV1_BASE + SID_MVx_NOTE_STACK_0, BANKED
97
	clrf	SID_MV2_BASE + SID_MVx_NOTE_STACK_0, BANKED
98
	clrf	SID_MV3_BASE + SID_MVx_NOTE_STACK_0, BANKED
99
	clrf	SID_MV4_BASE + SID_MVx_NOTE_STACK_0, BANKED
100
	clrf	SID_MV5_BASE + SID_MVx_NOTE_STACK_0, BANKED
101
	clrf	SID_MV6_BASE + SID_MVx_NOTE_STACK_0, BANKED
102
	SET_BSR	SID_BASE
103
SID_MIDI_L_NoteOn_NoSuperPoly
104
#endif
105
 
398 tk 106
	;; copy velocity into mod matrix source
1 tk 107
	clrc
108
	rlf	SID_MIDI_PARAMETER2, W, BANKED
109
	movwf	MIOS_PARAMETER1
110
	movlw	SID_KNOB_VEL
111
	call	SID_KNOB_SetValue
112
 
113
	;; copy patch flags to temporary register SID_MIDI_FLAGS
114
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_FLAGS1, SID_MIDI_FLAGS
115
 
116
	;; go through all voices
117
	lfsr	FSR0, SID_MV1_BASE
118
	lfsr	FSR1, SIDL_V1_BASE
119
	clrf	SID_CURRENT_VOICE, BANKED
120
SID_MIDI_L_NoteOn_Loop
121
	;; SID_Ix_Vx_ARP_MODE of instrument -> TMP1
122
	lfsr	FSR2, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE + SID_Ix_Vx_ARP_MODE
123
	movf	SID_CURRENT_VOICE, W, BANKED
124
	mullw	SID_Ix_L_S1V2_BASE-SID_Ix_L_S1V1_BASE
125
	movf	PRODL, W
126
	addwf	FSR2L, F
127
	movff	INDF2, TMP1
128
 
679 tk 129
	;; SID_Ix_Vx_ARP_SPEED_DIV of instrument -> TMP2
130
	movlw	SID_Ix_Vx_ARP_SPEED_DIV-SID_Ix_Vx_ARP_MODE
131
	movff	PLUSW2, TMP2
132
 
1 tk 133
	;; push note into WT stack
134
	lfsr	FSR2, SID_MV1_BASE + SID_MVx_WT_STACK_0
135
	movf	SID_CURRENT_VOICE, W, BANKED
136
	mullw	SID_MVx_RECORD_LEN
137
	movf	PRODL, W
138
	addwf	FSR2L, F
139
	call	SID_MIDI_Hlp_PushWT
140
 
141
	;; determine pointer to note stack -> FSR2
142
	movlw	SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
143
	addwf	FSR2L, F
144
 
145
	;; branch depending on Normal/Arp mode
146
	BRA_IFSET TMP1, SID_I_V_ARP_MODE_ENABLE, ACCESS, SID_MIDI_L_NoteOn_Loop_Arp
147
SID_MIDI_L_NoteOn_Loop_Norm
148
	;; push note into stack
149
	call	SID_MIDI_Hlp_PushNote
150
 
151
	;; switch off gate if not in legato or WTO mode
152
	BRA_IFSET SID_MIDI_FLAGS, SID_I_L_FLAGS1_WT_ONLY, BANKED, SID_MIDI_L_NoteOn_Ok_NoGateOff
153
SID_MIDI_L_NoteOn_Ok_GateOff
154
	RCALL_IFCLR SID_MIDI_FLAGS, SID_I_L_FLAGS1_LEGATO, BANKED, SID_MIDI_L_Hlp_GateOff
155
SID_MIDI_L_NoteOn_Ok_NoGateOff
156
 
157
	;; call note-on handler
158
	rcall	SID_MIDI_L_Hlp_NoteOn
159
	rgoto	SID_MIDI_L_NoteOn_Loop_Next
160
 
161
 
162
SID_MIDI_L_NoteOn_Loop_Arp
163
	call	SID_MIDI_Hlp_ArpNoteOn
164
	;; 	rgoto	SID_MIDI_L_NoteOn_Loop_Next
165
 
166
SID_MIDI_L_NoteOn_Loop_Next
167
	movlw	SID_MVx_RECORD_LEN
168
	addwf	FSR0L, F
169
	movlw	SID_Vx_RECORD_LEN
170
	addwf	FSR1L, F
171
	incf	SID_CURRENT_VOICE, F, BANKED
172
	movlw	SID_Vx_NUM - 1
173
	cpfsgt	SID_CURRENT_VOICE, BANKED
174
	rgoto SID_MIDI_L_NoteOn_Loop
175
 
176
SID_MIDI_L_NoteOn_End
177
	return
178
 
179
 
180
;; --------------------------------------------------------------------------
181
;;  This function is called to forward a Note Off event to the synthesizer
182
;;  Input:
183
;;     o MIDI channel in SID_CURRENT_CHANNEL
184
;;     o note number in SID_MIDI_PARAMETER1
185
;;     o velocity in SID_MIDI_PARAMETER2
186
;; --------------------------------------------------------------------------
187
SID_MIDI_L_NoteOff
188
	SET_BSR	SID_BASE
189
 
190
	;; lead engine works only with settings of first MIDI voice
191
	clrf	SID_CURRENT_MIDIVOICE, BANKED
192
	lfsr	FSR0, SID_MV1_BASE
193
 
194
	;; check if MIDI channel and split zone matches
195
	call	SID_MIDI_Hlp_ChkChnAndSplit
196
	bnz	SID_MIDI_L_NoteOff_End
197
 
198
#if SUPERPOLY_EXPERIMENT
199
	;; enabled when SID_ENSx_SUPERPOLY_CTRL[2:0] > 0 and number <= SID number
200
	movff	SID_LOCAL_ENS + SID_ENSx_SUPERPOLY_CTRL, WREG
201
	andlw	0x07
202
	bz	SID_MIDI_L_NoteOff_NoSuperPoly
203
	cpfslt	SID_MIDI_DEVICE, ACCESS
653 tk 204
	rgoto	SID_MIDI_L_NoteOff_NoSuperPoly
1 tk 205
SID_MIDI_L_NoteOff_SuperPoly
653 tk 206
	;; exit if slave -> it's directly controlled from master via MBNET!
207
	movf	SID_MIDI_DEVICE, W
208
	bnz	SID_MIDI_L_NoteOff_End
209
 
1 tk 210
	;; check MIDI note -> voice assignment
211
	lfsr	FSR1, SID_SUPERPOLY_VOICE_NOTE_TAB
212
	clrf	SID_CURRENT_VOICE, BANKED
213
SID_MIDI_L_NoteOff_SuperPolyLoop
214
	movf	INDF1, W
215
	xorwf	SID_MIDI_PARAMETER1, W, BANKED
216
	bz	SID_MIDI_L_NoteOff_SP_NoteFound
217
	movf	POSTINC1, W			; switch to next table entry
218
	incf	SID_CURRENT_VOICE, F, BANKED	; switch to next voice
219
	BRA_IFCLR SID_CURRENT_VOICE, 2, BANKED, SID_MIDI_L_NoteOff_SuperPolyLoop
653 tk 220
 
1 tk 221
	rgoto	SID_MIDI_L_NoteOff_End		; note not played
222
 
223
SID_MIDI_L_NoteOff_SP_NoteFound
224
	clrf	INDF1				; clear note number (so, it's free again)
225
 
226
	;; release voice
227
	call	SID_VOICE_Release	; expects voice number in SID_CURRENT_VOICE
228
 
653 tk 229
	;; NEW: if not master voice: forward to slave via MBNET
1 tk 230
	movf	SID_CURRENT_VOICE, W, BANKED
653 tk 231
	bz	SID_MIDI_L_NoteOff_SuperPoly_M
232
SID_MIDI_L_NoteOff_SuperPoly_S
233
	clrf	SID_MIDI_PARAMETER2, BANKED ; ensure that velocity is zero, so that Note Off will be played
234
	movwf	CS_MENU_SID
235
	IRQ_ENABLE		; we can already IRQs enable again to avoid MIDI buffer overrun
236
				; which are notified with "F0 00 00 7E 40 00 0E 0B 00 F7"
237
	call	CS_MENU_MBNET_Tx_SP_Note
238
	rgoto	SID_MIDI_L_NoteOff_End
239
SID_MIDI_L_NoteOff_SuperPoly_M
240
	;; directly called from SID_MBNET_RxSpecial_SPNOTE for SuperPoly slave control
241
SID_MIDI_L_NoteOff_Direct
1 tk 242
SID_MIDI_L_NoteOff_NoSuperPoly
243
#endif
244
 
653 tk 245
 
1 tk 246
	;; copy patch flags to temporary register SID_MIDI_FLAGS
247
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_FLAGS1, SID_MIDI_FLAGS
248
 
249
	;; go through all voices
250
	lfsr	FSR0, SID_MV1_BASE
251
	lfsr	FSR1, SIDL_V1_BASE
252
	clrf	SID_CURRENT_VOICE, BANKED
253
SID_MIDI_L_NoteOff_Loop
254
	;; SID_Ix_Vx_ARP_MODE of instrument -> TMP1
255
	lfsr	FSR2, SID_PATCH_BUFFER_SHADOW + SID_Ix_L_S1V1_BASE + SID_Ix_Vx_ARP_MODE
256
	movf	SID_CURRENT_VOICE, W, BANKED
257
	mullw	SID_Ix_L_S1V2_BASE-SID_Ix_L_S1V1_BASE
258
	movf	PRODL, W
259
	addwf	FSR2L, F
260
	movff	INDF2, TMP1
261
 
679 tk 262
	;; SID_Ix_Vx_ARP_SPEED_DIV of instrument -> TMP2
263
	movlw	SID_Ix_Vx_ARP_SPEED_DIV-SID_Ix_Vx_ARP_MODE
264
	movff	PLUSW2, TMP2
265
 
1 tk 266
	;; pop note from WT stack if sustain function not active
267
	lfsr	FSR2, SID_MV1_BASE + SID_MVx_WT_STACK_0
268
	movf	SID_CURRENT_VOICE, W, BANKED
269
	mullw	SID_MVx_RECORD_LEN
270
	movf	PRODL, W
271
	addwf	FSR2L, F
272
	CALL_IFCLR SID_MIDIVOICE_SUSTAIN, 0, BANKED, SID_MIDI_Hlp_PopWT
273
 
274
	;; determine pointer to note stack -> FSR2
275
	movlw	SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
276
	addwf	FSR2L, F
277
	movff	INDF2, TMP3	; save current #0 entry in TMP3 for later use
278
 
279
	;; if sustain active: mark note, but don't stop it
280
	;; this works for normal and arp mode
281
	BRA_IFCLR SID_MIDIVOICE_SUSTAIN, 0, BANKED, SID_MIDI_L_NoteOff_Loop_NoSus
282
	;; if not in arp mode: sustain only relevant if only one active note in stack
283
	BRA_IFSET TMP1, SID_I_V_ARP_MODE_ENABLE, ACCESS, SID_MIDI_L_NoteOff_Loop_Sus
284
	clrf	PRODL		; loop counter
285
	clrf	PRODH		; active note counter
286
SID_MIDI_L_NoteOff_Loop_SusChkLp
287
	movf	PRODL, W
288
	movf	PLUSW2, F
289
	bz	SID_MIDI_L_NoteOff_Loop_SusCLpNx
290
	btfss	PLUSW2, 7
291
	incf	PRODH, F
292
SID_MIDI_L_NoteOff_Loop_SusCLpNx
293
	incf	PRODL, F
294
	movlw	SID_MVx_NOTE_STACK_LEN - 1
295
	cpfsgt	PRODL, ACCESS
296
	rgoto SID_MIDI_L_NoteOff_Loop_SusChkLp
297
	;; no special sustain if more than one note is played
298
	movlw	2
299
	cpfslt	PRODH, ACCESS
300
	rgoto SID_MIDI_L_NoteOff_Loop_NoSus
301
SID_MIDI_L_NoteOff_Loop_Sus
302
	rcall	SID_MIDI_Hlp_PopArpHold
303
	rgoto	SID_MIDI_L_NoteOff_Loop_Next
304
SID_MIDI_L_NoteOff_Loop_NoSus
305
 
306
	;; branch depending on Normal/Arp mode
307
	BRA_IFSET TMP1, SID_I_V_ARP_MODE_ENABLE, ACCESS, SID_MIDI_L_NoteOff_Loop_Arp
308
SID_MIDI_L_NoteOff_Loop_Norm
309
 
310
	;; pop note from stack (pointer to stack in FSR2)
311
	rcall	SID_MIDI_Hlp_PopNote
843 tk 312
	bnz	SID_MIDI_L_NoteOff_Loop_Next ; ZERO flag cleared: note not found!
1 tk 313
 
314
	movf	TMP3, W		; restore note
315
	rcall	SID_MIDI_L_Hlp_NoteOff
316
	RCALL_IFSET WREG, 0, ACCESS, SID_MIDI_L_Hlp_NoteOn
317
	rgoto	SID_MIDI_L_NoteOff_Loop_Next
318
 
319
 
320
SID_MIDI_L_NoteOff_Loop_Arp
321
	call	SID_MIDI_Hlp_ArpNoteOff
322
	;; 	rgoto	SID_MIDI_L_NoteOff_Loop_Next
323
 
324
SID_MIDI_L_NoteOff_Loop_Next
325
	movlw	SID_MVx_RECORD_LEN
326
	addwf	FSR0L, F
327
	movlw	SID_Vx_RECORD_LEN
328
	addwf	FSR1L, F
329
	incf	SID_CURRENT_VOICE, F, BANKED
330
	movlw	SID_Vx_NUM - 1
331
	cpfsgt	SID_CURRENT_VOICE, BANKED
332
	rgoto SID_MIDI_L_NoteOff_Loop
333
 
334
SID_MIDI_L_NoteOff_End
335
	return
336
 
337
 
338
;; --------------------------------------------------------------------------
339
;;  This function is called to forward a PitchBender event to the synthesizer
340
;;  Input:
341
;;     o MIDI channel in SID_CURRENT_CHANNEL
342
;;     o 8bit PitchBender value in SID_MIDI_PARAMETER1
343
;; --------------------------------------------------------------------------
344
SID_MIDI_L_PitchBender
345
	;; nothing else to do (pitchbender knob already handled in sid_midi.inc)
346
	return
347
 
348
 
349
;; --------------------------------------------------------------------------
350
;;  This function is called to forward a CC event to the synthesizer
351
;;  Input:
352
;;     o MIDI channel in SID_CURRENT_CHANNEL
353
;;     o CC number in SID_MIDI_PARAMETER1
354
;;     o CC value in SID_MIDI_PARAMETER2
355
;; --------------------------------------------------------------------------
356
SID_MIDI_L_CC
357
	SET_BSR	SID_BASE
358
 
359
	;; exit if MIDI channel doesn't match (only check for first MIDI voice)
360
	movff	SID_MV1_BASE + SID_MVx_MIDI_CHANNEL, WREG
361
	cpfseq	SID_CURRENT_CHANNEL, BANKED
679 tk 362
	rgoto	SID_MIDI_L_End
1 tk 363
 
1122 tk 364
	;; if CC#06 (NRPN data MSB) received, forward to parameter handler
1 tk 365
	movlw	0x06
366
	cpfseq	SID_MIDI_PARAMETER1, BANKED
679 tk 367
	rgoto	SID_MIDI_L_CC_NoNRPNDataH
1 tk 368
SID_MIDI_L_CC_NRPNDataH
369
	;; prepare MIOS_PARAMETER3 (selection options)
370
	clrf	MIOS_PARAMETER3		; (L/R selection done in NRPN function)
371
	call	SID_PARIN_SetNRPN
372
	rgoto	SID_MIDI_L_End
373
SID_MIDI_L_CC_NoNRPNDataH
374
 
375
	;; if CC#64 (Sustain) received, set/clear sustain flags and release notes if required
376
	movlw	0x40
377
	cpfseq	SID_MIDI_PARAMETER1, BANKED
679 tk 378
	rgoto	SID_MIDI_L_CC_Not64
1 tk 379
SID_MIDI_L_CC_64
380
	;; sustain enabled if CC value >= 0x40
381
	BRA_IFSET SID_MIDI_PARAMETER2, 6, BANKED, SID_MIDI_L_CC_64_1
382
SID_MIDI_L_CC_64_0
383
	;; clear all flags and disable all notes
384
	clrf	SID_MIDIVOICE_SUSTAIN, BANKED
385
	;; go through all voices
386
	lfsr	FSR0, SID_MV1_BASE
387
	lfsr	FSR1, SIDL_V1_BASE
388
	clrf	SID_CURRENT_VOICE, BANKED
389
SID_MIDI_L_CC_64_0_Loop
390
	;; clear WT stack
391
	;; (TODO: this needs some more work - it would be nice if the WT sequencer would
392
	;; still play when sustain is released for continous sequences)
393
	movff	FSR0H, FSR2H
394
	movlw	SID_MVx_WT_STACK_3
395
	addwf	FSR0L, W
396
	movwf	FSR2L
397
	clrf	POSTDEC2
398
	clrf	POSTDEC2
399
	clrf	POSTDEC2
400
	clrf	INDF2
401
	;; clear all non-active notes (which have been released during sustain was active)
402
	movlw	SID_MVx_NOTE_STACK_0 - SID_MVx_WT_STACK_0
403
	addwf	FSR2L, F
404
	rcall	SID_MIDI_Hlp_ClrNonActive
405
	;; initiate note off
406
	movlw	SID_Vx_PLAYED_NOTE	; dirty: fake note --- SID_MIDI_PARAMETER1 has to be overwritten!!!
407
	movf	PLUSW1, W
408
	movwf	SID_MIDI_PARAMETER1, BANKED
409
	;; (skip if note hasn't been changed)
410
	movlw	SID_MVx_NOTE_STACK_0
411
	movf	PLUSW0, W
412
	xorwf	SID_MIDI_PARAMETER1, W, BANKED
413
	bz	SID_MIDI_L_CC_64_0_Loop_Next
414
	movf	SID_MIDI_PARAMETER1, W, BANKED
415
	rcall	SID_MIDI_L_Hlp_NoteOff
416
	RCALL_IFSET WREG, 0, ACCESS, SID_MIDI_L_Hlp_NoteOn
417
SID_MIDI_L_CC_64_0_Loop_Next
418
	movlw	SID_MVx_RECORD_LEN
419
	addwf	FSR0L, F
420
	movlw	SID_Vx_RECORD_LEN
421
	addwf	FSR1L, F
422
	incf	SID_CURRENT_VOICE, F, BANKED
423
	movlw	SID_Vx_NUM - 1
424
	cpfsgt	SID_CURRENT_VOICE, BANKED
679 tk 425
	rgoto	SID_MIDI_L_CC_64_0_Loop
1 tk 426
 
427
	rgoto	SID_MIDI_L_CC_64_End
428
SID_MIDI_L_CC_64_1
429
	;; set first flag - notes won't be removed from note stack anymore until sustain is disabled again
430
	movlw	0x01
431
	movwf	SID_MIDIVOICE_SUSTAIN, BANKED
432
	;; 	rgoto	SID_MIDI_L_CC_64_End
433
 
434
SID_MIDI_L_CC_64_End
679 tk 435
	rgoto	SID_MIDI_L_End
436
 
1 tk 437
SID_MIDI_L_CC_Not64
438
 
679 tk 439
	;; handle remaining CCs
1122 tk 440
	movlw	0x03		; modify both channels
441
	movwf	MIOS_PARAMETER3
679 tk 442
	call	SID_CC_TABLE_Set
443
 
1 tk 444
SID_MIDI_L_End
445
	return
446
 
447
 
448
;; --------------------------------------------------------------------------
449
;;  help routines for lead engine
450
;; --------------------------------------------------------------------------
451
 
452
 
453
;; --------------------------------------------------------------------------
454
;; Note On help function
455
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
456
;;     voice number in SID_CURRENT_VOICE
457
;; ALSO USED BY SID_PATCH_Init !
458
;; --------------------------------------------------------------------------
459
SID_MIDI_L_Hlp_NoteOn
460
	;; save note into SID_Vx_NOTE (if not in WTO mode) and SID_Vx_PLAYED_NOTE (last one is relevant for MIDI handler)
461
	movlw	SID_MVx_NOTE_STACK_0
462
	movff	PLUSW0, PRODL
463
	bcf	PRODL, 7	; (ensure that non-active flag is cleared)
464
	BRA_IFSET SID_MIDI_FLAGS, SID_I_L_FLAGS1_WT_ONLY, BANKED, SID_MIDI_L_Hlp_NoteOn_WTO
465
SID_MIDI_L_Hlp_NoteOn_NotWTO
466
	movlw	SID_Vx_NOTE
467
	movff	PRODL, PLUSW1
468
SID_MIDI_L_Hlp_NoteOn_WTO
469
	movlw	SID_Vx_PLAYED_NOTE
470
	movff	PRODL, PLUSW1
471
 
472
	;; sus-key activated?
473
	BRA_IFCLR SID_MIDI_FLAGS, SID_I_L_FLAGS1_SUS_KEY, BANKED, SID_MIDI_L_Hlp_NoteOn_NoSusKey
474
SID_MIDI_L_Hlp_NoteOn_SusKey
875 tk 475
	;; in sus-key mode, we activate portamento only if at least two keys are played
228 tk 476
	movlw	SID_MVx_NOTE_STACK_PTR
477
	decf	PLUSW0, W
478
	bz	SID_MIDI_L_Hlp_NoteOn_NoSusKeyPr
1 tk 479
SID_MIDI_L_Hlp_NoteOn_NoSusKey
399 tk 480
	;; omit portamento if first key played after patch initialisation
481
	movlw	SID_Vx_STATE2
482
	BRA_IFCLR PLUSW1, SID_V_STATE2_PORTA_INITIALIZED, ACCESS, SID_MIDI_L_Hlp_NoteOn_NoSusKeyPr
1 tk 483
	movlw	SID_Vx_STATE
484
	bsf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
485
SID_MIDI_L_Hlp_NoteOn_NoSusKeyPr
486
 
399 tk 487
	;; next key will allow portamento
488
	movlw	SID_Vx_STATE2
489
	bsf	PLUSW1, SID_V_STATE2_PORTA_INITIALIZED
490
 
1 tk 491
	;; skip the rest if legato and voice already active
492
	BRA_IFCLR SID_MIDI_FLAGS, SID_I_L_FLAGS1_LEGATO, BANKED, SID_MIDI_L_Hlp_NoteOn_NoLegato
493
SID_MIDI_L_Hlp_NoteOn_Legato
494
	movlw	SID_Vx_STATE
495
	BRA_IFSET PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_L_Hlp_NoteOn_End
496
SID_MIDI_L_Hlp_NoteOn_NoLegato
497
 
498
	;; request gate bit
499
	rcall	SID_MIDI_L_Hlp_GateOn
500
 
501
	;; don't sync if legato mode and current note is first note
502
	RCALL_IFCLR SID_MIDI_FLAGS, SID_I_L_FLAGS1_LEGATO, BANKED, SID_MIDI_L_Hlp_NoteOn_NOnTrg
503
	movlw	SID_MVx_NOTE_STACK_0
504
	movff	PLUSW0, PRODL
505
	movf	SID_MIDI_PARAMETER1, W, BANKED
506
	cpfseq	PRODL, ACCESS
507
	rgoto SID_MIDI_L_Hlp_NoteOn_NoNOnTrg
508
	movlw	SID_MVx_NOTE_STACK_1
509
	movf	PLUSW0, W
510
	bnz	SID_MIDI_L_Hlp_NoteOn_NoNOnTrg
511
SID_MIDI_L_Hlp_NoteOn_NOnTrg
512
 
513
	;; WTO mode: only trigger WT reset/step sync
514
	BRA_IFSET SID_MIDI_FLAGS, SID_I_L_FLAGS1_WT_ONLY, BANKED, SID_MIDI_L_Hlp_NoteOn_NOnTrg_WTO
515
 
516
	;; determine mask for Note On
517
	movf	SID_CURRENT_VOICE, W, BANKED
518
	call	MIOS_HLP_GetBitORMask
519
	iorlw	0xc0
520
	movwf	PRODL
521
	;; ENV/LFO/... synchronisation via trigger matrix
522
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 0, WREG
523
	andwf	PRODL, W	; only selected voice can trigger NoteOn
524
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
525
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 1, WREG
526
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
527
 
528
SID_MIDI_L_Hlp_NoteOn_NOnTrg_WTO
529
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOn_BASE + 2, WREG
530
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
531
SID_MIDI_L_Hlp_NoteOn_NoNOnTrg
532
 
533
SID_MIDI_L_Hlp_NoteOn_End
534
	return
535
 
536
 
537
;; --------------------------------------------------------------------------
538
;; Note Off help function
399 tk 539
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
1 tk 540
;; OUT: returns 0x01 if gate should be retriggered (mono mode, more than one note was played)
541
;; --------------------------------------------------------------------------
542
SID_MIDI_L_Hlp_NoteOff
543
	;; last note number of #0 (before pop) in WREG!
544
	movwf	TABLAT
545
 
546
	;; if not in legato mode and current note-off number equal to last entry #0: gate off
547
	movf	TABLAT, W
548
	cpfseq	SID_MIDI_PARAMETER1, BANKED
549
	rgoto SID_MIDI_L_Hlp_NoteOff_End
550
	BRA_IFSET SID_MIDI_FLAGS, SID_I_L_FLAGS1_LEGATO, BANKED, SID_MIDI_L_Hlp_NoteOff_NoGOff
551
	rcall	SID_MIDI_L_Hlp_GateOff
552
SID_MIDI_L_Hlp_NoteOff_NoGOff
553
	;; ------------------------------------------------------------------
554
 
555
	;; if there is still a note in the stack, play new note with NoteOn function (checked by caller)
556
	movlw	SID_MVx_NOTE_STACK_PTR
557
	movf	PLUSW0, W
842 tk 558
	bz	SID_MIDI_L_Hlp_NoteOff_GOff
559
 
560
	;; activate portamento (will be ignored by Pitch handler if no portamento active - important for SusKey function to have it here!)
561
	movlw	SID_Vx_STATE
562
	bsf	PLUSW1, SID_V_STATE_PORTA_ACTIVE
563
 
1 tk 564
	retlw	0x01		; return, request Note On!
565
 
566
SID_MIDI_L_Hlp_NoteOff_GOff
567
	;; else request gate clear bit
568
	rcall	SID_MIDI_L_Hlp_GateOff
569
 
570
	;; ENV/LFO/... synchronisation via trigger matrix
571
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, WREG
379 tk 572
	andlw	0xc0		; (Gates handled separately in SID_MIDI_L_Hlp_GateOff)
1 tk 573
	iorwf	SID_SE_TRG_EVNT_L, F, BANKED
574
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 1, WREG
575
	iorwf	SID_SE_TRG_EVNT_H, F, BANKED
576
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 2, WREG
577
	iorwf	SID_SE_TRG_EVNT_U, F, BANKED
578
SID_MIDI_L_Hlp_NoteOff_End
579
	retlw	0x00		; return, request NO Note On!
580
 
581
 
582
;; --------------------------------------------------------------------------
583
;; Gate On help function
584
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
585
;;     voice number in SID_CURRENT_VOICE
586
;; --------------------------------------------------------------------------
587
SID_MIDI_L_Hlp_GateOn
588
	;; set "voice active" flag
589
	movlw	SID_Vx_STATE
590
	bsf	PLUSW1, SID_V_STATE_VOICE_ACTIVE
591
 
592
SID_MIDI_L_Hlp_GateOn_End
593
	return
594
 
595
;; --------------------------------------------------------------------------
596
;; Gate Off help function
597
;; IN: pointer to voice in FSR1, pointer to MIDI voice in FSR0
598
;;     voice in SID_CURRENT_VOICE
599
;;     note in SID_MIDI_PARAMETER1
600
;; --------------------------------------------------------------------------
601
SID_MIDI_L_Hlp_GateOff
602
	;; nothing to do if voice not active anymore
603
	movlw	SID_Vx_STATE
604
	BRA_IFCLR PLUSW1, SID_V_STATE_VOICE_ACTIVE, ACCESS, SID_MIDI_L_Hlp_GateOff_End
605
 
606
#if 0
607
	;; clashes with sustain function (different note is played when still held after sustain-off)
608
	;; don't know why this check should be relevant for lead engine, it's required for multi engine
609
	;; maybe an artefact...
610
	movlw	SID_Vx_PLAYED_NOTE
611
	movf	PLUSW1, W
612
	cpfseq	SID_MIDI_PARAMETER1, BANKED
613
	rgoto SID_MIDI_L_Hlp_GateOff_End
614
#endif
615
 
616
	;; request gate off if not disabled via trigger matrix
617
	movlw	SID_Vx_STATE
618
	bcf	PLUSW1, SID_V_STATE_VOICE_ACTIVE
619
	bcf	PLUSW1, SID_V_STATE_GATE_SET_REQ
620
 
621
	;; request gate clear via trigger matrix
622
	movf	SID_CURRENT_VOICE, W, BANKED
623
	call	MIOS_HLP_GetBitORMask
624
	movwf	PRODL
625
	SET_BSR	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE
626
	andwf	SID_PATCH_BUFFER_SHADOW + SID_Ix_L_TRG_NOf_BASE + 0, W, BANKED
627
	SET_BSR	SID_BASE
628
	movlw	SID_Vx_STATE
629
	skpz
630
	bsf	PLUSW1, SID_V_STATE_GATE_CLR_REQ
631
 
632
	;; remove gate set request
633
	comf	PRODL, W
634
	andwf	SID_SE_TRG_EVNT_L, F, BANKED
635
 
636
SID_MIDI_L_Hlp_GateOff_End
637
	return