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