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_voice.inc 44 2008-01-30 21:39:30Z tk $
1 tk 2
;
3
; MIDIbox SID
4
; Voice handling
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
;; --------------------------------------------------------------------------
16
;;  This function initializes the voice queue and the assigned instruments
17
;;  The queue contains a number for each voice. So long bit 7 is set, the
18
;;  voice is assigned to an instrument, if bit 7 is not set, the voice can
19
;;  be allocated by a new instrument
20
;;
21
;;  The instrument number to which the voice is assigned can be found in
22
;;  SID_VOICE_INSTR_x, it is especially important for mono voices
23
;;
24
;;  The first voice in the queue is the first which will be taken.
25
;;  To realize a "drop longest note first" algorithm, the take number should
26
;;  always be moved to the end of the queue
27
;;
28
;;  IN: -
29
;;  OUT: -
30
;;  USES: PRODL, FSR1
31
;; --------------------------------------------------------------------------
32
SID_VOICE_Init
33
	;; init voice queue
34
	lfsr	FSR1, SID_VOICE_QUEUE_0
35
	clrf	PRODL
36
SID_VOICE_InitQueueLoop1
37
	movff	PRODL, POSTINC1
38
	incf	PRODL, F
39
	movlw	SID_VOICE_QUEUE_LEN - 1
40
	cpfsgt	PRODL, ACCESS
41
	rgoto SID_VOICE_InitQueueLoop1
42
 
43
	;; init INSTR queue
44
	lfsr	FSR1, SID_VOICE_INSTR_0
45
	clrf	PRODL
46
SID_VOICE_InitQueueLoop2
47
	setf	POSTINC1
48
	incf	PRODL, F
49
	movlw	SID_VOICE_QUEUE_LEN - 1
50
	cpfsgt	PRODL, ACCESS
51
	rgoto SID_VOICE_InitQueueLoop2
52
 
53
	;; init exclusive voice allocation flags
54
	rcall	SID_VOICE_ReInit
55
 
56
	;; init superpoly note table (4 tables)
57
	lfsr	FSR1, SID_SUPERPOLY_VOICE_NOTE_TAB
58
	clrf	POSTINC1
59
	clrf	POSTINC1
60
	clrf	POSTINC1
61
	clrf	POSTINC1
62
 
63
	return
64
 
65
;; --------------------------------------------------------------------------
66
;;  (Re-)initializes the exclusive voice allocation flags
67
;; --------------------------------------------------------------------------
68
SID_VOICE_ReInit
69
	;; interrupts must be disabled when the voice queue is modified
70
	;; (in drum mode, voice queue is handled via IRQs)
71
	IRQ_DISABLE
72
 
73
	;; by default, allow non-exclusive access (INSTR[6] set to 1)
74
	lfsr	FSR1, SID_VOICE_INSTR_0
75
	clrf	PRODL
76
SID_VOICE_ReInit_Loop
77
	bsf	POSTINC1, 6
78
	incf	PRODL, F
79
	movlw	SID_VOICE_QUEUE_LEN - 1
80
	cpfsgt	PRODL, ACCESS
81
	rgoto SID_VOICE_ReInit_Loop
82
 
83
	;; branch depending on engine
84
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
85
	BRA_IFSET WREG, 1, ACCESS, SID_VOICE_ReInit_DM
86
SID_VOICE_ReInit_LB
87
	;; exclusive voice assignments not used by Lead/Bassline engine
88
	rgoto	SID_VOICE_ReInit_End
89
 
90
SID_VOICE_ReInit_DM
91
	BRA_IFSET WREG, 0, ACCESS, SID_VOICE_ReInit_M
92
SID_VOICE_ReInit_D
93
	;; go through 16 instruments
94
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_D_I1_BASE
95
	clrf	PRODL
96
SID_VOICE_ReInit_D_Loop
97
	movlw	SID_Ix_Dx_FLAGS1	; voice assignment located in [7:4]
98
	swapf	PLUSW1, W
99
	andlw	0x0f
100
	addlw	-3			; check if voice 1..6 exclusively selected
101
	movwf	PRODH
102
	movlw	6
103
	cpfslt	PRODH, ACCESS
104
	rgoto SID_VOICE_ReInit_D_Loop_Next
105
	;; exclusive voice assignment found -> clear flag #6 of INSTR record
