******************************************************
*                                                    *
*         Sound-Tracker V2.0 Replay-Routine          *
*       >>>---------------------------------<<<      *
*                                                    *
*        Written by Mr. Magic in 1988 by using       *
*          Sound-Tracker V2.0 Replay-Routine         *
*                                                    *
*     This Routine needs only the Song-File Name     *
* It will load the Instruments in CHIP_MEM and free  *
*         the MEM after playing the song.            *
*                                                    *
******************************************************

mt_speed=$1f4
SongLenMax=30000

PlayMain:
  bsr OpenDos       ; Open dos.library
  bsr LoadSong
  cmp.l #-2,d0
  beq EndePrg
  cmp.l #5,d0
  beq EndePrg2
  bsr LoadInstrumente
PlayStart:
  bsr mt_init
  move.w #$4000,$dff09a
  move.l $00006c,mt_oldirq
  move.l #mt_newirq,$00006c
  move.w #$c000,$dff09a

mt_wait:
  btst  #6,$bfe001
  bne.s mt_wait

  move.w #$000f,$dff096
  move.w #$4000,$dff09a
  move.l mt_oldirq,$00006c
  move.w #$c000,$dff09a
  bsr FreeInstruments
  clr.l  d0
  rts
EndePrg:
  rts
EndePrg2:   ;SongFile zu lang
  rts

ErrorSongFile:
  move.l #-2,d0
  rts

FreeInstruments:
  move.l 4,a6
  lea SongData,a4
  lea SampleMem,a5
  add.l #40,a4       ;Song-Name und 1. Instr ueberlesen
  move.l #14,d7      ;15 instrumente
FreeLoop:
  cmp.l #0,(a5)      ;wurde fuer Instrument Speicher reserviert???
                     ;0=nein (Kein Speicher)
  beq NextFreeInstr  ;dann naechstes Instrument
  move.l (a4),d0     ;len des instr
  mulu #2,d0         ;in WORTEN (2 bytes) umrechene
  move.l (a5),a1
  jsr -210(a6)      ;FreeMem
NextFreeInstr:
  add.l #30,a4
  add.l #4,a5        ;Sample Mem List
  dbf d7,FreeLoop
  rts

LoadInstrumente:
  move.l #14,d7
  lea SongData,a5
  add.l #20,a5     ;Song Name ueberlesen
LoadInstrLoop:
  bsr ClearInstrFile
  bsr ClearInstrName
  bsr SetInstrUnit
  bsr SetInstrFile ;instrumentenName in InstrFile copieren
  move.l (a5),d0
  mulu #2,d0       ;Instrument laenge in WORTEN (2bytes)
  move.l d0,InstrLen   ;Laenge des Instruments eintragen
  add.l #10,a5          ;Volumen und noch 4 bytes ueberlesen
                       ;jetzt steht naechstes instr in a5
  bsr GetMemForInstr     ;Speicher fuer Instrument holen
  cmp.l #0,d0            ;0=nicht genug Speicher da
  beq NoMemoryForInstr   ;Error->No Memory
  move.l a5,SongDataZeiger  ;a5:Zeiger auf SongData retten
  bsr OpenInstrFile
  cmp.l #0,d0               ;0=kann instr nicht oeffnen (I. nicht da)
  beq InstrNotFound
  bsr ReadInstrData
  bsr CloseInstrFile
InstrNotFound:
  move.l SongDataZeiger,a5        ;a5:Zeiger auf SongData holen
  dbf d7,LoadInstrLoop
  clr.l d0
  rts

NoMemoryForInstr:
  move.l #1,d0
  rts
NoInstrToLoad:
  move.l #2,d0
  rts

GetMemForInstr:
  cmp.l #0,instrlen
  beq NoInstrumentToAlloc
  move.l 4,a6
  move.l #$10003,d1
  move.l InstrLen,d0
  jsr -198(a6)
  move.l d0,InstrMemory
  lea SampleMem,a0
  add.l SampleNr,a0
  move.l d0,(a0)        ;memory in Sample liste eintragen
  lea sample1,a0
  add.l SampleNr,a0
  move.l d0,(a0)        ;Adresse von Instrument eintragen
NoInstrumentToAlloc:
  add.l #4,SampleNr
  move.l #1,d0
  rts

LoadSong:
  bsr ClearSongFile
  bsr SetSongUnit
  bsr SetSongName
  bsr OpenSongFile  ; Open Song File
  beq ErrorSongFile
  bsr ReadSongFile  ; Song data lesen
  bsr CloseSongFile ; Song-File schliessen
  rts

