forked from Tronix286/AIL2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMT32.INC
940 lines (756 loc) · 31.8 KB
/
MT32.INC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ MT32.INC ÛÛ
;ÛÛ ÛÛ
;ÛÛ IBM Audio Interface Library -- Roland MT-32-series MIDI interpreter ÛÛ
;ÛÛ ÛÛ
;ÛÛ Version 1.00 of 27-Sep-91: Initial version for AIL V2.0 release ÛÛ
;ÛÛ Version 1.01 of 12-Mar-92: Bad seq handles rejected by get_request ÛÛ
;ÛÛ ÛÛ
;ÛÛ 8086 ASM source compatible with Turbo Assembler v2.0 or later ÛÛ
;ÛÛ Author: John Miles ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;ÛÛ ÛÛ
;ÛÛ Copyright (C) 1991, 1992 Miles Design, Inc. ÛÛ
;ÛÛ ÛÛ
;ÛÛ Miles Design, Inc. ÛÛ
;ÛÛ 10926 Jollyville #308 ÛÛ
;ÛÛ Austin, TX 78759 ÛÛ
;ÛÛ (512) 345-2642 / FAX (512) 338-9630 / BBS (512) 454-9990 ÛÛ
;ÛÛ ÛÛ
;ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
;
;Driver-specific configuration equates
;
MAX_REC_CHAN equ 10 ;Max channel recognized by synths
MAX_TRUE_CHAN equ 9 ;Max channel available for locking
MIN_TRUE_CHAN equ 2 ;Min channel # (1-based)
SYSEX_SIZE equ 32 ;Controller sysex queue size in bytes
SYSEX_Q_CNT equ 3 ;# of sysex controller queues
DEF_SYNTH_VOL equ 90 ;init vol=90% (avoid MT-32 distortion)
CLEAR_SYNTH equ TRUE ;TRUE to reset Roland on init/shutdown
ADJUST_PART_RSV equ TRUE ;TRUE to set AIL partial reserve
;
;Driver Description Table (DDT)
;Returned by describe_driver() proc
;
DDT LABEL WORD
min_API_version dw 200 ;Minimum API version required = 2.00
drvr_type dw 3 ;Type 3: XMIDI driver
data_suffix db 'MT',0,0 ;Native data/instrument file suffix
device_name_o dw OFFSET devnames ;Pointer to list of supported devices
device_name_s dw ?
default_IO LABEL WORD
IFDEF MPU401
dw 330h ;Factory default I/O parameters
ELSEIFDEF SBMIDI
dw 220h
ENDIF
default_IRQ dw -1
default_DMA dw -1
default_DRQ dw -1
service_rate dw QUANT_RATE ;Typically 120 calls/second
display_size dw 20 ;20 char LCD display (MT-32)
devnames db 'Roland MT-32 or compatible with Roland MPU MIDI Interface',0
db 'Roland LAPC-1',0
db 0 ;0 to end list of device names
;
;Default setup values & constants
;
init_reverb db 0,3,2 ;reverb mode = 0, time = 3, level = 2
part_chans db 1,2,3,4,5,6,7,8,9 ;default (0-based) chans for each part
part_rsv db 3,4,3,4,3,4,3,4,4 ;# of reserved AIL partials/channel
NUM_TIMBS equ 64 ;# of RAM timbres
SYSEX_BLK_SIZE = (FINAL_BYTE_1 - START_MSB_1) + 1
SYSEX_RANGE_BEG = START_MSB_1
SYSEX_RANGE_END = SYSEX_RANGE_BEG + (SYSEX_BLK_SIZE * SYSEX_Q_CNT) - 1
;
;Misc. data
;
patch_bank db 128 dup (?)
chksum dw ?
string_buf db 32 dup (?)
sysex_queues db SYSEX_SIZE*SYSEX_Q_CNT dup (?)
M_ad db SYSEX_Q_CNT dup (?)
K_ad db SYSEX_Q_CNT dup (?)
L_ad db SYSEX_Q_CNT dup (?)
queue_ptrs db SYSEX_Q_CNT dup (?)
note_event_l dw ? ;used for LRU counting
note_event_h dw ?
timb_hist_l dw NUM_TIMBS dup (?) ;last note event count for LRU
timb_hist_h dw NUM_TIMBS dup (?)
timb_bank db NUM_TIMBS dup (?) ;GTR bank
timb_num db NUM_TIMBS dup (?) ;GTR #
timb_attribs db NUM_TIMBS dup (?) ;bit 7=in use 6=protected
chan_timbs db NUM_CHANS dup (?) ;indexes used by channels 1-16
;(-1 if internal/uninit'd)
MIDI_bank db NUM_CHANS dup (?) ;Patch Bank Select values
MIDI_program db NUM_CHANS dup (?) ;program change # / channel
IFDEF MPU401
INCLUDE mpu401.inc ;Roland MPU-401-compatible interface
ENDIF
IFDEF SBMIDI
INCLUDE sbmidi.inc ;Sound Blaster MIDI port
ENDIF
;****************************************************************************
;* *
;* MIDI interpreter and related procedures *
;* *
;****************************************************************************
reset_synth PROC
USES ds,si,di
pushf
cli
IF CLEAR_SYNTH ;reset all internal parameters/patches
call send_sysex_msg C,0,7fh,00h,00h,OFFSET part_chans,cs,1,12
ENDIF
;init part/channel assignments
call send_sysex_msg C,0,10h,00h,0dh,OFFSET part_chans,cs,9,4
POP_F
ret
ENDP
;****************************************************************************
init_synth PROC
USES ds,si,di
pushf
cli
;send adjusted partial reserve table
IF ADJUST_PART_RSV ;to avoid dropout on high channel #s
call send_sysex_msg C,0,10h,00h,04h,OFFSET part_rsv,cs,9,4
ENDIF
call send_sysex_msg C,0,10h,00h,01h,OFFSET init_reverb,cs,3,4
mov bx,0
__init_sysex: mov queue_ptrs[bx],0
inc bx
cmp bx,SYSEX_Q_CNT
jne __init_sysex
mov note_event_l,0
mov note_event_h,0
mov di,0
__init_tcache: mov timb_attribs[di],00000000b
inc di
cmp di,NUM_TIMBS
jne __init_tcache
mov di,0
__init_tchans: mov chan_timbs[di],-1
mov MIDI_program[di],-1
mov MIDI_bank[di],0
inc di
cmp di,NUM_CHANS
jne __init_tchans
mov di,0
__init_patches: mov patch_bank[di],0
inc di
cmp di,128
jne __init_patches
POP_F
ret
ENDP
;****************************************************************************
add_sysex_addr PROC Addend,MSB:BYTE,KSB:BYTE,LSB:BYTE
USES ds,si,di ;Add value to 21-bit address
mov al,[LSB]
mov bl,[KSB]
mov cl,[MSB]
mov ah,0
mov bh,0
mov ch,0
add ax,[Addend]
__chk_l: cmp ax,80h
jb __chk_k
sub ax,80h
inc bx
jmp __chk_l
__chk_k: cmp bx,80h
jb __store_sum
sub bx,80h
inc cx
jmp __chk_k
__store_sum: mov ah,bl
mov dl,cl
mov dh,0
ret
ENDP
;****************************************************************************
send_MIDI_sysex PROC Src:FAR PTR,Type,Len
USES ds,si,di ;Send MIDI System Exclusive message
cld
cmp [Type],0f0h ;F0 type?
jne __get_msg_len ;no, don't send explicit F0
call send_byte C,0f0h
__get_msg_len: lds si,[Src]
mov cx,[Len] ;get length
jcxz __exit
__send_bytes: push cx
lodsb
call send_byte C,ax
pop cx
loop __send_bytes
__exit: ret
ENDP
;****************************************************************************
sysex_wait PROC Delay ;Delay after System Exclusive message
USES ds,si,di ;transmissions
mov ax,40h ;wait n VBL periods (14 ms/period min,
mov ds,ax ;requires CGA/EGA/VGA/XGA video)
mov dx,ds:[63h] ;get CRTC Address register location
add dl,6 ;get CRTC Status register location
mov cx,[Delay]
jcxz __exit
__sync_1: in al,dx
test al,8
jz __sync_1
__sync_2: in al,dx
test al,8
jnz __sync_2
loop __sync_1
__exit: ret
ENDP
;****************************************************************************
write_system PROC Index,Value
USES ds,si,di ;Write value to System area
;(Warning: No delay!)
mov ax,[Index]
lea bx,[Value]
call send_sysex_msg C,0,10h,0,ax,bx,ss,1,0
ret
ENDP
;****************************************************************************
write_rhythm_setup PROC Keynum,Offset,Value
USES ds,si,di ;Write value to Rhythm Setup area
mov ax,[Keynum]
sub ax,24
shl ax,1
shl ax,1
add ax,[Offset]
call add_sysex_addr C,ax,3,1,16
mov cl,ah
lea bx,[Value]
call send_sysex_msg C,0,dx,cx,ax,bx,ss,1,4
ret
ENDP
;****************************************************************************
write_patch PROC Patch,Index,Value,Size
USES ds,si,di ;Write byte or word to Patch area
mov ax,[Patch]
shl ax,1
shl ax,1
shl ax,1
add ax,[Index]
call add_sysex_addr C,ax,5,0,0
mov cl,ah
lea bx,[Value]
call send_sysex_msg C,0,dx,cx,ax,bx,ss,[Size],2
__exit: ret
ENDP
;****************************************************************************
send_MIDI_message PROC Stat:BYTE,D1:BYTE,D2:BYTE
LOCAL op ;Send MIDI Channel Voice message
USES ds,si,di
NOJUMPS
mov si,WORD PTR [D1]
and si,0ffh ;SI=data 1 / controller #
mov di,WORD PTR [Stat]
mov ax,di
and di,00fh ;DI=channel
and ax,0f0h ;AX=status
cmp ax,0b0h
je __go_cc
cmp ax,0c0h
je __prg_change
cmp ax,090h ;Note On (or Note Off)?
jne __send
add note_event_l,1 ;yes, update timbre cache LRU counters
adc note_event_h,0
mov bh,0
mov bl,chan_timbs[di]
cmp bl,-1
je __send
shl bx,1
mov ax,note_event_l
mov dx,note_event_h
mov timb_hist_l[bx],ax
mov timb_hist_h[bx],dx
__send: mov di,WORD PTR [Stat]
call send_byte C,di
call send_byte C,si
and di,0f0h
cmp di,0c0h
je __exit
cmp di,0d0h
je __exit
call send_byte C,WORD PTR [D2]
__exit: ret
JUMPS
__go_cc: jmp __ctrl_change
__prg_change: mov ax,si ;log current patch for channel
mov MIDI_program[di],al
mov ah,MIDI_bank[di]
cmp ah,patch_bank[si] ;changing patch's timbre bank?
je __set_index ;no, just log index & send message
push ax ;else send sysex message to associate
mov al,ah ;patch with timbre
call setup_patch C,si,ax
pop ax
__set_index: call index_timbre C,ax
mov chan_timbs[di],al
jmp __send
__ctrl_change: cmp si,SYSEX_RANGE_BEG
jb __send
cmp si,SYSEX_RANGE_END
jbe __sysex
cmp si,PATCH_REVERB
je __p_rev
cmp si,PATCH_BENDER
je __p_b_range
cmp si,REVERB_MODE
je __rev_mode
cmp si,REVERB_TIME
je __rev_time
cmp si,REVERB_LEVEL
je __rev_lvl
cmp si,PATCH_BANK_SEL
je __t_bank
cmp si,RHYTHM_KEY_TIMB
je __r_t_sel
cmp si,TIMBRE_PROTECT
je __t_prot
cmp si,CHAN_LOCK ;(lowest XMIDI control #)
jb __send
cmp si,SEQ_INDEX ;(highest XMIDI control #)
ja __send ;keep XMIDI controls out of
jmp __exit ;MIDI data stream for speed
__t_prot: mov bl,chan_timbs[di]
cmp bl,-1
je __exit
mov bh,0
mov al,timb_attribs[bx]
and al,10111111b
cmp [D2],64
jl __tprot
or al,01000000b
__tprot: mov timb_attribs[bx],al
jmp __exit
__t_bank: mov al,[D2]
mov MIDI_bank[di],al
jmp __exit
__p_rev: mov al,MIDI_program[di]
mov ah,0
cmp al,-1
je __exit
push ax
call write_patch C,ax,6,WORD PTR [D2],1
or di,0c0h
call send_byte C,di
pop ax
call send_byte C,ax
jmp __exit
__p_b_range: mov al,MIDI_program[di]
mov ah,0
cmp al,-1
je __exit
push ax
call write_patch C,ax,4,WORD PTR [D2],1
or di,0c0h
call send_byte C,di
pop ax
call send_byte C,ax
jmp __exit
__rev_mode: call write_system C,1,WORD PTR [D2]
jmp __exit
__rev_time: call write_system C,2,WORD PTR [D2]
jmp __exit
__rev_lvl: call write_system C,3,WORD PTR [D2]
jmp __exit
__r_t_sel: mov al,chan_timbs[di]
cmp al,-1
je __exit
mov ah,0
call write_rhythm_setup C,WORD PTR [D2],0,ax
jmp __exit
__sysex: sub si,SYSEX_RANGE_BEG
mov ax,si
mov cx,SYSEX_BLK_SIZE
mov dx,0
div cx
mov op,dx
mov bx,ax
mov al,[D2] ;BX=queue #, AL=data, DX=operation
cmp dx,0
je __set_MSB
cmp dx,1
je __set_KSB
cmp dx,2
je __set_LSB
mov ax,SYSEX_SIZE ;BX = queue #
mul bx
add ax,OFFSET sysex_queues
mov di,ax ;DI = base queue address
add al,queue_ptrs[bx]
adc ah,0
mov si,ax ;SI = pointer to last byte
mov al,[D2]
mov cs:[si],al
cmp op,3
je __bump_ptr ;inc ptr and exit if not final byte
__send_queue: mov al,queue_ptrs[bx] ;else send message
mov ah,0
inc ax
mov si,ax ;SI = len
xchg di,bx ;DI = queue #, CS:BX = base address
call send_sysex_msg C,0,WORD PTR M_ad[di],WORD PTR K_ad[di],\
WORD PTR L_ad[di],bx,cs,si,0
cmp op,3 ;was this an overflow dump?
jne __address_byte
call sysex_wait C,4 ;yes, do an automatic wait of 4
jmp __overflowed ;VBL intervals
__address_byte: dec si ;SI=len-1
__overflowed: call add_sysex_addr C,si,WORD PTR M_ad[di],WORD PTR K_ad[di],\
WORD PTR L_ad[di]
mov L_ad[di],al ;add (qlen-1) to sysex start address,
mov K_ad[di],ah ;so future Final Byte controllers will
mov M_ad[di],dl ;address same byte (unless overflowed)
mov queue_ptrs[di],0 ;flush queue
jmp __exit
__bump_ptr: cmp queue_ptrs[bx],SYSEX_SIZE-1
jae __send_queue ;dump queue if overflow occurs
inc queue_ptrs[bx]
jmp __exit
__set_MSB: mov M_ad[bx],al
jmp __exit
__set_KSB: mov K_ad[bx],al
jmp __exit
__set_LSB: mov L_ad[bx],al
jmp __exit
ENDP
;****************************************************************************
index_timbre PROC GNum ;Get global timbre's local index 0-63
USES ds,si,di
mov si,0
mov ax,[GNum]
__find_gnum: test timb_attribs[si],10000000b
jz __find_next ;(timbre unused)
cmp timb_bank[si],ah
jne __find_next
cmp timb_num[si],al
je __found
__find_next: inc si
cmp si,NUM_TIMBS
jb __find_gnum
mov si,-1 ;return -1 if timbre not loaded
__found: mov ax,si
ret
ENDP
;****************************************************************************
setup_patch PROC Patch:BYTE,Bank:BYTE
USES ds,si,di ;Establish patch's timbre setting
mov bl,[Patch]
mov bh,0
mov ah,[Bank]
mov patch_bank[bx],ah ;log timbre bank # for patch
cmp ah,0
je __bank_0 ;bank 0 = built-in Roland timbres
mov al,bl
call index_timbre C,ax ;see if timbre loaded
cmp ax,-1
je __bank_0 ;timbre not loaded, use default
mov ah,al ;select TIMBRE NUMBER 0-63
mov al,2 ;select MEMORY (timbre group 2)
jmp __send
__bank_0: mov ah,[Patch] ;restore default Roland timbre...
mov al,0
cmp ah,64 ;set GROUP A if patch # < 64
sbb al,-1 ;set GROUP B if patch # >= 64
and ah,63 ;set TIMBRE NUMBER 0-63
__send: call write_patch C,WORD PTR [Patch],0,ax,2
__exit: ret
ENDP
;****************************************************************************
;* *
;* Public (API-accessible) procedures *
;* *
;****************************************************************************
describe_driver PROC H,IntRateProc:FAR PTR
USES ds,si,di ;Return far ptr to DDT
pushf
cli
mov dx,cs
mov device_name_s,dx
lea ax,DDT
POP_F
ret
ENDP
;****************************************************************************
send_sysex_msg PROC H,AddrA:BYTE,AddrB:BYTE,AddrC:BYTE,Data:FAR PTR,Size,Wait
USES ds,si,di
pushf
cli
call send_byte C,0f0h ;transmit Roland MT-32 header
call send_byte C,041h
call send_byte C,010h
call send_byte C,016h
call send_byte C,012h
call send_byte C,WORD PTR [AddrA]
call send_byte C,WORD PTR [AddrB]
call send_byte C,WORD PTR [AddrC]
mov al,[AddrA] ;init checksum
mov ah,0
add al,[AddrB]
adc ah,0
add al,[AddrC]
adc ah,0
mov chksum,ax
les di,[Data] ;send each message byte
mov si,[Size]
__send_data: or si,si
jz __send_chksum
dec si
xor ah,ah
mov al,es:[di]
inc di
add chksum,ax
call send_byte C,ax
jmp __send_data
__send_chksum: mov ax,chksum
and ax,7fh
sub al,80h
neg al
and ax,7fh
call send_byte C,ax ;send the checksum byte
call send_byte C,0f7h ;send EOX terminator
call sysex_wait C,[Wait]
POP_F
ret
ENDP
;****************************************************************************
write_display PROC H,String:FAR PTR ;Write string to display (unless NULL)
USES ds,si,di
pushf
cli
cld
lds si,[String] ;bail out if null string
mov ax,ds
cmp ax,0
je __end_write
push cs ;pad string with spaces
pop es
lea di,string_buf
mov cx,display_size
mov al,' '
rep stosb
lea di,string_buf ;write up to /display_size/ characters
mov cx,display_size
__pad_string: lodsb
cmp al,0
je __show_it
stosb
loop __pad_string
__show_it: call send_sysex_msg C,0,20h,00h,00h,\
OFFSET string_buf,cs,display_size,4
__end_write: POP_F
ret
ENDP
;****************************************************************************
send_cv_msg PROC H,Stat,D1,D2 ;Send an explicit Channel Voice msg
USES ds,si,di
pushf
cli
call send_MIDI_message C,[Stat],[D1],[D2]
POP_F
ret
ENDP
;****************************************************************************
protect_timbre PROC H,Bank:BYTE,Num:BYTE
USES ds,si,di ;Protect a timbre from replacement
pushf
cli
mov al,[Num]
mov ah,[Bank]
cmp ax,-1
je __prot_all
call index_timbre C,ax
cmp ax,-1
je __exit ;timbre not loaded, can't protect it
mov bx,ax
or timb_attribs[bx],01000000b
jmp __exit
__prot_all: mov bx,0
__prot_timb: or timb_attribs[bx],01000000b
inc bx
cmp bx,NUM_TIMBS
jb __prot_timb
__exit: POP_F
ret
ENDP
;****************************************************************************
unprotect_timbre PROC H,Bank:BYTE,Num:BYTE
USES ds,si,di ;Allow a timbre to be replaced
pushf
cli
mov al,[Num]
mov ah,[Bank]
cmp ax,-1
je __unprot_all
call index_timbre C,ax
cmp ax,-1
je __exit ;timbre not loaded, can't unprotect it
mov bx,ax
and timb_attribs[bx],10111111b
jmp __exit
__unprot_all: mov bx,0
__unprot_timb: and timb_attribs[bx],10111111b
inc bx
cmp bx,NUM_TIMBS
jb __unprot_timb
__exit: POP_F
ret
ENDP
;****************************************************************************
timbre_status PROC H,Bank:BYTE,Num:BYTE
USES ds,si,di ;Return 0 if timbre not resident
pushf
cli
mov al,[Num]
mov ah,[Bank]
cmp ah,0 ;Roland driver reports all bank 0
je __OK ;(default) and bank 127 (rhythm)
cmp ah,127 ;timbres present
je __OK
call index_timbre C,ax
__OK: inc ax ;0 if -1, else local cache index
POP_F
ret
ENDP
;****************************************************************************
get_cache_size PROC H
USES ds,si,di
pushf
cli
mov ax,0 ;no resident cache for MT-32
POP_F
ret
ENDP
;****************************************************************************
define_cache PROC H,Addr:FAR PTR,Size
USES ds,si,di
ret
ENDP
;****************************************************************************
get_request PROC H,Sequence
USES ds,si,di
pushf
cli
mov si,[Sequence]
cmp si,-1
je __no_request
lds si,sequence_state[si]
cmp WORD PTR [si].TIMB+2,0
je __no_request ;no requested timbres, exit
lds si,[si].TIMB ;make sure TIMB chunk is present
cmp [si],'IT'
jne __no_request ;if not, no requests are possible
cmp [si+2],'BM'
jne __no_request
add si,8
mov di,[si] ;get TIMB.cnt
__chk_index: add si,2
mov ax,[si]
cmp ah,0 ;bank 0 reserved for Roland built-in
je __next_index ;timbres.... don't request
cmp ah,127 ;bank 127 reserved for melodic-mode
je __next_index ;rhythm sounds.... don't request
call index_timbre C,[si]
cmp ax,-1 ;timbre in local cache?
je __request ;no, request it
__next_index: dec di
jne __chk_index
jmp __no_request ;all requested timbres loaded, exit
__request: mov ax,[si] ;else return request: AL=num, AH=bank
jmp __exit
__no_request: mov ax,-1
__exit: POP_F
ret
ENDP
;****************************************************************************
install_timbre PROC H,Bank:BYTE,Num:BYTE,Addr:FAR PTR
LOCAL sys_seg,sys_dest
USES ds,si,di
pushf
cli
mov al,[Num]
mov ah,[Bank]
cmp ah,0 ;bank 0 reserved for built-in default
je __set_patch ;timbres -- restore normal patch
cmp ah,127 ;bank 127 reserved for melodic mode
je __exit ;rhythm sounds -- don't install
call index_timbre C,ax
cmp ax,-1
jne __set_patch ;timbre already resident, index it
mov ax,WORD PTR [Addr]
or ax,WORD PTR [Addr+2]
jz __exit
mov si,0 ;else look for an empty timbre slot
__find_free: test timb_attribs[si],10000000b
jz __found
inc si
cmp si,NUM_TIMBS
jb __find_free
mov si,0 ;no free timbre slots, replace least-
mov bx,0 ;recently-used unprotected timbre
mov cx,-1
mov ax,-1
mov dx,-1
__find_LRU: test timb_attribs[si],01000000b
jnz __next_LRU ;(timbre protected)
cmp timb_hist_h[bx],dx
ja __next_LRU
jb __log_LRU
cmp timb_hist_l[bx],ax
ja __next_LRU
__log_LRU: mov ax,timb_hist_l[bx]
mov dx,timb_hist_h[bx]
mov cx,si
__next_LRU: add bx,2
inc si
cmp si,NUM_TIMBS
jb __find_LRU
cmp cx,-1 ;if no unprotected timbre slots, exit
je __exit ;without installing new timbre
mov si,cx ;else SI = LRU timbre index
__found: mov bx,si ;found free/LRU timbre, update its
shl bx,1 ;timestamp and replace it
mov ax,note_event_l
mov dx,note_event_h
add note_event_l,1
adc note_event_h,0
mov timb_hist_l[bx],ax
mov timb_hist_h[bx],dx
mov al,[Num] ;AL=num, AH=bank
mov ah,[Bank]
mov timb_num[si],al ;record global # in slot
mov timb_bank[si],ah ;mark timbre "in use/unprotected"
mov timb_attribs[si],10000000b
cmp WORD PTR [Addr+2],0
je __exit ;(NULL pointer = placeholder)
les di,[Addr]
add di,2 ;skip timbre length prefix (norm. $F6)
mov ax,si ;set up to send timbre dump to Roland
shl ax,1 ;8,AX,00 = MT-32 address MSB,KSB,LSB
mov sys_seg,es ;send common parameter
mov sys_dest,ax
call send_sysex_msg C,0,8,sys_dest,0,di,sys_seg,0eh,3
add di,0eh ;send partial parameter #1
call send_sysex_msg C,0,8,sys_dest,0eh,di,sys_seg,3ah,3
add di,3ah ;send partial parameter #2
call send_sysex_msg C,0,8,sys_dest,48h,di,sys_seg,3ah,3
add di,3ah ;send partial parameter #3
inc sys_dest
call send_sysex_msg C,0,8,sys_dest,2,di,sys_seg,3ah,3
add di,3ah ;send partial parameter #4
call send_sysex_msg C,0,8,sys_dest,3ch,di,sys_seg,3ah,3
__set_patch: call setup_patch C,WORD PTR [Num],WORD PTR [Bank]
__exit: POP_F
ret
ENDP