106
	rcall	SID_VOICE_ReInit_Sub
107
SID_VOICE_ReInit_D_Loop_Next
108
	movlw	(SID_Ix_D_I2_BASE-SID_Ix_D_I1_BASE)
109
	addwf	FSR1L, F
110
	incf	PRODL, F
111
	BRA_IFCLR PRODL, 4, ACCESS, SID_VOICE_ReInit_D_Loop
112
	rgoto	SID_VOICE_ReInit_End
113
 
114
SID_VOICE_ReInit_M
115
	;; go through 6 instruments
116
	lfsr	FSR1, SID_PATCH_BUFFER_SHADOW + SID_Ix_M_I1_BASE
117
	clrf	PRODL
118
SID_VOICE_ReInit_M_Loop
119
	movlw	SID_Ix_M_Vx_VOICE_ASSGN	; voice assignment located in [3:0]
120
	movf	PLUSW1, W
121
	andlw	0x0f
122
	addlw	-3			; check if voice 1..6 exclusively selected
123
	movwf	PRODH
124
	movlw	6
125
	cpfslt	PRODH, ACCESS
126
	rgoto SID_VOICE_ReInit_M_Loop_Next
127
	;; exclusive voice assignment found -> clear flag #6 of INSTR record
128
	rcall	SID_VOICE_ReInit_Sub
129
SID_VOICE_ReInit_M_Loop_Next
130
	movlw	(SID_Ix_M_I2_BASE-SID_Ix_M_I1_BASE)
131
	addwf	FSR1L, F
132
	movlw	0
133
	addwfc	FSR1H, F
134
 
135
	incf	PRODL, F
136
	movlw	6-1
137
	cpfsgt	PRODL, ACCESS
138
	rgoto SID_VOICE_ReInit_M_Loop
139
	;; 	rgoto	SID_VOICE_ReInit_End
140
 
141
SID_VOICE_ReInit_End
142
	IRQ_ENABLE
143
	return
144
 
145
	;; help routine which searches for INSTR entry of specific voice and
146
	;; clears flag #6 of this entry, so that it is exclusively assigned
147
	;; IN: voice number in PRODH
148
SID_VOICE_ReInit_Sub
149
	lfsr	FSR0, SID_VOICE_QUEUE_0
150
	clrf	TABLAT
151
SID_VOICE_ReInit_Sub_Loop
152
	movf	TABLAT, W
153
	movf	PLUSW0, W
154
	andlw	0x7f
155
	xorwf	PRODH, W
156
	bz	SID_VOICE_ReInit_Sub_Found
157
	incf	TABLAT, F
158
	movlw	SID_VOICE_QUEUE_LEN - 1
159
	cpfsgt	TABLAT, ACCESS
160
	rgoto SID_VOICE_ReInit_Sub_Loop
161
	;; very strange error which should never happen!!! issue an reset for debugging purposes
162
	goto	MIOS_Reset
163
SID_VOICE_ReInit_Sub_Found
164
	movf	TABLAT, W
165
	addlw	SID_VOICE_INSTR_OFFSET
166
	bcf	PLUSW0, 6
167
	return
168
 
169
 
170
;; --------------------------------------------------------------------------
171
;;  (Re-)initializes the superpoly voice allocation
172
;; --------------------------------------------------------------------------
173
SID_VOICE_SP_ReInit
174
	;; if lead engine selected:
175
	movff	SID_PATCH_BUFFER_SHADOW + SID_Ix_ENGINE, WREG
176
	andlw	0x03
177
	bnz	SID_VOICE_SP_ReInit_NoLead
178
SID_VOICE_SP_ReInit_Lead
179
	;; re-initialize voice queues
180
	rcall	SID_VOICE_Init
181
SID_VOICE_SP_ReInit_NoLead
182
	return
183
 
184
 
185
;; --------------------------------------------------------------------------
186
;;  This function searches for a voice which is not allocated, or drops the
187
;;  voice which played the longest note
188
;;  IN:  o instrument number in SID_CURRENT_MIDIVOICE
189
;;       o voice assignment mode in SID_CURRENT_VOICE_ASSG[2:0]
190
;;       o number of voices (1..6) in SID_CURRENT_VOICE_ASSG[6:4]
191
;;  OUT: o SID_CURRENT_VOICE contains the index of the found voice
192
;;       o FSR1 contains the base pointer to the found voice
193
;;  USES: PROD[LH], TABLAT, FSR1
194
;; --------------------------------------------------------------------------
195
SID_VOICE_Get
196
	SET_BSR	SID_BASE
