home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip: Special Sound & MIDI
/
Chip-Special_Sound-und-Midi-auf-dem-PC.bin
/
midiprog
/
uplay.asm
< prev
next >
Wrap
Assembly Source File
|
1993-09-27
|
39KB
|
1,548 lines
title UPLAY - (U)ART - SMF1 PLAY Utility
page 64,132
.186
; ----------
; Allgemeine Definitionen
IS_NOPATCH equ 1
IS_OCTAVE equ 2
IS_TEST equ 4
IS_VERBOSE equ 8
IS_YAMAHA equ 16
IS_PLAY equ 32
STACKADDR equ 2000h
TRACKNAME equ 2200h
INSTRNAME equ 2800h
EVENTS equ 2e00h
PATCH equ 2f00h
CHANNEL equ 3000h
COUNTER equ 3200h
TRACKFLAGS equ 3800h
TRACKSTART equ 3a00h
MAX_TRACKS equ 64
code segment 'code'
assume cs:code,ds:code,es:code
org 100h
start : jmp anfang
; -----
; Texte
msg_hello db 'UPLAY - Uart Standard MIDI File Type 0/1 Play Utility'
db 13,10
db 'Version 1.00 - Copyright (c) 1993 by Andreas Nieden'
db 13,10,10,0
msg_help db 'Aufruf: UPLAY [-novy] Datei[.MID] ...'
msg_cr db 13,10,0
msg_fnf db 'UPLAY: Keine passende(n) Datei(en) gefunden'
db 13,10,0
msg_nosmf db 'UPLAY: Keine Standard-Midi Datei (Typ 0/1)'
db 13,10,0
msg_toomuch db 'UPLAY: Zuviele Tracks im SMF - ich gebe auf ...'
db 13,10,0
msg_invtbase db 'UPLAY: Ungültige Timebase'
db 13,10,0
msg_invtrack db 'UPLAY: Ungültige Trackkennung'
db 13,10,0
msg_invdelta db 'UPLAY: Ungültiges Timedelta im Track'
db 13,10,0
msg_trktoolong db 'UPLAY: Aktueller Track zu lang - ich gebe auf ...'
db 13,10,0
msg_eof db 'UPLAY: Unexpected EOF'
db 13,10,0
msg_smfFile db 'Aktuelle SMF-Datei: ',0
msg_title db 13,10
db 'Nr. Trackname Instrument Events Channel Patch'
db 13,10,0
msg_mult db ' MULT',0
; -------
; General MIDI Mapper
ALIGN 16
gm_map label byte
db 25h, 1 ; 001 Acoustic Grand Piano - TG33-AP:Piano
db 25h, 1 ; 002 Bright Acoustic Piano - TG33-AP:Piano
db 25h, 5 ; 003 Electric Grand Piano - TG33-EP:Pin
db 25h, 7 ; 004 Honky-Tonk - TG33-EP:Fosta
db 25h, 2 ; 005 Electric Piano 1 - TG33-EP:Malet
db 25h, 6 ; 006 Electric Piano 2 - TG33-EP*NewDX
db 25h, 13 ; 007 Harpsichord - TG33-KY:Hrpsi
db 25h, 15 ; 008 Clavi - TG33-KY:Clavi
db 25h, 14 ; 009 Celesta - TG33-KY*Celst
db 25h, 61 ; 010 Glockenspiel - TG33-PC:Vibes
db 25h, 60 ; 011 Music Box - TG33-PC:Marim
db 25h, 61 ; 012 Vibraphone - TG33-PC:Vibes
db 25h, 60 ; 013 Marimba - TG33-PC:Marim
db 25h, 60 ; 014 Xylophone - TG33-PC:Marim
db 25h, 62 ; 015 Tubular Bells - TG33-PC*Bells
db 25h, 8 ; 016 Dulcimer - TG33-OR*Gospl
db 25h, 8 ; 017 Drawbar Organ - TG33-OR*Gospl
db 25h, 11 ; 018 Percussive Organ - TG33-OR*Perc
db 25h, 9 ; 019 Rock Organ - TG33-OR*Rock
db 25h, 10 ; 020 Church Organ - TG33-OR*Pipe
db 25h, 35 ; 021 Reed Organ - TG33-BR*Reed
db 25h, 12 ; 022 Accordion - TG33-KY*Squez
db 22h, 37 ; 023 Harmonica - TG33-SL*Blues
db 25h, 12 ; 024 Tango Accordion - TG33-KY*Squez
db 25h, 30 ; 025 Acoustic Guitar (Nylon) - TG33-PL*Nylon
db 25h, 27 ; 026 Acoustic Guitar (Steel) - TG33-PL*Foksy
db 25h, 30 ; 027 Electric Guitar (JAZZ ) - TG33-PL*Nylon
db 22h, 32 ; 028 Electric Guitar (Clean) - TG33-SL*Sync
db 22h, 33 ; 029 Electric Guitar - TG33-SL*VCO
db 25h, 31 ; 030 Overdriven Guitar - TG33-PL*Dist
db 25h, 31 ; 031 Distortion Guitar - TG33-PL*Dist
db 25h, 27 ; 032 Guitar harmonics - TG33-PL*12Str
db 25h, 20 ; 033 Acoustic Bass - TG33-BA*Pick
db 25h, 24 ; 034 Electric Bass (Finger ) - TG33-BA*Fingr
db 25h, 20 ; 035 Electric Bass (Pick ) - TG33-BA*Pick
db 25h, 25 ; 036 Fretless Bass - TG33-BA*Frtls
db 25h, 16 ; 037 Slap Bass 1 - TG33-BA*Slap
db 25h, 16 ; 038 Slap Bass 2 - TG33-BA*Slap
db 25h, 21 ; 039 Synth Bass 1 - TG33-BA*Syn
db 25h, 22 ; 040 Synth Bass 2 - TG33-BA*Rezz
db 20h, 14 ; 041 Violin - TG33-ST:Viola
db 25h, 14 ; 042 Viola - TG33-ST:Viola
db 25h, 13 ; 043 Cello - TG33-ST:Cello
db 25h, 52 ; 044 Contrabass - TG33-ST*Celst
db 25h, 53 ; 045 Tremolo Strings - TG33-ST*Exel
db 25h, 51 ; 046 Pizzicato Strings - TG33-ST:Pizza
db 25h, 14 ; 047 Orchestral Harp - TG33-KY*Celst
db 20h, 7 ; 048 Timpani - TG33-PC*Timpa
db 25h, 49 ; 049 String Ensemble 1 - TG33-ST:Chmbr
db 25h, 49 ; 050 String Ensemble 2 - TG33-ST:Chmbr
db 25h, 54 ; 051 SynthStrings 1 - TG33-ST:Synth
db 25h, 54 ; 052 SynthStrings 2 - TG33-ST:Synth
db 25h, 58 ; 053 Choir Aa's - TG33-CH:Itopy
db 25h, 56 ; 054 Voice Ooh's - TG33-CH*Modrn
db 25h, 59 ; 055 Synth Voice - TG33-CH*Astiz
db 22h, 42 ; 056 Orchestra Hit - TG33-PC*Hit+
db 25h, 41 ; 057 Trumpet - TG33-BR*Trmpt
db 25h, 42 ; 058 Trombone - TG33-BR*Tromb
db 25h, 42 ; 059 Tuba - TG33-BR*Tromb
db 25h, 38 ; 060 Muted Trump - TG33-BR*Moot
db 25h, 40 ; 061 French Horn - TG33-BR:FrHrn
db 25h, 33 ; 062 Brass Section - TG33-BR*Fanfr
db 25h, 36 ; 063 SynthBrass 1 - TG33-BR*Chill
db 25h, 34 ; 064 SynthBrass 2 - TG33-BR*Class
db 25h, 43 ; 065 Soprano Sax - TG33-WN*Sax
db 25h, 43 ; 066 Alto Sax - TG33-WN*Sax
db 25h, 43 ; 067 Tenor Sax - TG33-WN*Sax
db 25h, 43 ; 068 Baritone Sax - TG33-WN*Sax
db 25h, 45 ; 069 Oboe - TG33-WN:Oboe
db 25h, 40 ; 070 Englisch Horn - TG33-WN:FrHrn
db 25h, 45 ; 071 Bassoon - TG33-WN:Oboe
db 25h, 46 ; 072 Clarinet - TG33-WN:Clart
db 25h, 47 ; 073 Piccolo - TG33-WN:Flute
db 25h, 47 ; 074 Flute - TG33-WN:Flute
db 22h, 36 ; 075 Recorder - TG33-SL*Wisul
db 25h, 44 ; 076 Pan Flute - TG33-WN:Pan
db 25h, 44 ; 077 Blown Bottle - TG33-WN:Pan
db 25h, 44 ; 078 Shakuhashi - TG33-WN:Pan
db 22h, 36 ; 079 Whistle - TG33-SL:Wisul
db 22h, 36 ; 080 Ocarina - TG33-SL:Wisul
db 22h, 33 ; 081 Lead 1 (square) - TG33-SL:VCO
db 22h, 34 ; 082 Lead 2 (sawtooth) - TG33-SL:Chic
db 22h, 39 ; 083 Lead 3 (calliope) - TG33-SL:Super
db 25h, 39 ; 084 Lead 4 (Chiff) - TG33-BR*Anlog
db 25h, 32 ; 085 Lead 5 (charang) - TG33-BR*Power
db 25h, 59 ; 086 Lead 6 (voice) - TG33-CH*Astiz
db 22h, 34 ; 087 Lead 7 (fifths) - TG33-SL:VCO
db 22h, 39 ; 088 Lead 8 (BASSLead) - TG33-SL:Super
db 22h, 41 ; 089 Pad 1 (new age) - TG33-ME*NuAge
db 22h, 13 ; 090 Pad 2 (warm) - TG33-SP*Quire
db 22h, 14 ; 091 Pad 3 (polysynth) - TG33-SP*Digit
db 22h, 13 ; 092 Pad 4 (choir) - TG33-SP:Quire
db 22h, 22 ; 093 Pad 5 (bowed) - TG33-SC:Decay
db 22h, 46 ; 094 Pad 6 (metallic) - TG33-ME*Hitch
db 22h, 33 ; 095 Pad 7 (halo) - TG33-SL:VCO
db 22h, 19 ; 096 Pad 8 (sweep) - TG33-SC:Sweep
db 22h, 54 ; 097 FX 1 (rain) - TG33-Neuro
db 22h, 44 ; 098 FX 2 (soundtrack) - TG33-Astro
db 22h, 25 ; 099 FX 3 (crystal) - TG33-Bellz
db 22h, 4 ; 100 FX 4 (atmosphere) - TG33-Ice
db 22h, 7 ; 101 FX 5 (brightness) - TG33-BrVec
db 22h, 8 ; 102 FX 6 (goblins) - TG33-Matrx
db 22h, 1 ; 103 FX 7 (echoes) - TG33-Echo
db 22h, 3 ; 104 FX 8 (scifi) - TG33-Full
db 22h, 23 ; 105 Sitar - TG33-Steel
db 22h, 23 ; 106 Banjo - TG33-Steel
db 22h, 23 ; 107 Shamisen - TG33-Steel
db 22h, 23 ; 108 Koto - TG33-Steel
db 22h, 3 ; 109 Kalimba - TG33-Full
db 22h, 36 ; 110 Bag Pipe - TG33-Wisul
db 20h, 14 ; 111 Fiddle - TG33-Viola
db 22h, 14 ; 112 Shanai - TG33-Viola
db 25h, 63 ; 113 Tinkle Bell - TG33-Clang
db 22h, 3 ; 114 Agogo - TG33-Full
db 22h, 3 ; 115 Steel Drums - TG33-Full
db 25h, 26 ; 116 Woodblock - TG33-Wood
db 22h, 3 ; 117 Taiko Drums - TG33-Full
db 22h, 3 ; 118 Melodic Tom - TG33-Full
db 22h, 3 ; 119 Synth Drum - TG33-Full
db 22h, 3 ; 120 Reverse Cymbal - TG33-Full
db 22h, 9 ; 121 Guitar Fret Noise - TG33-Gut
db 22h, 53 ; 122 Breath Noise - TG33-Hades
db 22h, 48 ; 123 Seashore - TG33-Mount
db 22h, 61 ; 124 BirdTweet - TG33-Devol
db 22h, 61 ; 125 Telephone Ring - TG33-Devol
db 22h, 61 ; 126 Helicopter - TG33-Devol
db 22h, 54 ; 127 Applause - TG33-Neuro
db 22h, 61 ; 128 Gunshot - TG33-Devol
; ---------
; Variablen
; Doppelwortvariablen
ALIGN 4
timedelta dd 0
oldvec08 dd 0
; -------------
; Wortvariablen
trackseg dw MAX_TRACKS dup (0) ; Segmente der Tracks
trackaddr dw MAX_TRACKS dup (0) ; Trackadressen
stellen dw 8
fileaddr dw 0
shandle dw 0
tracks dw 0 ; Anzahl der Gesamttracks
atracks dw 0 ; Aktive Tracks
tracklen dw 0 ; Länge des Aktuellen Tracks
timebase dw 0 ; Timebase des SMF's
tempo dw 120 ; Current Tempo
org_cnt dw 0
int_cnt dw 0
save_bx dw 0
; -------------
; Bytevariablen
u2flag db 0
; -------------
; Textvariablen
smf_ext db '.MID',0
drums db 0b9h, 0,0, 0b9h, 20h, 22h, 0c9h, 62
options db 'NOTVY',0
; ---------
; Utilities
ALIGN 16
; ------
; timint - Clock Interupt Routine
timint : test cs:u2flag,IS_PLAY
jnz timi10
tim_far proc far
jmp cs:oldvec08
tim_far endp
timi10 : push ax
pusha
push ds
push es
mov ax,cs
mov ds,ax
mov es,ax
cld
timi20 : call tmain
timi30 : pop es
pop ds
popa
timi40 : inc cs:int_cnt
mov ax,cs:int_cnt
cmp ax,cs:org_cnt
jb timi50
mov cs:int_cnt,0
pop ax
jmp short tim_far
timi50 : mov al,20h
out 20h,al
pop ax
iret
; -------
; timiset - Setzt den Timer auf das neue Tempo
timiset: pushf
push bx
push dx
cli
mov al,36h
out 43h,al
mov bx,tempo
shl bx,1
mov ax,34dch
mov dx,12h
div bx
push ax
out 40h,al
mov al,ah
out 40h,al
pop bx
xor ax,ax
mov dx,1
div bx
mov org_cnt,ax
mov int_cnt,0
pop dx
pop bx
popf
ret
; -------
; timrest - Zurücksetzen Real Time Clock + Interrupts
timrest: push ds
lds dx,oldvec08
mov ax,2508h
int 21h
pop ds
cli
mov al,36h
out 43h,al
xor ax,ax
out 40h,al
mov al,ah
out 40h,al
sti
call settimer
ret
; ------
; rtimer
rtimer : pushf
cli
push dx
mov dx,70h
out dx,al
inc dx
in al,dx
pop dx
popf
ret
bcd : mov bl,al
shr al,1
shr al,1
shr al,1
shr al,1
mov ah,0ah
mul ah
and bl,0fh
add al,bl
ret
settimer:mov al,4
call rtimer
call bcd
mov ch,al
mov al,2
call rtimer
call bcd
mov cl,al
mov al,0
call rtimer
call bcd
mov dh,al
mov dl,0
mov ah,2dh
int 21h
ret
; -------
; wstring
wstring: push ax
push si
wstr100: lodsb
or al,al
jz wstr200
call wchar
jmp short wstr100
wstr200: pop si
pop ax
ret
wchar : push ax
push dx
mov dl,al
mov ah,2
int 21h
pop dx
pop ax
ret
; ------
; werror
werror : push bx
push cx
push si
xor cx,cx
mov dx,si
werr10 : lodsb
or al,al
jz werr20
inc cx
jmp short werr10
werr20 : mov ax,4000h
mov bx,2
int 21h
pop si
pop cx
pop bx
ret
dz : push ax
push bx
push cx
push dx
xor cx,cx
de100 : call dv
push bx
inc cx
or ax,ax
jnz de100
or dx,dx
jnz de100
mov bx,stellen
de200 : cmp bx,cx
jz de300
mov al,' '
call wchar
dec bx
jmp short de200
de300 : pop ax
or al,'0'
call wchar
loop de300
pop dx
pop cx
pop bx
pop ax
ret
dv : push cx
xor bx,bx
mov cx,20h
dv10 : shl ax,1
rcl dx,1
rcl bx,1
sub bx,10
jnb dv20
add bx,10
add ax,1
adc dx,0
dv20 : loop dv10
not ax
not dx
pop cx
ret
toupper: cmp al,'a'
jb tou_ex
cmp al,'z'
ja tou_ex
and al,not 32
tou_ex : ret
hexw : xchg al,ah
call hexb
xchg al,ah
hexb : push ax
push cx
mov ah,al
mov cl,4
shr al,cl
call hexb500
mov al,ah
and al,15
call hexb500
pop cx
pop ax
ret
hexb500: add al,'0'
cmp al,'9'
jbe hexb600
add al,7
hexb600: call wchar
ret
; -----
; ludiv - Long Unsigned Division
; Eingabe: Dividend in AX:DX
; Divisor in CX:BX
; Ausgabe: Quotient in AX:DX
; Rest in CX:BX
ludiv : test bx,bx
jnz lud200
cmp cx,dx
ja lud100
push ax
mov ax,dx
sub dx,dx
div cx
mov bx,ax
pop ax
div cx
mov cx,dx
mov dx,bx
sub bx,bx
ret
lud100 : div cx
mov cx,dx
mov dx,bx
ret
lud200 : push bp
push di
push si
mov si,cx
mov di,bx
sub bx,bx
sub bp,bp
mov cx,32
lud220 : shl ax,1
rcl dx,1
rcl bp,1
rcl bx,1
sub bp,si
sbb bx,di
js lud280
lud240 : inc ax
loop lud220
jmp short lud300
lud260 : shl ax,1
rcl dx,1
rcl bp,1
rcl bx,1
add bp,si
adc bx,di
jns lud240
lud280 : loop lud260
add bp,si
adc bx,di
lud300 : mov cx,bp
pop si
pop di
pop bp
ret
; -----
; wtick - Wartet für einen Timertick ...
wtick : push ax
push bx
push cx
push dx
sti
xor ax,ax
int 1ah
mov bx,dx
wtick10: xor ax,ax
int 1ah
cmp dx,bx
jz wtick10
pop dx
pop cx
pop bx
pop ax
ret
; ------
; alloff - ALL OFF über ACK !
alloff : mov al,0feh
call put_midi
mov cx,24
alloff10:call wtick
loop alloff10
mov cx,16
mov ah,0
alloff20:mov al,0b0h
or al,ah
call put_midi
mov al,79h
call put_midi
mov al,0
call put_midi
inc ah
loop alloff20
ret
; -------
; waitrcv Wait For MPU Receive Ready
waitrcv: push ax
push dx
mov dx,0331h
waitr10: in al,dx
test al,40h
jnz waitr10
pop dx
pop ax
ret
; --------
; put_midi Ausgabe eines MidiBytes
put_midi:push ax
push dx
call waitrcv
mov dx,0330h
pushf
cli
out dx,al
popf
pop dx
pop ax
ret
; -------
; put_cmd Ausgabe eines MPU-Kommandos
put_cmd: push ax
push cx
push dx
call waitrcv
pushf
cli
mov dx,0331h
out dx,al
mov cx,4000h
put_c20: in al,dx
test al,80h
jz put_c30
loop put_c20
mov ax,0e07h
int 10h
jmp ende
put_c30: dec dx
in al,dx
inc dx
cmp al,0feh
jnz put_c20
put_c90: popf
pop dx
pop cx
pop ax
ret
; -------
; resetmpu Reset MPU
resetmpu:push ax
push dx
call waitrcv
pushf
cli
mov dx,0331h
mov al,0ffh
out dx,al
call waitrcv
dec dx
in al,dx
popf
pop dx
pop ax
ret
; -------
; parscmd - Die Kommandozeile untersuchen
parscmd: lea si,msg_hello
call werror
mov si,80h
lodsw
or al,al
jnz pars100
helpexit:lea si,msg_help
err_exit:call werror
mov al,1
jmp ende
pars100: call pars500
jb helpexit
cmp byte ptr [si],'-'
jz pars120
cmp byte ptr [si],'/'
jnz pars200
pars120: lodsw
mov al,ah
pars130: call toupper
lea di,options
mov bl,1
pars140: cmp byte ptr [di],0
jz helpexit
scasb
jz pars160
shl bl,1
jmp short pars140
pars160: or u2flag,bl
cmp byte ptr [si],' '
jz pars100
cmp byte ptr [si],9
jz pars100
cmp byte ptr [si],13
jz helpexit
lodsb
jmp short pars130
pars200: lea di,filename
mov fileaddr,di
mov bl,0 ; BL kennzeichnet "."
pars220: lodsb
cmp al,13
jz pars300
cmp al,'.'
jnz pars240
inc bl
pars240: call toupper
stosb
cmp al,'\'
jz pars260
cmp al,':'
jnz pars220
pars260: mov fileaddr,di
jmp short pars220
pars300: or bl,bl
jnz pars320
lea si,smf_ext
mov cx,5
rep movsb
ret
pars320: mov al,0
stosb
ret
pars500: cmp byte ptr [si],' '
jz pars540
cmp byte ptr [si],9
jz pars540
cmp byte ptr [si],13
jnz pars520
stc
ret
pars520: clc
ret
pars540: inc si
jmp short pars500
; --------
; getdelta - Liest Timedelta nach AX:DX
getdelta:push bx
push cx
push di
xor ax,ax
xor dx,dx
mov di,4
getdel10:mov cx,7
getdel20:shl ax,1
rcl dx,1
loop getdel20
mov cl,[si]
inc si
mov bl,cl
and cx,07fh
add ax,cx
adc dx,0
test bl,80h
jz getdelex
dec di
jnz getdel10
mov ax,si
call hexw
mov ax,cs
mov ds,ax
lea si,msg_invdelta
jmp err_exit
getdelex:pop di
pop cx
pop bx
ret
; --------
; getxdelt - Liest Timedelta nach AX:DX
getxdelt:push bx
push cx
xor ax,ax
xor dx,dx
getxdel1:mov cx,7
getxdel2:shl ax,1
rcl dx,1
loop getxdel2
push bx
push ax
call getbyte
mov cl,al
pop ax
mov bl,cl
and cx,07fh
add ax,cx
adc dx,0
test bl,80h
pop bx
jnz getxdel1
pop cx
pop bx
ret
; -------
; getbyte
getbyte: push bx
push si
push ds
shl bx,1
mov si,trackaddr[bx]
mov ds,trackseg [bx]
lodsb
pop ds
mov trackaddr[bx],si
pop si
pop bx
ret
; --------
; loadfile - Lädt und überprüft SMF-Datei
loadfile:mov di,TRACKNAME
xor ax,ax
mov cx,TRACKSTART
sub cx,di
rep stosb
mov ax,3f00h
mov bx,shandle
mov cx,14
mov dx,STACKADDR
int 21h
mov si,dx
lodsw
cmp ax,'TM'
jz loadf100
nosmf : lea si,msg_nosmf
jmp err_exit
loadf100:lodsw
cmp ax,'dh'
jnz nosmf
lodsw
or ax,ax
jnz nosmf
lodsw
xchg al,ah
cmp al,6
jnz nosmf
lodsw
xchg al,ah
cmp ax,1
ja nosmf ; Typ muss 0 oder 1 sein
lodsw ; Anzahl der Tracks
xchg al,ah
mov tracks,ax
cmp ax,MAX_TRACKS
jb loadf120
lea si,msg_toomuch
jmp err_exit
loadf120:lodsw
xchg al,ah
push ax
mov bx,24
xor dx,dx
div bx
or ax,ax
jnz loadf140
lea si,msg_invtbase
jmp err_exit
loadf140:pop ax
mov timebase,ax
mov ax,cs
mov bx,TRACKSTART
shr bx,4
add ax,bx
mov word ptr trackseg,ax
mov atracks,0
; -------
; nachdem der Header abgehandelt ist, werden jetzt die Tracks eingelesen!
loadf200:mov ax,3f00h
mov bx,shandle
mov cx,8
mov dx,STACKADDR
int 21h
mov si,dx
lodsw
cmp ax,'TM'
jz loadf220
invtrack:lea si,msg_invtrack
jmp err_exit
loadf220:lodsw
cmp ax,'kr'
jnz invtrack
lodsw
or ax,ax
jz loadf240
toolong: lea si,msg_trktoolong
jmp err_exit
loadf240:lodsw
xchg al,ah
mov tracklen,ax
cmp ax,0fff0h
ja toolong
mov bx,atracks
shl bx,1
add ax,15
shr ax,4
add ax,trackseg[bx]
mov trackseg[bx+2],ax
; Startsegment des nächsten Tracks ermitteln
mov word ptr trackaddr[bx],0
push ds
mov ds,trackseg[bx]
mov ax,3f00h
mov bx,cs:shandle
mov cx,cs:tracklen
xor dx,dx
int 21h
cmp ax,cx
jz loadf260
mov ax,cs
mov ds,ax
lea si,msg_eof
jmp err_exit
loadf260:xor si,si
; ----
; Hier wird der Track schlicht überprüft!
loadf300:call getdelta ; Timedelta nach ax:dx
mov bx,cs:atracks
shl bx,2
add word ptr cs:[bx+EVENTS],1
adc word ptr cs:[bx+EVENTS+2],0
lodsb ; Event nach AL einlesen
cmp al,0ffh ; META Event ?
jnz loadf400 ; nein, weitermachen
; ------------
; Hier beginnt die Abhandlung der von uns unterstützten META Events
lodsb ; EVENT nach AL
cmp al,3 ; Trackname (?)
jnz loadf320 ; nein, weitersuchen
lodsb
mov ah,0
mov cx,ax ; Länge nach CX
mov di,cs:atracks ; Welcher Track ist aktuell (?)
shl di,5 ; * 32
add di,TRACKNAME ; + Adresse TRACKNAME
xor bx,bx
loadf304:movsb
inc bx
cmp bx,32
jz loadf306
loop loadf304
loadf306:mov al,0
stosb
jcxz loadf310
loadf308:lodsb
loop loadf308
loadf310:jmp loadf300
loadf320:cmp al,4 ; Instrname (?)
jnz loadf340 ; nein, weitersuchen
lodsb
mov ah,0
mov cx,ax ; Länge nach CX
mov di,cs:atracks ; Welcher Track ist aktuell (?)
shl di,5 ; * 32
add di,INSTRNAME ; + Adresse INSTRNAME
xor bx,bx
loadf324:movsb
inc bx
cmp bx,32
jz loadf326
loop loadf324
loadf326:mov al,0
stosb
jcxz loadf330
loadf328:lodsb
loop loadf328
loadf330:jmp loadf300
loadf340:cmp al,2fh ; End Of Track (?)
jnz loadf360
jmp loadf900 ; Abbrechen und unten weitermachen!
; ---------------
; Uninteressanter META-Event - überlesen!
loadf360:lodsb ; Länge nach AL
mov ah,0
mov cx,ax
loadf362:lodsb
loop loadf362
jmp loadf300
; ---------
; Kein META Event, also hier weiterprüfen
loadf400:cmp al,0f0h
jz loadf420
cmp al,0f7h ; SYSEX - oder SYSEX Continue Events
jnz loadf500
loadf420:lodsb ; Länge nach AL
mov ah,0
mov cx,ax
loadf440:lodsb
loop loadf440
jmp loadf300
; ----------
; Hier kommt ein reinrassiger MIDI-Event!
loadf500:test al,80h
jnz loadf520 ; MIDI Runtime Message
lodsb ; Velocity lesen
jmp loadf300 ; und weitermachen
loadf520:mov bx,cs:atracks
add bx,CHANNEL
mov cl,al
and cl,0fh
mov cs:[bx],cl
mov cl,al
and al,0f0h
cmp al,0c0h
jnz loadf540
mov cl,[si]
mov bx,cs:atracks
add bx,PATCH
cmp byte ptr cs:[bx],0
jz loadf530
mov byte ptr cs:[bx],-1
jmp short loadf540
loadf530:inc cl
mov byte ptr cs:[bx],cl
loadf540:shr al,4
cmp al,0ch
jz loadf580
cmp al,0dh
jz loadf580
lodsb
loadf580:lodsb
jmp loadf300
; --------
; Hier ist der Track abgehandelt
loadf900:pop ds
inc atracks
mov ax,atracks
cmp ax,tracks
jz loadfex
jmp loadf200
loadfex: ret
; -----
; uplay - Spielt SMF Datei !
uplay : call resetmpu
mov al,3fh
call put_cmd
xor bx,bx
mov di,COUNTER
mov cx,tracks
uplay020:call getxdelt
stosw
mov ax,dx
stosw
mov byte ptr [bx+TRACKFLAGS],0
inc bx
loop uplay020
test u2flag,IS_YAMAHA
jz uplay060
mov cx,8
lea si,drums
uplay040:lodsb
call put_midi
loop uplay040
uplay060:push es
mov ax,3508h
int 21h
mov word ptr oldvec08,bx
mov word ptr oldvec08+2,es
pop es
mov tempo,120
lea dx,timint
mov ax,2508h
int 21h
or u2flag,IS_PLAY
uplay120:test u2flag,IS_PLAY
jz uplay180
uplay140:mov ah,1
int 16h
jz uplay120
mov ah,0
int 16h
cmp al,27
jnz uplay120
uplay180:and u2flag,not IS_PLAY
call timrest
call alloff
call resetmpu
ret
; ---------------
; TMAIN! Erster Einstieg - alle Tracks
tmain : xor bx,bx
mov cx,tracks
; ---------
; Einzelner Track
uplay220:cmp byte ptr [TRACKFLAGS+bx],-1
jz uplay500 ; Wenn Track nicht aktiv, weitermachen
mov si,bx
shl si,2
add si,COUNTER
lodsw
mov dx,[si]
or ax,ax
jnz uplay300
or dx,dx
jnz uplay300
; -----
; Timer abgelaufen - Event ausgeben und weitermachen
call putevent
call getxdelt
mov di,bx
shl di,2
add di,COUNTER
stosw
mov ax,dx
stosw
or ax,ax
jnz uplay500
or dx,dx
jz uplay220
jmp short uplay500
; -----
; Timer dekrementieren
uplay300:sub ax,1
sbb dx,0
mov word ptr [si],dx
mov word ptr [si-2],ax
uplay500:inc bx
loop uplay220
ret
; --------
; PutEvent - Verarbeitet Event
putevent:call getbyte
cmp al,-1 ; META Event ?
jnz putev200 ; Nein, dann weiter
; ----------
; Abhandlung META Event
call getbyte ; Event lesen
cmp al,2fh ; Event Trackende!
jnz putev100
dec atracks
mov byte ptr [bx+TRACKFLAGS],-1
call getbyte
cmp atracks,0
jnz putev020
and u2flag,not IS_PLAY
putev020:ret
putev100:cmp al,51h ; Change Tempo wäre noch interessant (!)
jnz putev120
push bx
push cx
call getbyte
call getbyte
push ax
call getbyte
mov ch,al
call getbyte
pop bx
mov cl,al
mov bh,0
mov ax,8700h
mov dx,393h
call ludiv
mul word ptr timebase
mov bx,120
div bx
mov tempo,ax
call timiset
pop cx
pop bx
ret
; -----------
; Ein für uns uninteressanter EVENT - überlesen und zurück!
putev120:call getbyte ; Länge nach AL
mov ah,0
push cx ; Nach CX
mov cx,ax
jcxz putev160
putev140:call getbyte
loop putev140 ; Und Event überlesen
putev160:pop cx
ret
; ----
; Kein META-Event - also weitermachen
putev200:cmp al,0f0h ; SYSEX's
jz putev120 ; die überlesen wir einfach
cmp al,0f7h
jz putev120
test al,80h
jnz putev220
; Runtime EVENT
call put_midi
call getbyte
call put_midi
ret
putev220:mov ah,al
shr ah,4
cmp ah,0bh
jbe putev240
cmp ah,0eh
jz putev240
cmp ah,0ch ; PRG CHG
jz putev260
call put_midi
call getbyte
call put_midi
ret
putev240:call put_midi
call getbyte
call put_midi
call getbyte
call put_midi
ret
; -------
; PRG Chg Event
putev260:test u2flag,IS_YAMAHA
jz putev280
call map
ret
putev280:call put_midi
call getbyte
call put_midi
ret
; ---
; map General MIDI
map : push bx
push ax ; AL = Program Change Controller sichern
and al,0fh ; Kanal filtern
or al,0b0h ; Or 0b0h - Control Change
mov ah,al ; nach AH sichern
call put_midi ; ausgeben
mov al,0 ; 0 ausgeben
call put_midi
mov al,0 ; 0 ausgeben
call put_midi
mov al,ah ; Control Change
call put_midi ; ausgeben
mov al,20h ; Bank Select Low Byte
call put_midi ; ausgeben
lea bx,gm_map ; Adresse GM Map
call getbyte ; nächstes byte lesen PRG CHANGE
mov ah,0
shl ax,1
add bx,ax ; Offset in GM Tabelle
mov al,[bx] ; ausgeben
call put_midi
pop ax ; PRG Change Controller
call put_midi ; ausgeben
mov al,[bx+1] ; PRG
call put_midi ; ausgeben
pop bx ; und zurück
ret
; --------
; dispfile - Stellt Informationen dar
dispfile:lea si,msg_smfFile
call wstring
lea si,filename
call wstring
lea si,msg_title
call wstring
mov al,'-'
mov cx,73
dispf100:call wchar
loop dispf100
lea si,msg_cr
call wstring
xor bx,bx
; ---------
; Für jeden Track entsprechende Meldung ausgeben!
dispf120:mov ax,bx
inc ax
cwd
mov stellen,3
call dz
mov al,' '
call wchar
mov cx,24
mov si,bx
shl si,5
add si,TRACKNAME
dispf140:lodsb
or al,al
jz dispf160
call wchar
loop dispf140
dispf160:jcxz dispf200
mov al,' '
dispf180:call wchar
loop dispf180
dispf200:mov cx,24
mov si,bx
shl si,5
add si,INSTRNAME
dispf240:lodsb
or al,al
jz dispf260
call wchar
loop dispf240
dispf260:jcxz dispf300
mov al,' '
dispf280:call wchar
loop dispf280
dispf300:mov si,bx
shl si,2
add si,EVENTS
lodsw
mov dx,[si]
mov stellen,6
call dz
mov al,' '
call wchar
mov si,bx
add si,CHANNEL
lodsb
inc al
mov ah,0
cwd
mov stellen,8
call dz
mov si,bx
add si,PATCH
lodsb
cmp al,-1
jnz dispf320
lea si,msg_mult
call wstring
jmp short dispf340
dispf320:mov ah,0
cwd
mov stellen,6
call dz
dispf340:lea si,msg_cr
call wstring
inc bx
cmp bx,tracks
jz dispfex
jmp dispf120
dispfex: ret
; --------
; fileloop - Durchsucht alle Dateien
fileloop:mov ax,1a00h
mov dx,80h
int 21h
mov ax,4e00h
mov cx,27h
lea dx,filename
int 21h
jnb filel100
fnf_exit:lea si,msg_fnf
jmp err_exit
filel100:mov si,9eh
mov di,fileaddr
mov cx,6
rep movsw
mov al,0
stosb
lea dx,filename
mov ax,3d00h
int 21h
jb fnf_exit
mov shandle,ax
call loadfile
call dispfile
test u2flag,IS_TEST
jnz filel120
call uplay
filel120:mov ax,3e00h
mov bx,shandle
int 21h
mov ax,4f00h
int 21h
jnb filel100
ret
; ------
; anfang
anfang : cld
mov sp,STACKADDR-2
call parscmd
call fileloop
ende : mov ah,4ch
int 21h
ALIGN 16
filename label byte
code ends
end start