OpenDos:
  lea dosname,a1
  move.l 4,a6
  jsr -408(a6)
  move.l d0,dosbase
  rts

SetSongUnit:
  lea SongUnit,a0
  lea SongFile,a1
  move.l #19,d0
CopyLoop00:
  sub.l #1,d0
  cmp.l #0,d0
  beq EndeCopyLoop00
  move.b (a0)+,(a1)+
  cmp.b #0,(a0)
  bne CopyLoop00
EndeCopyLoop00:
  rts

SetInstrUnit:
  lea InstrUnit,a0
  lea InstrFile,a1
  move.l #19,d0
CopyLoop01:
  sub.l #1,d0
  cmp.l #0,d0
  beq EndeCopyLoop01
  move.b (a0)+,(a1)+
  cmp.b #0,(a0)
  bne CopyLoop01
EndeCopyLoop01:
  rts

SetInstrFile:
  move.l #19,d0
CopyLoop03:
  move.b (a5)+,(a1)+
  dbf d0,CopyLoop03
EndeCopyLoop03:
  rts

SetSongName:
  lea SongName,a0
  move.l #40,d0
CopyLoop02:
  sub.l #1,d0
  cmp.l #0,d0
  beq EndeCopyLoop02
  move.b (a0)+,(a1)+
  cmp.b #0,(a0)
  bne CopyLoop02
EndeCopyLoop02:
  rts

OpenSongFile:
  move.l dosbase,a6
  move.l #SongFile,d1
  move.l #1005,d2
  jsr -30(a6)
  move.l d0,SongHd
  rts

OpenInstrFile:
  move.l dosbase,a6
  move.l #InstrFile,d1
  move.l #1005,d2
  jsr -30(a6)
  move.l d0,InstrHd
  rts

CloseInstrFile:
  move.l dosbase,a6
  move.l InstrHd,d1
  jsr -30(a6)
  rts

ReadInstrData:
  move.l dosbase,a6
  move.l InstrHD,d1
  move.l InstrMemory,d2
  move.l InstrLen,d3
  jsr -42(a6)               ;Read
  rts

ReadSongFile:
  move.l dosbase,a6
  move.l SongHD,d1
  move.l #SongData,d2
  move.l #SongLenMax,d3
  jsr -42(a6)               ;Read
  move.l d0,LoadedBytes
  cmp.l #SongLenMax,d0
  bne OkAllLoaded
  clr.l d0
  rts
OkAllLoaded:
  move.l #5,d0
  rts

CloseSongFile:
  move.l dosbase,a6
  move.l SongHD,d1
  jsr -36(a6)  
  rts

ClearInstrFile:
  movem.l d0/a0,-(sp)
  lea InstrFile,a0
  move.l #29,d0
ClearLoop00:
  clr.b (a0)+
  dbf d0,ClearLoop00
  movem.l (sp)+,d0/a0
  rts

ClearInstrName:
  movem.l d0/a0,-(sp)
  lea InstrName,a0
  move.l #29,d0
ClearLoop03:
  clr.b (a0)+
  dbf d0,ClearLoop03
  movem.l (sp)+,d0/a0
  rts

ClearSongFile:
  movem.l d0/a0,-(sp)
  lea SongFile,a0
  move.l #49,d0
ClearLoop01:
  clr.b (a0)+
  dbf d0,ClearLoop01
  movem.l (sp)+,d0/a0
  rts

mt_init:
  move.l #sample1,a0
  clr.l d0
mt_clear:
  move.l (a0,d0),a1
  clr.l (a1)
  addq #4,d0
  cmp.l #$3c,d0
  bne.s mt_clear

move.w #0,$dff0a8
move.w #0,$dff0b8
move.w #0,$dff0c8
move.w #0,$dff0d8
eor.w #$c000,mt_voice0+12
clr.l mt_partnrplay
clr.l mt_partnote
clr.l mt_partpoint

move.b SongData+$1d6,mt_maxpart+1
move.b SongData+$1d7,mt_kn1+1
rts

mt_newirq:
movem.l		d0-d7/a0-a6,-(a7)
bsr		mt_music
movem.l		(a7)+,d0-d7/a0-a6
dc.w $4ef9
mt_oldirq: dc.l 0

mt_music:
addq.l		#1,mt_counter
cmp.l		#6,mt_counter
bne.s		mt_notsix
clr.l		mt_counter
bra.L		mt_rout2