197
 
198
	;; number of voices -> TABLAT
199
	swapf	SID_CURRENT_VOICE_ASSG, W, BANKED
200
	andlw	0x07
201
	movwf	TABLAT
202
 
203
	;; branch depending on voice assignment mode
204
	movf	SID_CURRENT_VOICE_ASSG, W, BANKED
205
	andlw	0x0f
206
	bz	SID_VOICE_Get_LR
207
	addlw	-1
208
	bz	SID_VOICE_Get_L
209
	addlw	-1
210
	bz	SID_VOICE_Get_R
211
	addlw	-1
212
 
213
SID_VOICE_Get_S
214
	;; get single voice, number in SID_CURRENT_VOICE_ASSG[3:0]  (-3)
215
	movwf	PRODH
216
 
217
	;; only take one of the first n voices (n = TABLAT)
218
	decf	TABLAT, W
219
	cpfsgt	PRODH, ACCESS
220
	rgoto SID_VOICE_Get_S_Ok
221
	;; decrement number of available voices
222
	;; e.g.: n=3, PRODH=4 (voice 5) -> PRODH += ((comf n) + 1) -> PRODH += 0xfc+1) -> PRODH=1 (voice 2)
223
	comf	WREG, W
224
	addlw	1
225
	addwf	PRODH, F
226
	;; ensure that PRODH is never > n (corner case where SID_CURRENT_VOICE_ASSG[2:0] contains invalid value)
227
	movf	TABLAT, W
228
	cpfslt	PRODH, ACCESS
229
	clrf PRODH
230
SID_VOICE_Get_S_Ok
231
 
232
	;; search for the voice and allocate it
233
	lfsr	FSR1, SID_VOICE_QUEUE_0
234
	clrf	PRODL
235
SID_VOICE_Get_S_Loop
236
	movf	PRODL, W
237
	movf	PLUSW1, W
238
	andlw	0x7f
239
	xorwf	PRODH, W
240
	bz	SID_VOICE_Get_Found
241
	incf	PRODL, F
242
	movlw	SID_VOICE_QUEUE_LEN - 1
243
	cpfsgt	PRODL, ACCESS
244
	rgoto SID_VOICE_Get_S_Loop
245
SID_VOICE_Get_S_NotFound
246
	;; very strange error which should never happen!!! issue an reset for debugging purposes
247
	goto	MIOS_Reset
248
 
249
 
250
	;; ------------------------------------------------------------------
251
SID_VOICE_Get_L
252
	;; only Voice 1..3 allowed!
253
	movlw	3
254
	cpfslt	TABLAT, ACCESS
255
	movwf TABLAT
256
 
257
SID_VOICE_Get_LR ; (all voices available)
258
 
259
	lfsr	FSR1, SID_VOICE_QUEUE_0
260
	clrf	PRODL
261
SID_VOICE_Get_L_Loop1
262
	movf	PRODL, W
263
	movff	PLUSW1, PRODH
264
	BRA_IFSET PRODH, 7, ACCESS, SID_VOICE_Get_L_Loop1_Next
265
	;; don't take voice if exclusively allocated
266
	movf	PRODL, W
267
	addlw	SID_VOICE_INSTR_OFFSET
268
	BRA_IFCLR PLUSW1, 6, ACCESS, SID_VOICE_Get_L_Loop1_Next
269
 
270
	;; check if voice < TABLAT (number of voices)
271
	decf	TABLAT, W
272
	cpfsgt	PRODH, ACCESS
273
	rgoto SID_VOICE_Get_Found
274
SID_VOICE_Get_L_Loop1_Next
275
	incf	PRODL, F
276
	movlw	SID_VOICE_QUEUE_LEN - 1
277
	cpfsgt	PRODL, ACCESS
278
	rgoto SID_VOICE_Get_L_Loop1
279
SID_VOICE_Get_L_NotFound
280
 
281
 
282
	;; no free voice found, take first note in queue w/ exclusive check
283
	;; it must be < TABLAT
284
	clrf	PRODL
285
SID_VOICE_Get_L_Loop2
286
	movf	PRODL, W
287
	addlw	SID_VOICE_INSTR_OFFSET
