home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 4: Demo 1
/
almathera_demo1.bin
/
sourcecode
/
noisetracker1.1
/
replay1.1.s
< prev
next >
Wrap
Text File
|
1995-03-17
|
15KB
|
636 lines
*---------------------------------------------------------------*
* *
* NoisetrackerV1.0 replayroutine *
* *
* Documented, debugged and optimized by JMP in Nov 89 *
* *
*---------------------------------------------------------------*
* ALTERATIONS
*
* 1) SetVolume now sets the shadow copy as well as the chip volume
* so that volume slides work.
* 2) Vibrato no longer crashes the main program, it used to use A4
* although this register wasn't saved by the interrupt routine !!
* 3) The instrument parameters (addr,length,repeat,replen) are now
* calculated once in mt_init rather than every time a new note
* is played
* 4) Code is now totally position independent.
opt p+
*------------------------------
* EQUATES
_custom equ $DFF000
dmacon equ $96
aud0 equ $A0
aud1 equ $B0
aud2 equ $C0
aud3 equ $D0
ac_ptr equ 0
ac_len equ 4
ac_per equ 6
ac_vol equ 8
ac_dat equ 10
*------------------------------
* VOICE INFO
rsreset
vi_command rs.l 1 command $spppsfnn (see song format)
vi_addr rs.l 1 sample start address
vi_length rs.w 1 sample length
vi_repeat rs.l 1 repeat address
vi_replen rs.w 1 repeat length
vi_period rs.w 1 current period
vi_volume rs.w 1 current volume
vi_voice rs.w 1 voice enable bit mask (for dmacon)
vi_tdir rs.b 1 tone portamento direction 0 down/1 up
vi_tspeed rs.b 1 tone portamento speed
vi_tperiod rs.w 1 tone portamento dest. period (0=off)
vi_vspeed rs.b 1 vibrato, bits 7..4=speed, bits 3..0=size
vi_vframe rs.b 1 vibrato frame count
vi_size rs.w 0
*------------------------------
* LOCAL VARIABLES
rsreset
mv_file rs.l 1 song file address
mv_speed rs.b 1 current speed
mv_songpos rs.b 1 current position 0..127
mv_counter rs.b 1 frame count
mv_break rs.b 1 set if pattern break/position jump
mv_length rs.w 1 song length
mv_pattpos rs.w 1 current pattern row 0..63
mv_dmacon rs.w 1 shadow reg for enabled voices
mv_size rs.w 0
*------------------------------
* CONSTANTS
no_of_instruments equ 31
no_of_positions equ 128
row_size equ 16
no_of_rows equ 64
pattern_size equ no_of_rows*row_size
instname_size equ 22
songname_size equ 20
*------------------------------
* SONG/MODULE format
* instrument info
rsreset
in_name rs.b instname_size padded with 0's
in_length rs.w 1 length in words
in_volume rs.w 1 volume 0..64
in_repeat rs.w 1 repeat offset in words
in_replen rs.w 1 repeat length in words
in_size rs.w 0
* song file
rsreset
sf_name rs.b songname_size padded with 0's
sf_instr rs.b no_of_instruments*in_size
sf_length rs.b 1 song length
sf_restart rs.b 1 =120, not implemented
sf_positions rs.b no_of_positions pattern nos.
sf_ident rs.l 1 identifier 'M.K.'
sf_patterns rs.w 0 patterns start here
* pattern format
*
* 16 bytes/row : 4 bytes per voice
* format : $spppsfnn
* where ppp = note (period value)
* ss = instrument no. (0 or $01..$1F)
* f = special function (0..$F)
* nn = parameters for function
*
* function no. parameters
*
* arpeggio 0 2nd halfnote 3rd halfnote
* porta up 1 speed
* porta down 2 speed
* tone porta 3 speed
* vibrato 4 vibratospeed vibratosize
* volume slide A upslide downslide
* jump B position
* set volume C volume
* pattern break D 0 0
* set filter E 0 0=on/1=off
* set speed F speed
*------------------------------
* TESTER
test lea mt_data(pc),a0
bsr.s mt_init setup
.loop move.l _custom+4,d0 wait for v64
lsr.l #8,d0
and.w #$1FF,d0
cmp.w #128,d0
bne.s .loop
move.w #$070,_custom+$180 border=green
bsr mt_music irq routine
move.w #$000,_custom+$180
btst #6,$BFE001 until right button
bne.s .loop
bsr mt_end all done
moveq #0,d0 ok
rts
*------------------------------
* PLAYER
* initialize song
* entry a0=song file address
* exit d0-d2,a0-a3 used
mt_init lea mt_vars(pc),a3
move.l a0,mv_file(a3)
move.b sf_length(a0),mv_length(a3) save length
lea sf_positions(a0),a1 find maximum pattern no.
moveq #no_of_positions-1,d0
moveq #0,d2
.find move.b (a1)+,d1
cmp.b d1,d2
bgt.s .find2
move.b d1,d2
.find2 dbra d0,.find
addq.b #1,d2
mulu #pattern_size,d2
lea sf_patterns(a0),a2
add.l d2,a2 a2=samples
lea sf_instr(a0),a0 a0=instrument info
lea mt_sampleinfo(pc),a1 a1=sample info
moveq #no_of_instruments-1,d0 for each instrument
.instr clr.l (a2) wipe start of sample
move.l a2,(a1) save addr
moveq #0,d1
move.w in_length(a0),d1
move.w d1,4(a1) save length
add.l d1,d1
add.l d1,a2 step 2*length bytes
move.w in_volume(a0),12(a1) save volume
moveq #0,d3
move.w in_repeat(a0),d3 if repeat<>0 then
beq.s .norep
move.l (a1),d2
asl.w #1,d3
add.l d3,d2
move.l d2,6(a1) set repeat addr
move.w in_repeat(a0),d0
add.w in_replen(a0),d0
move.w d0,4(a1) set length
bra.s .next
.norep move.l (a1),6(a1) else repeat addr = addr
.next move.w in_replen(a0),10(a1) set repeat length
lea in_size(a0),a0 next
lea 16(a1),a1
dbra d0,.instr
or.b #2,$bfe001 LED off i.e. filter off
lea _custom,a0
clr.w aud0+ac_vol(a0) clear volumes
clr.w aud1+ac_vol(a0)
clr.w aud2+ac_vol(a0)
clr.w aud3+ac_vol(a0)
move.b #6,mv_speed(a3) default tempo
clr.b mv_songpos(a3) position 0
clr.b mv_counter(a3) frame 0
clr.w mv_pattpos(a3) row 0
rts
* end song
* exit a0 used
mt_end lea _custom,a0
clr.w aud0+ac_vol(a0) clear volumes
clr.w aud1+ac_vol(a0)
clr.w aud2+ac_vol(a0)
clr.w aud3+ac_vol(a0)
move.w #$000F,dmacon(a0) disable audio dma
rts
* music irq handler
* exit all registers preserved
* note call on a vbl
mt_music
movem.l d0-d4/a0-a6,-(a7) save used registers
lea mt_vars(pc),a3 local variables
lea _custom,a4 hardware
move.l mv_file(a3),a0 a0=song file
addq.b #1,mv_counter(a3) frame+1
move.b mv_counter(a3),d0
cmp.b mv_speed(a3),d0 if frame<speed then
bge.s .getnew
lea mt_voice1(pc),a6 update each voice
lea aud0(a4),a5
bsr mt_checkcom
lea mt_voice2(pc),a6
lea aud1(a4),a5
bsr mt_checkcom
lea mt_voice3(pc),a6
lea aud2(a4),a5
bsr mt_checkcom
lea mt_voice4(pc),a6
lea aud3(a4),a5
bsr mt_checkcom
bra .endr
.getnew clr.b mv_counter(a3) else frame=0
move.l mv_file(a3),a0 check new notes
lea sf_positions(a0),a2 a2=positions
lea sf_patterns(a0),a0 a0=patterns
moveq #0,d0
move.l d0,d1
move.b mv_songpos(a3),d0
move.b (a2,d0.w),d1 get current pattern no.
asl.l #8,d1
asl.l #2,d1
add.l d1,a0
add.w mv_pattpos(a3),a0 a0=ptr to current pattern
lea mt_voice1(pc),a6
move.l (a0)+,vi_command(a6) get command bytes
move.l (a0)+,vi_size+vi_command(a6)
move.l (a0)+,2*vi_size+vi_command(a6)
move.l (a0)+,3*vi_size+vi_command(a6)
clr.w mv_dmacon(a3) no voices selected
lea aud0(a4),a5 update each voice
lea mt_voice1(pc),a6
bsr mt_playvoice
lea aud1(a4),a5
lea mt_voice2(pc),a6
bsr mt_playvoice
lea aud2(a4),a5
lea mt_voice3(pc),a6
bsr mt_playvoice
lea aud3(a4),a5
lea mt_voice4(pc),a6
bsr mt_playvoice
move.w #300,d0 delay
.wait dbra d0,.wait
move.w mv_dmacon(a3),d0 enable flagged voices
or.w #$8000,d0
move.w d0,dmacon(a4)
move.w #300,d0 delay
.wait2 dbra d0,.wait2
lea mt_voice1(pc),a6
move.l vi_repeat(a6),aud0+ac_ptr(a4) set repeat address,length
move.w vi_replen(a6),aud0+ac_len(a4)
move.l vi_size+vi_repeat(a6),aud1+ac_ptr(a4)
move.w vi_size+vi_replen(a6),aud1+ac_len(a4)
move.l 2*vi_size+vi_repeat(a6),aud2+ac_ptr(a4)
move.w 2*vi_size+vi_replen(a6),aud2+ac_len(a4)
move.l 3*vi_size+vi_repeat(a6),aud3+ac_ptr(a4)
move.w 3*vi_size+vi_replen(a6),aud3+ac_len(a4)
add.w #row_size,mv_pattpos(a3) bump pattern row
cmp.w #pattern_size,mv_pattpos(a3) if end of pattern then
bne.s .endr
.nex clr.w mv_pattpos(a3) row=0
clr.b mv_break(a3) cancel break flag
move.b mv_songpos(a3),d1 next position
addq.b #1,d1
and.b #no_of_positions-1,d1
cmp.b mv_length(a3),d1 if end of song then
bne.s .ok
moveq #0,d1 restart
.ok move.b d1,mv_songpos(a3)
.endr move.b mv_break(a3),d0 if pattern break then next
bne.s .nex
movem.l (a7)+,d0-d4/a0-a6 restore registers
rts
* update voice for new note
* entry d1=index into current pattern
* a5=audio ptr
* a6=voice info
mt_playvoice
moveq #0,d2
move.b vi_command+2(a6),d2 get instrument no.
lsr.b #4,d2
move.b vi_command(a6),d0
and.b #$F0,d0
or.b d0,d2 if new instrument then
beq.s .setreg
lsl.w #4,d2 get parameters
lea mt_sampleinfo-16(pc),a1
add.w d2,a1
move.l (a1)+,vi_addr(a6)
move.w (a1)+,vi_length(a6)
move.l (a1)+,vi_repeat(a6)
move.w (a1)+,vi_replen(a6)
move.w (a1)+,vi_volume(a6)
.setreg move.w vi_volume(a6),ac_vol(a5) set chip volume
move.w vi_command(a6),d2 get period
and.w #$FFF,d2
beq mt_checkcom2 if period<>0 then
move.b vi_command+2(a6),d0
and.b #$F,d0 if command=3 then
cmp.b #$3,d0
bne.s .setper set portamento
move.w d2,vi_tperiod(a6) set dest. period
clr.b vi_tdir(a6)
cmp.w vi_period(a6),d2 cancel if = period
beq.s .port1 set direction flag
bge.s .port2
addq.b #1,vi_tdir(a6)
bra.s .port2
.port1 clr.w vi_tperiod(a6)
.port2 bra mt_checkcom2
.setper move.w vi_voice(a6),d0 else
move.w d0,dmacon(a4) disable voice
or.w d0,mv_dmacon(a3) flag voice used
move.w d2,vi_period(a6) set period
clr.b vi_vframe(a6) clear vibrato frame
move.l vi_addr(a6),ac_ptr(a5) set chip address
move.w vi_length(a6),ac_len(a5) set chip length
move.w d2,ac_per(a5) set chip period
bra mt_checkcom2
* check commands 1..4,10
* entry A5=audio ptr
* A6=voice info
mt_checkcom
move.w vi_command+2(a6),d0 skip if no command
and.w #$FFF,d0
beq.s .skip
lsr.w #6,d0
and.w #$003C,d0
jmp .v0(pc,d0.w)
.v0 bra mt_arpeggio (quicker)
.v1 bra mt_portup
.v2 bra mt_portdown
.v3 bra mt_myport
.v4 bra mt_vib
.v5 bra .skip
.v6 bra .skip
.v7 bra .skip
.v8 bra .skip
.v9 bra .skip
.vA bra mt_volslide
.vB bra .skip
.vC bra .skip
.vD bra .skip
.vE bra .skip
.vF bra .skip
.skip move.w vi_period(a6),ac_per(a5)
rts
* do arpeggio
mt_arpeggio
moveq #0,d0
move.b mv_counter(a3),d0 cycle = counter mod 3
divs #3,d0
swap d0
cmp.w #1,d0
bcs.s .arp2
bne.s .arp1
moveq #0,d0 cycle=1 : period+2nd halfnote
move.b vi_command+3(a6),d0
lsr.b #4,d0
bra.s .arp3
.arp1 moveq #0,d0 cycle=2 : period+3rd halfnote
move.b vi_command+3(a6),d0
and.b #$F,d0
.arp3 asl.w #1,d0
moveq #0,d1
lea mt_periods(pc),a0
move.w vi_period(a6),d1
moveq #37-1,d7
.loop move.w (a0,d0.w),d2 find new period
cmp.w (a0)+,d1
bge.s .arp4
dbra d7,.loop
rts
.arp2 move.w vi_period(a6),d2 cycle=0 : period
.arp4 move.w d2,ac_per(a5) set chip period
rts
* portamento up
mt_portup
moveq #0,d0
move.b vi_command+3(a6),d0
sub.w d0,vi_period(a6) period-offset
move.w vi_period(a6),d0
and.w #$FFF,d0
cmp.w #$71,d0 min $71
bpl.s .ok
and.w #$F000,vi_period(a6)
or.w #$71,vi_period(a6)
.ok move.w d0,ac_per(a5) set chip period
rts
* portamento down
mt_portdown
moveq #0,d0
move.b vi_command+3(a6),d0
add.w d0,vi_period(a6) period+offset
move.w vi_period(a6),d0
and.w #$FFF,d0
cmp.w #$358,d0 max $358
bmi.s .ok
and.w #$F000,vi_period(a6)
or.w #$358,vi_period(a6)
.ok move.w d0,ac_per(a5) set chip period
rts
* do tone portamento
mt_myport
move.b vi_command+3(a6),d0 if new speed then
beq.s .slide
move.b d0,vi_tspeed(a6) set speed
clr.b vi_command+3(a6)
.slide tst.w vi_tperiod(a6) skip if off
beq.s .skip
moveq #0,d0 get speed
move.b vi_tspeed(a6),d0
tst.b vi_tdir(a6) if up then
bne.s .minus
add.w d0,vi_period(a6) period+speed
move.w vi_tperiod(a6),d0
cmp.w vi_period(a6),d0 if >=dest then done
bgt.s .ok
bra.s .done
.minus sub.w d0,vi_period(a6) else
move.w vi_tperiod(a6),d0 period-speed
cmp.w vi_period(a6),d0
blt.s .ok if <=dest then
.done move.w vi_tperiod(a6),vi_period(a6) period=dest
clr.w vi_tperiod(a6) cancel
.ok move.w vi_period(a6),ac_per(a5) set chip period
.skip rts
* do vibrato
mt_vib move.b vi_command+3(a6),d0 if new speed/size then
beq.s .vi
move.b d0,vi_vspeed(a6) set speed/size
.vi move.b vi_vframe(a6),d0 get frame
lsr.w #2,d0
and.w #$1F,d0
moveq #0,d2
move.b .sine(pc,d0.w),d2 index offset = 255*sin(frame)
move.b vi_vspeed(a6),d0 *size/64
and.w #$F,d0
mulu d0,d2
lsr.w #6,d2
move.w vi_period(a6),d0
tst.b vi_vframe(a6) set chip period+/-offset
bpl.s .plus
neg.w d2
.plus add.w d2,d0
move.w d0,ac_per(a5)
move.b vi_vspeed(a6),d0 frame+speed
lsr.w #2,d0
and.w #$3C,d0
add.b d0,vi_vframe(a6)
rts
* fn(i=0..31)=255*sin(i*360/32)
.sine dc.b $00,$18,$31,$4a,$61,$78,$8d,$a1
dc.b $b4,$c5,$d4,$e0,$eb,$f4,$fa,$fd
dc.b $ff,$fd,$fa,$f4,$eb,$e0,$d4,$c5
dc.b $b4,$a1,$8d,$78,$61,$4a,$31,$18
even
* volume slide
mt_volslide
move.w vi_period(a6),ac_per(a5) set period
moveq #0,d0
move.b vi_command+3(a6),d0
cmp.b #16,d0 if high nibble <> 0 then
bcs.s .down
lsr.b #4,d0
add.w vi_volume(a6),d0 volume+offset, max 64
cmp.w #64,d0
bmi.s .vol2
moveq #64,d0
bra.s .vol2
.down and.b #$F,d0 else
neg.w d0
add.w vi_volume(a6),d0 volume-offset, min 0
bpl.s .vol2
moveq #0,d0
.vol2 move.w d0,vi_volume(a6)
move.w d0,ac_vol(a5) set chip volume
rts
* check for commands B..F
mt_checkcom2
move.b vi_command+2(a6),d0 get command no.
and.w #$000F,d0
add.w d0,d0
jmp .v0(pc,d0.w)
.v0 rts (quicker)
.v1 rts
.v2 rts
.v3 rts
.v4 rts
.v5 rts
.v6 rts
.v7 rts
.v8 rts
.v9 rts
.vA rts
.vB bra.s .jump
.vC bra.s .setvol
.vD bra.s .break
.vE bra.s .filter
.vF bra.s .speed
.filter move.b vi_command+3(a6),d0
and.b #1,d0
add.b d0,d0
and.b #$FD,$BFE001 0=on/1=off
or.b d0,$BFE001
rts
.jump move.b vi_command+3(a6),d0
subq.b #1,d0
move.b d0,mv_songpos(a3) set song position
.break not.b mv_break(a3) force break
rts
.setvol moveq #0,d0
move.b vi_command+3(a6),d0 max 64
cmp.b #64,d0
ble.s .sv2
moveq #64,d0
.sv2 move.w d0,vi_volume(a6)
move.w d0,ac_vol(a5)
rts
.speed move.b vi_command+3(a6),d0
and.w #31,d0 skip if 0
beq.s .speed2
clr.b mv_counter(a3)
move.b d0,mv_speed(a3)
.speed2 rts
*------------------------------
* TABLES
mt_periods
dc.w $0358,$0328,$02fa,$02d0,$02a6,$0280
dc.w $025c,$023a,$021a,$01fc,$01e0,$01c5
dc.w $01ac,$0194,$017d,$0168,$0153,$0140
dc.w $012e,$011d,$010d,$00fe,$00f0,$00e2
dc.w $00d6,$00ca,$00be,$00b4,$00aa,$00a0
dc.w $0097,$008f,$0087,$007f,$0078,$0071
dc.w 0,0
*------------------------------
* VARIABLES
mt_vars ds.b mv_size
even
* sample info
* 16 bytes per sample = addr.l,length.w,repeat.l,replen.w,volume.w,padding.w
mt_sampleinfo
ds.b no_of_instruments*16
* voice info (see rs at top of file)
mt_voice1
ds.l 5
dc.w $0001 dma select mask
ds.w 3
mt_voice2
ds.l 5
dc.w $0002
ds.w 3
mt_voice3
ds.l 5
dc.w $0004
ds.w 3
mt_voice4
ds.l 5
dc.w $0008
ds.w 3
*------------------------------
* MODULE
mt_data incbin "st-00:modules/mod.scav3"
*------------------------------
end