Tak zkus tohle:
Kód:
; MMLPLAY for MZ-700 - prehraje string v MML
;
; Author: vaclavpe@seznam.cz
; 8.11.2021 - added TEMPO1-7, octaves are done with division,fixed order of '#'
;
; Supported MML commands
; '+','-' - upper/lower octave
; CDEFGAB - tones
; # - semitone letter preceeding the tone
; R - rest
; 0x0 - end of the text
;
; tones and rest are followed by the length 0-9
;
; https://www.sharpmz.no/articles/the-mz-series/mz-700/mz-700-8253-sound-functions-part-1/
;
MZFSTRT:ORG 0x1200
call CLRSCR
; song init
ld HL,SONGDATA
ld (SONGPTR),HL
loop: call VBLNK
; TEMPO divider
ld A,(DIVACT)
dec A
ld (DIVACT),A
jp NZ,lplayend
ld A,(DIVMAX)
ld (DIVACT),A
; ok let's play the next tone
ld HL,(SONGPTR)
playnxt:; get next command
ld A,(HL)
; end is 0x0
or A
jp Z,lplayend1 ; end of the song
inc HL ; advance the position
; lower octave
cp '-'
jr NZ,lpl1
ld A,(DOCT)
dec A
jr C,playnxt ; we are already at the lowest octave
ld (DOCT),A
jr playnxt
lpl1: ; higher octave
cp '+'
jr NZ,lpl2
ld A,(DOCT)
inc A
cp 5 ; we have only octaves 0,1,2,3,4
jr Z,playnxt
ld (DOCT),A
jr playnxt
lpl2: ; Rest
cp 'R'
jr NZ,lpl5
; switch off the gate
xor A
ld (0E008h),A
; now the length
lplen: ld A,(HL)
inc HL
call TONUMBER
jr NC,lpl3
ld A,4 ; take default number
dec HL ; unroll the position
lpl3: ; index the delay for DIVACT from DELTBL
push HL
ld HL,DELTBL
add A,L
ld L,A
jr NC,lpl4
inc H
lpl4: ld B,(HL)
; multiply with TEMPO
ld A,(TEMPO)
ld C,A
xor A
rr C
jr NC,lpl41
add A,B
lpl41: sla B
rr C
jr NC,lpl42
add A,B
lpl42: sla B
rr C
jr NC,lpl43
add A,B
lpl43: ld (DIVACT),A
pop HL
jp lplayend
lpl5: ; get hash
ld C,0
cp '#'
jr NZ,lpla
inc HL
inc C
lpla: ; get the tone - ABCDEFG
sub 041h ; is it A or over ?
jr C,playnxt ; probably bad command, try next command
cp 'H'-'A' ; under H ?
jr NC,playnxt ; probably bad command, try next command
; we have A-G starting with A - 110Hz; find halftones
push HL
ld HL,TONTBL
add A,L
ld L,A
jr NC,lpl6
inc H
lpl6: ld A,(HL)
pop HL
add A,C
ld C,A
; index the value for 8253 counter/timer
; base octave is enough and then number of divisions
sla C ; *2
ld B,0
ex DE,HL
ld HL,SNDTBL
add HL,BC
ld C,(HL)
inc HL
ld B,(HL)
ex DE,HL
; get the right octave
ld A,(DOCT)
or A
lpl9: jr Z,lpl8
srl B
rr C
dec A
jr lpl9
lpl8: ; write to 8253
ld A,036h
ld (0E007h),A ; control word
ld A,C
ld (0E004h),A
ld A,B
ld (0E004h),A
; enable the gate
ld A,1
ld (0E008h),A
; now the tone length
jp lplen
;
lplayend1:
; switch off the gate
xor A
ld (0E008h),A
lplayend:ld (SONGPTR),HL
jp loop
SONGPTR:defw 1
DOCT: defb 2
DIVMAX: defb 4
DIVACT: defb 1
TEMPO: defb 4 ; number 1-7
; table of delays - maximum multiply *4
DELTBL: defb 1,2,3,4,6,8,12,16,24,32
; table of fulltone numbers - A,Ais,B,C,Cis,D,Dis,E,F,Fis,G,Gis
TONTBL: defb 0,2,3,5,7,8,10
; table of sounds - four octaves divided from 1.1MHz starting from A/110Hz
SNDTBL: defw 10000,9439,8909,8409,7937,7492,7071,6674
defw 6300,5946,5612,5297,5000,4719,4454,4204
SONGDATA: ; ovcaci ctveraci
defb "C4R1E4R1G5R5C4R1E4R1G5R5"
defb "-E2R0E2R0D2R0E2R0F4R1D4R1"
defb "++E2R0E2R0D2R0E2R0F4R1D4R1"
defb "-E4R1D4R1C4",0
TONUMBER: ; returns CARRY when number is not 0-9
sub 030h
ret C
cp 0Ah
ccf
ret
; vblnk delay
VBLNK: push AF
vblnk1: ld A,($E002)
rlca
jr NC,vblnk1
vblnk2: ld A,($E002)
rlca
jr C,vblnk2
pop AF
ret
; Screen clear together with attr
CLRSCR: ld HL,$D000 ; Text VRAM start
ld DE,$D001
ld BC,$400 ; Whole screen
ld (HL),0
ldir
clratr: ld HL,0xd800 ; Attribute VRAM start
ld DE,0xd801
ld BC,0x0400
ld (HL),0x70
ldir
ret
MZFEND:
; MZF header
db 01 ; OBJ file
dw MZFSTRT ; MZF start
dw MZFEND-MZFSTRT ; length
dw MZFSTRT ; start address