288
	BRA_IFCLR PLUSW1, 6, ACCESS, SID_VOICE_Get_L_Loop2_Next
289
 
290
	movf	PRODL, W
291
	movf	PLUSW1, W
292
	andlw	0x7f
293
	movwf	PRODH
294
 
295
	;; check if voice < TABLAT (number of voices)
296
	decf	TABLAT, W
297
	cpfsgt	PRODH, ACCESS
298
	rgoto SID_VOICE_Get_Found
299
SID_VOICE_Get_L_Loop2_Next
300
	incf	PRODL, F
301
	movlw	SID_VOICE_QUEUE_LEN - 1
302
	cpfsgt	PRODL, ACCESS
303
	rgoto SID_VOICE_Get_L_Loop2
304
 
305
	;; still no free voice found, take first note in queue w/o exclusive check
306
	;; it must be < TABLAT
307
	clrf	PRODL
308
SID_VOICE_Get_L_Loop3
309
	movf	PRODL, W
310
	movf	PLUSW1, W
311
	andlw	0x7f
312
	movwf	PRODH
313
 
314
	;; check if voice < TABLAT (number of voices)
315
	decf	TABLAT, W
316
	cpfsgt	PRODH, ACCESS
317
	rgoto SID_VOICE_Get_Found
318
	incf	PRODL, F
319
	movlw	SID_VOICE_QUEUE_LEN - 1
320
	cpfsgt	PRODL, ACCESS
321
	rgoto SID_VOICE_Get_L_Loop3
322
SID_VOICE_Get_L_NeverFound
323
	;; very strange error which should never happen!!! issue an reset for debugging purposes
324
	goto	MIOS_Reset
325
 
326
 
327
	;; ------------------------------------------------------------------
328
SID_VOICE_Get_R
329
	;; if number of voices <= 3, only take voice of left channel
330
	movlw	3
331
	cpfsgt	TABLAT, ACCESS
332
	rgoto SID_VOICE_Get_LR
333
 
334
	;; search in voice queue for free voice
335
	;; only Voice 4, 5 or 6 allowed!
336
	lfsr	FSR1, SID_VOICE_QUEUE_0
337
	clrf	PRODL
338
SID_VOICE_Get_R_Loop1
339
	movf	PRODL, W
340
	movff	PLUSW1, PRODH
341
	BRA_IFSET PRODH, 7, ACCESS, SID_VOICE_Get_R_Loop1_Next
342
	;; don't take voice if exclusively allocated
343
	movf	PRODL, W
344
	addlw	SID_VOICE_INSTR_OFFSET
345
	BRA_IFCLR PLUSW1, 6, ACCESS, SID_VOICE_Get_R_Loop1_Next
346
 
347
	;; check if voice >= 3
348
	movlw	3
349
	cpfslt	PRODH, ACCESS
350
	rgoto SID_VOICE_Get_Found
351
SID_VOICE_Get_R_Loop1_Next
352
	incf	PRODL, F
353
	movlw	SID_VOICE_QUEUE_LEN - 1
354
	cpfsgt	PRODL, ACCESS
355
	rgoto SID_VOICE_Get_R_Loop1
356
SID_VOICE_Get_R_NotFound
357
 
358
 
359
	;; no free voice found, take first note in queue w exclusive check
360
	;; it must be >= 3
361
	clrf	PRODL
362
SID_VOICE_Get_R_Loop2
363
	movf	PRODL, W
364
	addlw	SID_VOICE_INSTR_OFFSET
365
	BRA_IFCLR PLUSW1, 6, ACCESS, SID_VOICE_Get_R_Loop2_Next
366
 
367
	movf	PRODL, W
368
	movf	PLUSW1, W
369
	andlw	0x7f
370
	movwf	PRODH
371
	movlw	3
372
	cpfslt	PRODH, ACCESS
373
	rgoto SID_VOICE_Get_Found
374
SID_VOICE_Get_R_Loop2_Next
375
	incf	PRODL, F
376
	movlw	SID_VOICE_QUEUE_LEN - 1
377
	cpfsgt	PRODL, ACCESS
378
	rgoto SID_VOICE_Get_R_Loop2
379
 
380
 
381
	;; no free voice found, take first note in queue w/o exclusive check
382
	;; it must be >= 3
383
	clrf	PRODL
384
SID_VOICE_Get_R_Loop3
385
	movf	PRODL, W