mt_notsix:
lea		mt_aud1temp,a6
tst.b		3(a6)
beq.s		mt_arp1
move.l		#$dff0a0,a5		
bsr.s		mt_arprout

mt_arp1:
lea		mt_aud2temp,a6
tst.b		3(a6)
beq.s		mt_arp2
move.l		#$dff0b0,a5
bsr.s		mt_arprout

mt_arp2:
lea		mt_aud3temp,a6
tst.b		3(a6)
beq.s		mt_arp3
move.l		#$dff0c0,a5
bsr.s		mt_arprout

mt_arp3:
lea		mt_aud4temp,a6
tst.b		3(a6)
beq.s		mt_arp4
move.l		#$dff0d0,a5
bsr.s		mt_arprout
mt_arp4:
bra.L		mt_stop


mt_arprout:
tst.w	24(a6)
beq.s	mt_noslide

clr.w	d0
move.b	25(a6),d0
lsr.b	#4,d0
tst.b	d0
beq.s	mt_voldwn2
bsr.L	mt_pushvol1
bra.s	mt_noslide

mt_voldwn2:
clr.w	d0
move.b	25(a6),d0
bsr.L	mt_pushvol2

mt_noslide:
move.b	2(a6),d0
and.b	#$0f,d0
tst.b	d0
beq.L	mt_arpegrt
cmp.b	#3,d0
beq.L	mt_arpegrt
cmp.b	#4,d0
beq.L	mt_arpegrt
cmp.b	#5,d0
beq.L	mt_arpegrt
cmp.b	#1,d0
beq.s	mt_portup
cmp.b	#6,d0
beq.s	mt_portup
cmp.b	#7,d0
beq.s	mt_portup
cmp.b	#8,d0
beq.s	mt_portup
cmp.b	#2,d0
beq.s	mt_portdwn
cmp.b	#9,d0
beq.s	mt_portdwn
cmp.b	#10,d0
beq.s	mt_portdwn
cmp.b	#11,d0
beq.s	mt_portdwn
cmp.b	#13,d0
beq.s	mt_volup
rts

mt_portup:
clr.w	d0
move.b	3(a6),d0
sub.w	d0,22(a6)
cmp.w	#$71,22(a6)
bpl.s	mt_ok1
move.w	#$71,22(a6)
mt_ok1:
move.w	22(a6),6(a5)
rts

mt_portdwn:
clr.w	d0
move.b	3(a6),d0
add.w	d0,22(a6)
cmp.w	#$358,22(a6)
bmi.s	mt_ok2
move.w	#$358,22(a6)
mt_ok2:
move.w	22(a6),6(a5)
rts

mt_volup:
clr.w	d0
move.b	3(a6),d0
lsr.b	#4,d0
tst.b	d0
beq.s	mt_voldwn
mt_pushvol1:
add.w	d0,$12(a6)
cmp.w	#$40,$12(a6)
bmi.s	mt_ok3
move.w	#$40,$12(a6)
mt_ok3:
move.w	$12(a6),8(a5)
rts

mt_voldwn:
clr.w	d0
move.b	3(a6),d0
mt_pushvol2:
and.b	#$0f,d0
sub.w	d0,$12(a6)
bpl.s	mt_ok4
clr.w	$12(a6)
mt_ok4:
move.w	$12(a6),8(a5)
rts

mt_arpegrt:
cmp.l		#1,mt_counter
beq.s		mt_loop2
cmp.l		#2,mt_counter
beq.s		mt_loop3
cmp.l		#3,mt_counter
beq.s		mt_loop4
cmp.l		#4,mt_counter
beq.s		mt_loop2
cmp.l		#5,mt_counter
beq.s		mt_loop3
rts

mt_loop2:
clr.l		d0
move.b		3(a6),d0
lsr.b		#4,d0
bra.s		mt_cont

mt_loop3:
clr.l		d0
move.b		3(a6),d0
and.b		#$0f,d0
bra.s		mt_cont

mt_loop4:
move.w		16(a6),d2
bra.s		mt_endpart

mt_cont:
lsl.w		#1,d0
clr.l		d1
move.w		16(a6),d1
lea		mt_arpeggio,a0
mt_loop5:
move.w		(a0,d0),d2
cmp.w		(a0),d1
beq.s		mt_endpart
addq.l		#2,a0
bra.s		mt_loop5

