home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Da Capo
/
da_capo_vol1.bin
/
programs
/
amiga
/
edit
/
octamedv2
/
programmers
/
modplayer
/
mod8player.a
< prev
next >
Wrap
Text File
|
1993-03-13
|
36KB
|
1,303 lines
; mod8player.a
; ~~~~~~~~~~~~
; The player routine for OctaMED V2.00 5 - 8 channel songs.
; Written by Teijo Kinnunen in 1991.
;============================================================================
;the MMD0 structure offsets
mmd_id EQU 0
mmd_modlen EQU 4
mmd_songinfo EQU 8
mmd_songlen EQU 12 ;currently unused
mmd_blockarr EQU 16
mmd_blockarrlen EQU 20 ;unused
mmd_smplarr EQU 24
mmd_smplarrlen EQU 28 ;unused
mmd_expdata EQU 32
mmd_expsize EQU 36 ;unused
mmd_pstate EQU 40
mmd_pblock EQU 42
mmd_pline EQU 44
mmd_pseqnum EQU 46
mmd_actplayline EQU 48 ;obsolete
mmd_counter EQU 50
mmd_songsleft EQU 51
;the MMD0song structure
;Instrument data here (504 bytes = 63 * 8)
msng_numblocks EQU 504
msng_songlen EQU 506
msng_playseq EQU 508
msng_deftempo EQU 764
msng_playtransp EQU 766
msng_flags EQU 767
msng_reserved EQU 768
msng_tempo2 EQU 769
msng_trkvol EQU 770
msng_mastervol EQU 786
msng_numsamples EQU 787
;Instrument data
inst_repeat EQU 0
inst_replen EQU 2
inst_midich EQU 4
inst_midipreset EQU 5
inst_svol EQU 6
inst_strans EQU 7
;Audio hardware offsets
ac_ptr EQU $00
ac_len EQU $04
ac_per EQU $06
ac_vol EQU $08
; These are not in real hardware, but the player "emulates" the real
; hardware. And there are some extra registers that we require.
ac_end EQU $0C
ac_rest EQU $10
ac_mask EQU $14
ac_rhw EQU $16
T03SZ EQU 88
section "text",code
sinetable: dc.b 0,25,49,71,90,106,117,125,127,125,117,106,90,71,49
dc.b 25,0,-25,-49,-71,-90,-106,-117,-125,-127,-125,-117
dc.b -106,-90,-71,-49,-25,0
nextblock: dc.w 0
numtracks: dc.w 0
numlines: dc.w 0
_Wait1line: move.l d0,-(sp)
moveq #$79,d0
wl0: move.b $dff007,d1
wl1: cmp.b $dff007,d1
beq.s wl1
dbf d0,wl0
move.l (sp)+,d0
rts
getinsdata: moveq #0,d2
move.w 4(a0),d0 ;Soitin-struct in a0
bne.s iff5or3oct ;note # in d1 (0 - ...)
move.l a0,d0
lea _periods(pc),a0
move.l a0,trk_periodtbl(a5)
add.b d1,d1
move.w 0(a0,d1.w),d5 ;put period to d5
move.l d0,a0
addq.l #6,d0 ;Skip structure
move.l (a0),d1 ;length
move.w (a3),d2 ;inst_repeat (offs. 0)
move.w inst_replen(a3),d3
rts
iff5or3oct: movem.l d6-d7,-(sp)
moveq #0,d7
move.w d1,d7
divu #12,d7 ;octave #
move.l d7,d5
swap d5 ;note number in this oct (0-11) is in d5
move.l (a0),d1
cmp.b #2,d0
bne.s no3oct
addq.l #6,d7
divu #7,d1 ;get length of the 1st octave
bra.s no5oct
no3oct: divu #31,d1 ;get length of the 1st octave (5 octaves)
no5oct: move.l d1,d0 ;d0 and d1 = length of the 1st oct
move.w (a3),d2 ;inst_repeat
move.w inst_replen(a3),d3
moveq #0,d6
move.b shiftcnt(pc,d7.w),d6
lsl.w d6,d2
lsl.w d6,d3
lsl.w d6,d1
move.b mullencnt(pc,d7.w),d6
mulu d6,d0 ;offset of this oct from 1st oct
add.l a0,d0 ;add base address to offset
addq.l #6,d0 ;skip structure
lea _periods(pc),a1
add.b octstart(pc,d7.w),d5
add.b d5,d5
move.w 0(a1,d5.w),d5
movem.l (sp)+,d6-d7
rts ;returns period in d5
shiftcnt: dc.b 4,3,2,1,1,0,2,2,1,1,0,0
mullencnt: dc.b 15,7,3,1,1,0,3,3,1,1,0,0
octstart: dc.b 12,12,12,12,24,24,0,12,12,24,24,36
;**************************************************************************
;*
;* 8 CHANNEL PLAY ROUTINE
;*
;**************************************************************************
_ChannelO8: cmp.b #8,d0
bge.s xco8
lea trackdata8(pc),a1
lsl.b #2,d0
adda.w d0,a1
movea.l (a1),a1
movea.l trk_audioaddr(a1),a1
clr.w ac_per(a1)
xco8 rts
_PlayNote8: ;d0(w) = trk #, d1 = note #, d2 = vol, d3(w) = instr # a3 = addr of instr
movem.l d3/d5,-(sp) ;All right, let's start!!
movea.l mmd_smplarr(a6),a0
add.w d3,d3 ;d3 = instr.num << 2
add.w d3,d3
move.l 0(a0,d3.w),d5 ;get address of instrument
beq.w retsn28
inmem8: add.b msng_playtransp(a4),d1 ;add play transpose
add.b inst_strans(a3),d1 ;and instr. transpose
tst.b inst_midich(a3)
bne.w retsn28 ;MIDI
clr.b trk_vibroffs(a5) ;clr vibrato offset
move.l d5,a0
subq.b #1,d1
tst.w 4(a0)
bmi.w retsn28 ;Synth
tlwtst08: tst.b d1
bpl.s notenot2low8
add.b #12,d1 ;note was too low, octave up
bra.s tlwtst08
notenot2low8: cmp.b #62,d1
ble.s endpttest8
sub.b #12,d1 ;note was too high, octave down
endpttest8: bsr.w getinsdata
movea.l trk_audioaddr(a5),a1 ;base of this channel's regs
move.l d0,(a1) ;put it in ac_ptr
cmp.w #1,d3
bhi.s repeat8
tst.b trk_split(a5)
beq.s pn8_nosplit0
add.l d1,d0
subq.l #1,d0
clr.l ac_rest(a1)
move.l d0,ac_end(a1)
bra.s retsn18
pn8_nosplit0 lsr.l #1,d1
move.w d1,ac_len(a1)
move.l #zerodata,ac_rest(a1)
move.w #1,ac_end(a1)
bra.s retsn18
repeat8: tst.b trk_split(a5)
bne.s pn8_split1
tst.w d2
beq.s begin08 ;rep. start < 2
move.w d2,ac_len(a1) ;move repeat to hardware
bra.s beginn08
begin08: move.w d3,ac_len(a1)
beginn08: add.l d2,d2 ;shift
add.l d2,d0 ;d0 = starting address of repeat
move.l d0,ac_rest(a1) ;remember rep. start
move.w d3,ac_end(a1) ;remember rep. length
bra.s retsn18
pn8_split1 add.l d2,d2 ;shift
add.l d3,d3
add.l d2,d0
move.l d0,ac_rest(a1)
add.l d3,d0
subq.l #1,d0
move.l d0,ac_end(a1)
retsn18: move.w d5,ac_per(a1) ;getinsdata puts period to d5
move.w d5,trk_prevper(a5)
retsn28: movem.l (sp)+,d3/d5
rts
t038: ds.b 20
dc.l track0hw
ds.b 64+20
dc.l track1hw
ds.b 64+20
t238 dc.l track2hw
ds.b 64+20
dc.l track3hw
ds.b 64
t4158: ds.b 20
dc.l track4hw
ds.b 64+20
dc.l track5hw
ds.b 64+20
t6158 dc.l track6hw
ds.b 64+20
dc.l track7hw
ds.b 64
trackdata8: dc.l t038,t038+T03SZ,t038+2*T03SZ,t038+3*T03SZ
dc.l t4158,t4158+T03SZ,t4158+2*T03SZ,t4158+3*T03SZ
_IntHandler8: movem.l d2-d7/a2-a5,-(sp)
; ================ 8 channel handling (buffer swap) ======
lea trksplit(pc),a2
move.w #800,d0
not.b whichbuff ;swap buffer
bne.s usebuff1
tst.b (a2)+
beq.s tnspl0
move.l a1,$a0(a0)
tnspl0 lea 800(a1),a5
tst.b (a2)+
beq.s tnspl1
move.l a5,$b0(a0)
tnspl1 adda.w d0,a5
tst.b (a2)+
beq.s tnspl2
move.l a5,$c0(a0)
tnspl2 adda.w d0,a5
tst.b (a2)
beq.s buffset
move.l a5,$d0(a0)
bra.s buffset
usebuff1: lea 400(a1),a1
tst.b (a2)+
beq.s tnspl0b
move.l a1,$a0(a0)
tnspl0b lea 800(a1),a5
tst.b (a2)+
beq.s tnspl1b
move.l a5,$b0(a0)
tnspl1b adda.w d0,a5
tst.b (a2)+
beq.s tnspl2b
move.l a5,$c0(a0)
tnspl2b tst.b (a2)
beq.s buffset
adda.w d0,a5
move.l a5,$d0(a0)
buffset: move.w #1<<7,$9c(a0) ;clear interrupt
; ============== fill buffers ============
moveq #0,d4 ;mask for DMA
move.l #3719168,d3
subq.l #3,a2 ;a2 = trksplit(pc)
lea track0hw(pc),a6
tst.b (a2)+
bne.s tspl0c
bsr.w pushregs
bra.s tnspl0c
tspl0c bsr.s fillbuf
tnspl0c adda.w #400,a1
lea track1hw(pc),a6
tst.b (a2)+
bne.s tspl1c
bsr.w pushregs
bra.s tnspl1c
tspl1c bsr.s fillbuf
tnspl1c adda.w #400,a1
lea track2hw(pc),a6
tst.b (a2)+
bne.s tspl2c
bsr.w pushregs
bra.s tnspl2c
tspl2c bsr.s fillbuf
tnspl2c adda.w #400,a1
lea track3hw(pc),a6
tst.b (a2)
bne.s tspl3c
bsr.w pushregs
bra.w do_play8
tspl3c bsr.s fillbuf
bra.w do_play8
; ==============================================================
; This is the magical routine which actually mixes the voices.
; ==============================================================
;calculate channel A period
fillbuf: move.l d3,d7
move.w ac_per(a6),d6
beq.s setpzero0
move.l d7,d2
divu d6,d2
moveq #0,d1
move.w d2,d1
add.l d1,d1
add.l d1,d1
;get channel A addresses
move.l ac_end(a6),a5
move.l (a6),d0
beq.s setpzero0
chA_dfnd move.l d0,a3 ;a3 = start address, a5 = end address
;calc bytes before end
mulu #1600,d2
clr.w d2
swap d2
; d2 = # of bytes/fill
add.l a3,d2 ;d2 = end position after this fill
sub.l a5,d2 ;subtract sample end
bmi.s norestart0
move.l ac_rest(a6),d0
beq.s rst0end
move.l d0,(a6)
move.l d0,a3
bra.s norestart0
rst0end clr.l (a6)
setpzero0 lea zerodata(pc),a3
moveq #0,d1
norestart0
;channel B period
move.w SIZE4TRKHW+ac_per(a6),d6
beq.s setpzero0b
divu d6,d7
moveq #0,d2
move.w d7,d2
add.l d2,d2
add.l d2,d2
;channel B addresses
move.l SIZE4TRKHW+ac_end(a6),a5
move.l SIZE4TRKHW(a6),d0
beq.s setpzero0b
move.l d0,a4
mulu #1600,d7
clr.w d7
swap d7
add.l a4,d7
sub.l