386
	movf	PLUSW1, W
387
	andlw	0x7f
388
	movwf	PRODH
389
	movlw	3
390
	cpfslt	PRODH, ACCESS
391
	rgoto SID_VOICE_Get_Found
392
	incf	PRODL, F
393
	movlw	SID_VOICE_QUEUE_LEN - 1
394
	cpfsgt	PRODL, ACCESS
395
	rgoto SID_VOICE_Get_R_Loop3
396
SID_VOICE_Get_R_NeverFound
397
	;; very strange error which should never happen!!! issue an reset for debugging purposes
398
	goto	MIOS_Reset
399
 
400
 
401
	;; ------------------------------------------------------------------
402
	;; ------------------------------------------------------------------
403
	;; free voice found - remember index | 0x80
404
SID_VOICE_Get_Found
405
	;; entry point for SID_Voice_GetLast if selected voice has been found and is not allocated
406
SID_VOICE_GetLast_Cont
407
	movf	PRODL, W	; mask as allocated
408
	bsf	PLUSW1, 7
409
	movff	PLUSW1, PRODH
410
 
411
	;; if this is not already the last voice in the queue, shift queue and put the number to the end
412
	movf	PRODL, W
413
	xorlw	SID_VOICE_QUEUE_LEN - 1
414
	bz	SID_VOICE_Get_End
415
	;; remember instrument setting in SID_CURRENT_VOICE (dirty!!! but we know that this register will be overwritten later)
416
	;; this is required to hold the exclusive allocation flag
417
	movf	PRODL, W
418
	addlw	SID_VOICE_INSTR_OFFSET
419
	movff	PLUSW1, SID_CURRENT_VOICE
420
 
421
SID_VOICE_Get_Loop2
422
	incf	PRODL, W
423
	movff	PLUSW1, TABLAT
424
	addlw	-1
425
	movff	TABLAT, PLUSW1
426
 
427
	incf	PRODL, W
428
	addlw	SID_VOICE_INSTR_OFFSET
429
	movff	PLUSW1, TABLAT
430
	addlw	-1
431
	movff	TABLAT, PLUSW1
432
 
433
	incf	PRODL, F
434
	movlw	SID_VOICE_QUEUE_LEN - 2
435
	cpfsgt	PRODL, ACCESS
436
	rgoto SID_VOICE_Get_Loop2
437
 
438
	;; put voice number at the end of the voice queue
439
 	movlw	SID_VOICE_QUEUE_LEN - 1
440
	movwf	PRODL
441
	movff	PRODH, PLUSW1
442
 
443
	;; put instrument number at the end of the instrument queue
444
	;; this is required to hold the exclusive allocation flag
445
	;; (the usage of SID_CURRENT_VOICE is dirty!!! but we know that this register will be overwritten later)
446
	movlw	SID_VOICE_INSTR_OFFSET + SID_VOICE_QUEUE_LEN - 1
447
	movff	SID_CURRENT_VOICE, PLUSW1
448
 
449
SID_VOICE_Get_End
450
	;; store the instrument number which allocates the voice
451
	movf	PRODL, W
452
	addlw	SID_VOICE_INSTR_OFFSET
453
	movf	PLUSW1, W