mt_endpart:
move.w		d2,6(a5)
rts

mt_rout2:
lea		SongData,a0
move.l		a0,a3
add.l		#$0c,a3
move.l		a0,a2
add.l		#$1d8,a2
add.l		#$258,a0
move.l		mt_partnrplay,d0
clr.l		d1
move.b		(a2,d0),d1
mulu		#$0400,d1
add.l		mt_partnote,d1
move.l		d1,mt_partpoint
clr.w		mt_dmacon

move.l		#$dff0a0,a5
lea		mt_aud1temp,a6
bsr.L		mt_playit

move.l		#$dff0b0,a5
lea		mt_aud2temp,a6
bsr.L		mt_playit

move.l		#$dff0c0,a5
lea		mt_aud3temp,a6
bsr.L		mt_playit

move.l		#$dff0d0,a5
lea		mt_aud4temp,a6
bsr.L		mt_playit

move.l		#mt_speed,d0
mt_rls:
dbf		d0,mt_rls

move.l		#$8000,d0
add.w		mt_dmacon,d0
move.w		d0,$dff096

move.l		#mt_aud4temp,a6
cmp.w		#1,14(a6)
bne.s		mt_voice3
move.l		10(a6),$dff0d0
move.w		#1,$dff0d4
mt_voice3:
move.l		#mt_aud3temp,a6
cmp.w		#1,14(a6)
bne.s		mt_voice2
move.l		10(a6),$dff0c0
move.w		#1,$dff0c4
mt_voice2:
move.l		#mt_aud2temp,a6
cmp.w		#1,14(a6)
bne.s		mt_voice1
move.l		10(a6),$dff0b0
move.w		#1,$dff0b4
mt_voice1:
move.l		#mt_aud1temp,a6
cmp.w		#1,14(a6)
bne.s		mt_voice0
move.l		10(a6),$dff0a0
move.w		#1,$dff0a4

mt_voice0:
lea		mt_modulate,a0
move.l		mt_partnote,d0
lsl.b		#7,d0
add.l		#$10,d0
move.l		d0,mt_partnote
cmp.l		#$400,d0
bne.s		mt_stop
clr.l		mt_partnote
addq.l		#1,mt_partnrplay
clr.l		d0
move.w		mt_maxpart,d0
move.l		mt_partnrplay,d1
cmp.l		d0,d1
bne.s		mt_stop
clr.l		mt_partnrplay
mt_stop:
rts


mt_playit:
move.l		(a0,d1),(a6)
addq.l		#4,d1
clr.l		d2
move.b		2(a6),d2
and.b		#$f0,d2
lsr.b		#4,d2
tst.b		d2
beq.s		mt_nosamplechange

clr.l		d3
lea		mt_samples,a1
move.l		d2,d4
mulu		#4,d2
mulu		#$1e,d4
move.l		(a1,d2),4(a6)
move.w		(a3,d4),8(a6)
move.w		2(a3,d4),18(a6)
move.w		4(a3,d4),d3
tst.w		d3
beq.s		mt_displace
move.l		4(a6),d2
add.l		d3,d2
move.l		d2,4(a6)
move.l		d2,10(a6)
move.w		6(a3,d4),8(a6)
move.w		6(a3,d4),14(a6)
move.w		18(a6),8(a5)
bra.s		mt_nosamplechange
mt_displace:
move.l		4(a6),d2
add.l		d3,d2
move.l		d2,10(a6)
move.w		6(a3,d4),14(a6)
move.w		18(a6),8(a5)
mt_nosamplechange:
tst.w		(a6)
beq.s		mt_retrout
move.w		(a6),16(a6)
move.w		20(a6),$dff096
move.l		4(a6),(a5)
move.w		8(a6),4(a5)
move.w		(a6),6(a5)
move.w		20(a6),d0
or.w		d0,mt_dmacon

mt_retrout:
move.w	20(a6),d0
lsl.w	#4,d0
add.w	20(a6),d0
move.w	d0,$dff09e

tst.w	(a6)
beq.s	mt_nonewper
move.w	(a6),22(a6)
mt_nonewper:

move.b	2(a6),d0
and.b	#$0f,d0
cmp.b	#14,d0
bne.s	mt_noset
move.w	2(a6),24(a6)
rts
mt_noset:
tst.b	3(a6)
bne.s	mt_noclr
clr.w	24(a6)
mt_noclr:
cmp.b	#3,d0
beq.s	mt_modvol
cmp.b	#6,d0
beq.s	mt_modvol
cmp.b	#9,d0
beq.s	mt_modvol
cmp.b	#4,d0
beq.s	mt_modper
cmp.b	#7,d0
beq.s	mt_modper
cmp.b	#10,d0
beq.s	mt_modper
cmp.b	#5,d0
beq.s	mt_modvolper
cmp.b	#8,d0
beq.s	mt_modvolper
cmp.b	#11,d0
beq.s	mt_modvolper
cmp.b	#12,d0
bne.s	mt_nochnge
move.b	3(a6),8(a5)
mt_nochnge:
rts

mt_modvol:
move.w	20(a6),d0
bra.s	mt_push

mt_modper:
move.w	20(a6),d0
lsl.w	#4,d0
bra.s	mt_push

mt_modvolper:
move.w	20(a6),d0
lsl.w	#4,d0
add.w	20(a6),d0

mt_push:
add.w	#$8000,d0
move.w	d0,$dff09e
rts


mt_aud1temp:
dc.w $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
dc.w $0000,$0000,$0001,$0000,$0000
mt_aud2temp:
dc.w $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
dc.w $0000,$0000,$0002,$0000,$0000
mt_aud3temp:
dc.w $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
dc.w $0000,$0000,$0004,$0000,$0000
mt_aud4temp:
dc.w $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000
dc.w $0000,$0000,$0008,$0000,$0000
mt_partnote: dc.l 0
mt_partnrplay: dc.l 0
mt_counter: dc.l 0
mt_partpoint: dc.l 0
mt_samples: dc.w $0000,$0000
sample1: dc.l 0
sample2: dc.l 0
sample3: dc.l 0
sample4: dc.l 0
sample5: dc.l 0
sample6: dc.l 0
sample7: dc.l 0
sample8: dc.l 0
sample9: dc.l 0
sample10: dc.l 0
sample11: dc.l 0
sample12: dc.l 0
sample13: dc.l 0
sample14: dc.l 0
sample15: dc.l 0
mt_maxpart: dc.w $0000
mt_kn1:     dc.w $0000
mt_dmacon:  dc.w $0000

mt_modulate:
dc.w $0c39,$0039,$00bf,$ec01,$6630,$0839,$0007,$00bf
dc.w $e001,$6626,$2c79,$0000,$0004,$43fa,$0020,$4eae
dc.w $fe68,$2c40,$4280,$41fa,$0026,$223c,$0000,$0032
dc.w $4eae,$ffa6,$60ee,$0000,$0000,$4e75,$696e,$7475
dc.w $6974,$696f,$6e2e,$6c69,$6272,$6172,$7900,$0104
dc.w $1753,$6f75,$6e64,$5472,$6163,$6b65,$7220,$5632
dc.w $0063,$00f0,$20a9,$2054,$6865,$204a,$756e,$676c
dc.w $6520,$436f,$6d6d,$616e,$6400,$0000

mt_arpeggio:
dc.w $0358,$0328,$02fa,$02d0,$02a6,$0280,$025c
dc.w $023a,$021a,$01fc,$01e0,$01c5,$01ac,$0194,$017d
dc.w $0168,$0153,$0140,$012e,$011d,$010d,$00fe,$00f0
dc.w $00e2,$00d6,$00ca,$00be,$00b4,$00aa,$00a0,$0097
dc.w $008f,$0087,$007f,$0078,$0071,$0000,$0000,$0000

InstrUnit: dc.b 'ST-01:'    ;hier Pfad fuer Instruments angeben
           blk.b 20-6,0
SongUnit:  dc.b 'df0:songs/' ;hier Pfad fuer Song-Files angeben
           blk.b 20-10,0
SongName:  dc.b 'pat'        ;hier Name des Song-Files eintragen
           blk.b 40-4,0
InstrName:     blk.b 40,0    ;\
SongFile:      blk.b 50,0    ; | hier nicht eintragen, wird vom PRG gemacht!
InstrFile:     blk.b 50,0    ;/
align 4

dosbase:       dc.l 0
SongHD:        dc.l 0
InstrHD:       dc.l 0
LoadedBytes:   dc.l 0
InstrLen:      dc.l 0
InstrMemory:   dc.l 0
SampleMem:     blk.l 16,0
SampleNr:      dc.l 0
SongDataZeiger:dc.l 0

dosname:       dc.b 'dos.library',0

align 4
SongData: blk.l SongLenMax/4,0
