home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Da Capo
/
da_capo_vol1.bin
/
programs
/
amiga
/
edit
/
octamedv2
/
programmers
/
modplayer
/
modplayer.a
< prev
next >
Wrap
Text File
|
1993-03-13
|
58KB
|
2,103 lines
; modplayer.a
; ~~~~~~~~~~~
; The music player routine for OctaMED V2.00 four channel/MIDI songs.
; Written by Teijo Kinnunen.
;============================================================================
MIDI EQU 0 ;1 = include MIDI code
AUDDEV EQU 1 ;1 = allocate channels using audio.device
SYNTH EQU 1 ;1 = include synth-sound handler
CHECK EQU 1 ;1 = do range checkings (track, sample in mem etc.)
RELVOL EQU 1 ;1 = include relative volume handling code
IFF53 EQU 1 ;1 = play IFF 3- and 5-octave samples correctly
HOLD EQU 1 ;1 = handle hold/decay
;****** Timing control ******
VBLANK EQU 0 ;1 = use VBlank interrupt (when absolutely necessary)
CIAB EQU 1 ;1 = use CIAB timers (default)
; Please use CIAB whenever possible to avoid problems with variable
; VBlank speeds and to allow the use of command F01 - FF0 (set tempo)
; If both are set to 0, the timing is left for you (never set both to 1!!),
; then you just call _IntHandler for each timing pulse.
;============================================================================
;If you are making a demo/game with only a single tune you'd like to
;incorporate in the code (like "easyplayer.a" of MED V3), set the following
;flag to 1. This requires an assembler with INCBIN (or equivalent) directive.
;You have to type the module name into the INCBIN statement (located near the
;end of this file, on line 2045).
EASY EQU 0
;Call _startmusic to play the music, and _endmusic to stop it (before
;exiting). Note: don't call _startmusic twice!! This would cause the module
;to be relocated twice (= Guru). If you need to stop and continue playing,
;don't use the EASY routines, use PlayModule/StopPlayer... instead.
;============================================================================
;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
mmd_smplarr EQU 24
mmd_smplarrlen EQU 28
mmd_expdata EQU 32
mmd_expsize EQU 36
mmd_pstate EQU 40 ; <0 = play song, 0 = don't play, >0 = play block
mmd_pblock EQU 42
mmd_pline EQU 44
mmd_pseqnum EQU 46
mmd_actplayline EQU 48
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
;Trackdata sizes
T03SZ EQU 88
T415SZ EQU 18
section "text",code
IFNE EASY
xdef _startmusic,_endmusic
_startmusic lea easymod,a0
bsr.w _RelocModule
bsr.w _InitPlayer
lea easymod,a0
bra.w _PlayModule
_endmusic bra.w _RemPlayer
ENDC
_ChannelOff: ;d0 = channel #
lea trackdataptrs(pc),a1
lsl.b #2,d0
adda.w d0,a1
lsr.b #2,d0
movea.l (a1),a1
IFNE MIDI
move.b trk_prevmidin(a1),d1 ;is it MIDI??
beq.s notcomidi ;not a MIDI note
choff_midi: clr.b trk_prevmidin(a1)
lea noteondata(pc),a0
move.b d1,1(a0)
move.b trk_prevmidich(a1),(a0) ;prev MIDI channel
clr.b 2(a0)
or.b #$90,(a0) ;note off
moveq #3,d0
bra.w _AddMIDIData
ENDC
notcomidi: cmp.b #4,d0
bge.s notamigatrk
IFNE SYNTH
clr.l trk_synthptr(a1)
clr.b trk_synthtype(a1)
ENDC
moveq #1,d1
lsl.w d0,d1
move.w d1,$dff096
notamigatrk: rts
SoundOff: move.l d2,-(sp)
moveq #15,d2
SO_loop0 move.l d2,d0
bsr.s _ChannelOff
dbf d2,SO_loop0
lea _module(pc),a0
clr.l (a0) ;play nothing
move.l (sp)+,d2
rts
_PlayNote: ;d0(w) = trk #, d1 = note #, d2 = vol, d3(w) = instr # a3 = addr of instr
moveq #0,d4
bset d0,d4 ;d4 is mask for this channel
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
IFNE MIDI
bne.s inmem
tst.b inst_midich(a3) ;is MIDI channel set
ENDC
IFNE CHECK
beq.w pnote_rts ; NO!!!
ENDC
inmem: add.b msng_playtransp(a4),d1 ;add play transpose
add.b inst_strans(a3),d1 ;and instr. transpose
cmp.b #4,d0
bge.s nodmaoff ;track # >= 4: not an Amiga channel
move.l d5,a1
IFNE SYNTH
tst.l d5
beq.s stpdma
tst.b trk_synthtype(a5)
ble.s stpdma ;prev. type = sample/hybrid
cmp.w #-1,4(a1) ;type == SYNTHETIC??
beq.s nostpdma
ENDC
stpdma: move.w d4,$dff096 ;stop this channel (dmacon)
nostpdma:
IFNE SYNTH
clr.l trk_synthptr(a5)
ENDC
nodmaoff:
IFNE MIDI
move.b trk_prevmidin(a5),d3 ;get prev. midi note
beq.s noprevmidi
clr.b trk_prevmidin(a5)
lea noteondata+2(pc),a0
clr.b (a0) ;volume = 0
move.b d3,-(a0)
move.b trk_prevmidich(a5),-(a0) ;prev midi channel
or.b #$90,(a0) ;note off
movem.w d0-d1,-(sp)
moveq #3,d0
bsr.w _AddMIDIData
movem.w (sp)+,d0-d1
noprevmidi: tst.b inst_midich(a3)
bne.w handleMIDInote
ENDC
IFNE CHECK
cmp.w #4,d0 ;track > 3???
bge.w pnote_rts ;no Amiga instruments here!!!
ENDC
; handle decay (for tracks 0 - 3 only!!)
IFNE HOLD
clr.b trk_fadespd(a5) ;no fade yet..
move.b trk_initdecay(a5),trk_decay(a5) ;set decay
ENDC
clr.b trk_vibroffs(a5) ;clr vibrato offset
or.w d4,dmaonmsk
move.l d5,a0
subq.b #1,d1
IFNE SYNTH
tst.w 4(a0)
bmi.w handleSynthnote
clr.b trk_synthtype(a5)
ENDC
tlwtst0: tst.b d1
bpl.s notenot2low
add.b #12,d1 ;note was too low, octave up
bra.s tlwtst0
notenot2low: cmp.b #62,d1
ble.s endpttest
sub.b #12,d1 ;note was too high, octave down
endpttest:
moveq #0,d4
IFNE IFF53
move.w 4(a0),d0 ;Soitin-struct in a0
bne.s iff5or3oct ;note # in d1 (0 - ...)
ENDC
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),d4 ;inst_repeat
move.w inst_replen(a3),d3
IFNE IFF53
bra.s end_getdata
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
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),d4 ;inst_repeat
move.w inst_replen(a3),d3
moveq #0,d6
move.b shiftcnt(pc,d7.w),d6
lsl.w d6,d4
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
ENDC
end_getdata movea.l trk_audioaddr(a5),a1 ;base of this channel's regs
move.l d0,(a1)+ ;put it in ac_ptr (= 0)
cmp.w #1,d3
bhi.s repeat
move.l #_chipzero,trk_sampleptr(a5) ;pointer of zero word
move.w #1,trk_samplelen(a5) ;length: 1 word
lsr.l #1,d1 ;shift length right
move.w d1,(a1)+ ;and put to custom chip (ac_len)
bra.s retsn1
repeat: tst.w d4
beq.s begin0 ;rep. start < 2
move.w d4,(a1)+ ;move repeat to hardware
bra.s beginn0
begin0: move.w d3,(a1)+ ;ac_len
beginn0: add.l d4,d4 ;shift
add.l d4,d0 ;d0 = starting address of repeat
move.l d0,trk_sampleptr(a5) ;remember rep. start
move.w d3,trk_samplelen(a5) ;remember rep. length
retsn1: move.w d5,(a1)+ ;getinsdata puts period to d5 (a1 = ac_per)
move.w d2,(a1) ;a1 = ac_vol
move.w d5,trk_prevper(a5)
IFNE SYNTH
tst.b trk_synthtype(a5)
bne.w hSn2
ENDC
pnote_rts rts
IFNE MIDI
handleMIDInote: add.b #23,d1 ;2 octaves higher and -1
bpl.s hmn_not2low ;note number not too low
hmn_2low add.b #12,d1 ;it was too low, 1 octave up
bmi.s hmn_2low
hmn_not2low
add.b d2,d2 ;volume 0 - 63 => 0 - 127
subq.b #1,d2 ;if 128 => 127
bpl.s hmn_notvolu0
moveq #0,d2
hmn_notvolu0
moveq #0,d5
move.b inst_midich(a3),d5 ;