454
	andlw	0x40		; (don't touch exclusive allocation flag)
455
	iorwf	SID_CURRENT_MIDIVOICE, W, BANKED
456
	movwf	TABLAT
457
	movf	PRODL, W
458
	addlw	SID_VOICE_INSTR_OFFSET
459
	movff	TABLAT, PLUSW1
460
 
461
	;; voice number -> SID_CURRENT_VOICE
462
	movf	PRODH, W
463
	andlw	0x7f
464
	movff	WREG, SID_CURRENT_VOICE
465
 
466
	;; create base pointer to voice
467
	lfsr	FSR1, SIDL_V1_BASE
468
	mullw	SID_Vx_RECORD_LEN
469
	movf	PRODL, W
470
	addwf	FSR1L, F
471
	movf	PRODH, W
472
	addwfc	FSR1H, F
473
	return
474
 
475
 
476
;; --------------------------------------------------------------------------
477
;;  This function searches for a given voice. If it is already allocated,
478
;;  it continues at SID_VOICE_Get, otherwise it returns the pointer to
479
;;  the selected voice
480
;;  IN:  o selected voice in WREG
481
;;       o voice assignment mode in SID_CURRENT_VOICE_ASSG[2:0]
482
;;       o number of voices (1..6) in SID_CURRENT_VOICE_ASSG[6:4]
483
;;       o SID_CURRENT_MIDIVOICE: the instrument (criteria for equal voice)
484
;;  OUT: o SID_CURRENT_VOICE contains the index of the found voice
485
;;       o FSR1 contains the base pointer to the found voice
486
;;  USES: PROD[LH], TABLAT, FSR1
487
;; --------------------------------------------------------------------------
488
SID_VOICE_GetLast
489
	movwf	PRODH		; save voice in PRODH
490
 
491
	SET_BSR	SID_BASE
492
 
493
SID_VOICE_GetLast_SearchVoice
494
	;; search in voice queue for selected voice
495
	lfsr	FSR1, SID_VOICE_QUEUE_0
496
	clrf	PRODL
497
SID_VOICE_GetLast_Loop1
498
	movf	PRODL, W
499
	movf	PLUSW1, W
500
	andlw	0x7f
501
	xorwf	PRODH, W
502
	bz	SID_VOICE_GetLast_Found
503
	incf	PRODL, F
504
	movlw	SID_VOICE_QUEUE_LEN - 1
505
	cpfsgt	PRODL, ACCESS
506
	rgoto SID_VOICE_GetLast_Loop1
507
 
508
SID_VOICE_GetLast_NotFound
509
	;; selected voice not found, continue at SID_VOICE_Get
510
	rgoto	SID_VOICE_Get
511
 
512
SID_VOICE_GetLast_Found
513
	;; selected voice found
514
	;; if instrument number not equal, we should get a new voice
515
	movf	PRODL, W
516
	addlw	SID_VOICE_INSTR_OFFSET
517
	movf	PLUSW1, W
518
	andlw	0x3f
519
	xorwf	SID_CURRENT_MIDIVOICE, W, BANKED
520
	bnz	SID_VOICE_GetLast_NotFound
521
 
522
	;; if number of available voices has changed in meantime (e.g. Stereo->Mono switch):
523
	;; check that voice number still < n
524
	swapf	SID_CURRENT_VOICE_ASSG, W, BANKED
525
	andlw	0x07
526
	cpfslt	PRODH, ACCESS
527
	rgoto SID_VOICE_GetLast_NotFound
528
 
529
SID_VOICE_GetLast_FoundGroup
530
	;; it's mine!
531
	;; continue at queue handling
532
	rgoto	SID_VOICE_GetLast_Cont
533
 
534
 
535
;; --------------------------------------------------------------------------
536
;;  This function releases a voice, so that it is free for SID_VOICE_Get
537
;;  IN:  o voice which should be released in SID_CURRENT_VOICE
538
;;  OUT: o FSR1 contains the base pointer to the voice
539
;;  USES: BSR, PROD[LH], TABLAT, FSR1
540
;; --------------------------------------------------------------------------
541
SID_VOICE_Release
542
	;; search in voice queue for the voice
543
	lfsr	FSR1, SID_VOICE_QUEUE_0
544
	clrf	PRODL
545
SID_VOICE_Release_Loop
546
	movf	PRODL, W
547
	movf	PLUSW1, W
548
	andlw	0x7f
549
	xorwf	SID_CURRENT_VOICE, W, BANKED
550
	bz	SID_VOICE_Release_Found
551
	incf	PRODL, F
552
	movlw	SID_VOICE_QUEUE_LEN - 1
553
	cpfsgt	PRODL, ACCESS
554
	rgoto SID_VOICE_Release_Loop
555
 
556
SID_VOICE_Release_NotFound
557
	;; very strange error which should never happen!!! issue an reset for debugging purposes
558
	goto	MIOS_Reset
559
 
560
SID_VOICE_Release_Found
561
	;; clear allocate marker
562
	movf	PRODL, W
563
	bcf	PLUSW1, 7
564
 
565
	;; create base pointer to voice
566
	lfsr	FSR1, SIDL_V1_BASE
567
	movf	SID_CURRENT_VOICE, W, BANKED
568
	mullw	SID_Vx_RECORD_LEN
569
	movf	PRODL, W
570
	addwf	FSR1L, F
571
	movf	PRODH, W
572
	addwfc	FSR1H, F
573
	return
574