#type &ffa
#name StasisMod
#base 0
#include ASMLib:Standard
#include StasisMod:Header
#include StasisMod:format

#set Service_StasisRate = &80313

#set startslot=80
#set startchan=5
#set status_fade	=1
#set status_pending	=1<<1

struct v {
  .ticker	DCD 0
  .lastticker	DCD 0
  .threaded	DCD 0
  .status	DCD 0
  .speed	DCD 0
  .speedctr	DCD 0
  .delay	DCD 0
  .seqno	DCD 0
  .patno	DCD 0
  .noteno	DCD 0
  .linkedadr	DCD 0
  .linkedmod	DCD 0
  .nextmod	DCD 0
  .realtune	DCD 0
  .filetype	DCD 0
  .songtype	DCD 0
  .pause	DCD 0
  .voices	DCD 0
  .textbuf	DBB 16
  .chantab	DBB 8*ch_sizeof
  .modtab	DBB 8*m_sizeof
  .soundtab	DBB 48
  .pattab	DBD 128
  .sizeof
}
struct m {
  .addr		DCD 0
  .type		DCD 0
  .samparea	DCD 0
  .pattarea	DCD 0
  .sizeof
  }
  
#set m_sizeof=16
#set m_shift =4

struct ch {
  .stereo	DCD 0
  .volume	DCD 0
  .pitch	DCD 0
  .lastslot	DCD 0
  .sizeof   
}
#set ch_sizeof = 16
#set h_shift = 4

.ModuleHeader
DCD 0
DCD init
DCD final
DCD service	;service
DCD title
DCD help
DCD helptable
DCD 0
DCD 0
DCD 0
DCD 0
.title
DCB  "StasisMod"
DCB 0
ALIGN
.help
DCB  "Stasis Module Player",9,"1.00 (16 Oct 1994)"
DCB 0
ALIGN
.helptable
DCB  "StasisMod"
DCB 0
ALIGN
DCD 0
DCD 0
DCD 0
DCD stasishelp
DCB "PlayMod"
DCB 0
ALIGN
DCD loadcom
DCD &0002FF02
DCD loadsyn
DCD loadhelp
DCB "PlayStop"
DCB 0
ALIGN
DCD stopcom
DCD &0000FF00
DCD stopsyn
DCD stophelp

DCB "PlayPause"
DCB 0
ALIGN
DCD pausecom
DCD &0001FF01
DCD pausesyn
DCD pausehelp

DCB "PlayVoices"
DCB 0
ALIGN
DCD voicescom
DCD &0001FF01
DCD voicessyn
DCD voiceshelp

DCD 0 ;           end marker

.stasishelp
DCB "A module player for use with Stasis.   Andy Southgate but use freely."

DCB 0

.loadhelp
DCB 27
DCB 0
DCB  " loads and plays a module."
DCB 13
DCB 10
.loadsyn
DCB 27
DCB 1
DCB  " <slot> <filename>"
DCB 0
.stophelp
DCB 27,0," stops a playing module.",13,10
.stopsyn
DCB  27,1,0
.pausehelp
DCB 27,0," pauses/restarts a playing module.",13,10
.pausesyn
DCB  27,1," <0|1>",0
.voiceshelp
DCB 27,0," informs the module of the number of voices.  If eight, the module will use channels 5-8.",13,10
.voicessyn
DCB  27,1," <voices>",0
ALIGN
.nullswi
.nullcommand
MOV PC,R14

.routine
STMFD R13!,{R0-R11,R14}
LDR R0,[R12,#v.ticker]
ADD R0,R0,#1
STR R0,[R12,#v.ticker]
LDR R1,[R12,#v.lastticker]
SUB R0,R0,R1
CMP R0,#2
LDMLTFD R13!,{R0-R11,PC}
LDR R0,[R12,#v.pause]
CMP R0,#1
LDMEQFD R13!,{R0-R11,PC}
LDR R0,[R12,#v.threaded]
CMP R0,#0
LDMNEFD R13!,{R0-R11,PC}
MOV R0,#1
STR R0,[R12,#v.threaded]
MOV R0,PC
ORR R0,R0,#3
TEQP R0,#0  ;switch to SVC
MOV R0,R0
STMFD R13!,{R14}
LDR R0,[R12,#v.speedctr]
LDR R1,[R12,#v.speed]
ADD R0,R0,#1
CMP R0,R1
MOVGE R0,#0
STR R0,[R12,#v.speedctr]
BLT nopatproc

.patproc
LDR R0,[R12,#v.linkedmod]
CMP R0,#0
BLT notplaying
get_m
LDR R0,[R12,#v.linkedadr]
LDR R1,[R10,#m.addr]
CMP R0,R1
BLNE swapin
BLVS terminate
BVS abort
LDR R0,[R12,#v.linkedmod]
CMP R0,#0
BLT notplaying
get_m
LDR R0,[R12,#v.patno]
ADD R11,R12,#v.pattab
LDR R11,[R11,R0,LSL #2]
LDR R0,[R12,#v.noteno]
LDR R9,[R10,#m.addr]
LDR R8,[R9,#mod.tracks]
MUL R0,R8,R0
ADD R11,R11,R0,LSL #2; R11 now points to the current note
ADD R11,R11,R9
MOV R8,#1
.trackloop
STMFD R13!,{R8}
LDR R0,[R12,#v.voices]
CMP R0,#8
ADDEQ R8,R8,#4
LDR R0,[R12,#v.delay]
CMP R0,#0
BLEQ processnote
BL processeffect
LDMFD R13!,{R8}
ADD R11,R11,#4
ADD R8,R8,#1
LDR R0,[R9,#mod.tracks]
AND R0,R0,#7
CMP R8,R0
BLE trackloop

LDR R1,[R12,#v.delay]
SUBS R1,R1,#1
STRPL R1,[R12,#v.delay]
CMP R1,#0
LDR R0,[R12,#v.noteno]
ADDLE R0,R0,#1
STRLE R0,[R12,#v.noteno]

LDR R0,[R12,#v.noteno]
LDR R1,[R12,#v.patno]
ADD R2,R9,#mod.patlen
LDRB R3,[R2,R1]
CMP R0,R3
BLGE patadvance
.nopatproc
.notplaying
.abort
LDMFD R13!,{R14}
MOV R0,PC
ORR R0,R0,#2
BIC R0,R0,#1
TEQP R0,#0  ;switch to IRQ
MOV R0,R0
LDR R0,[R12,#v.ticker]
STR R0,[R12,#v.lastticker]
MOV R0,#0
STR R0,[R12,#v.threaded]
LDMFD R13!,{R0-R11,PC}^

.patadvance
STMFD R13!,{R14}
LDR R4,[R12,#v.seqno]
ADD R4,R4,#1
LDR R0,[R9,#mod.musiclen]
CMP R4,R0
MOVGE R4,R0,LSR #24
AND R4,R4,#&7F
STR R4,[R12,#v.seqno]
BL patinit
LDMFD R13!,{PC}

.patinit
STMFD R13!,{R0-R11,R14}
LDR R0,[R12,#v.linkedmod]
CMP R0,#0
LDMLTFD R13!,{R0-R11,PC}
get_m
LDR R9,[R10,#m.addr]
LDR R4,[R12,#v.seqno]
AND R4,R4,#&7F
ADD R2,R9,#mod.sequence
LDRB R2,[R2,R4]
STR R2,[R12,#v.patno]
MOV R0,#0
STR R0,[R12,#v.noteno]
LDMFD R13!,{R0-R11,PC}


.processnote
STMFD R13!,{R14}
LDR R0,[R11]
AND R1,R0,#&FFFF
CMP R1,#&0300
LDMEQFD R13!,{PC}
AND R1,R0,#&FF00
CMP R1,#&0300
BEQ slidenote
AND R1,R0,#&FF<<24
MOV R1,R1,LSR #24
AND R2,R0,#&FF<<16
MOV R2,R2,LSR #16
CMP R1,#0
LDMEQFD R13!,{PC}
MOV R4,#&155
MUL R3,R4,R1
ADD R3,R3,#&1eaa
ADD R3,R3,R1,LSR #2
ADD R3,R3,R1,LSR #4
MOV R4,#0
CMP R2,#0
MOVEQ R4,#%1000001
MOV R1,R2
ADD R0,R12,#v.soundtab
LDRB R2,[R0,R1]
MOV R2,R2,LSR #1
ADD R1,R1,#startslot-1
MOV R0,R8
SWI Stasis_Sound
LDMFD R13!,{PC}

.slidenote
LDR R0,[R11]
AND R1,R0,#&FF<<24
AND R2,R0,#&FF<<16
MOV R1,R1,LSR #24
CMP R1,#0
LDMEQFD R13!,{PC}
AND R0,R0,#&FF
LDR R3,[R12,#v.realtune]
MUL R3,R0,R3
ADD R0,R12,#v.soundtab
STMFD R13!,{R1}
LDRB R1,[R0,R2,LSR #16]
MOV R1,R1,LSR #1
MOV R0,R8
SWI Stasis_Volume
LDMFD R13!,{R1}

MOV R4,#&155
MUL R2,R4,R1
ADD R2,R2,#&1eaa
ADD R2,R2,R1,LSR #2
ADD R2,R2,R1,LSR #4
ORR R0,R8,#1<<29
MOV R1,#1
SWI Stasis_Slide

LDMFD R13!,{PC}

.processeffect
STMFD R13!,{R14}
;get_ch R8,R7
LDR R6,[R11]
AND R6,R6,#&FFFF
MOV R5,R6,LSR #8
AND R6,R6,#&FF
CMP R5,#&1
BLEQ effpitchup
CMP R5,#&2
BLEQ effpitchdown
CMP R5,#&0A
BLEQ volslide
CMP R5,#&12
BLEQ effvolup
CMP R5,#&11
BLEQ effvoldown
CMP R5,#&1C
BLEQ effspeed
CMP R5,#&B
BLEQ effbreak
CMP R5,#&13
BLEQ effjump
CMP R5,#&C
BLEQ efflogvol
CMP R5,#&1F
BLEQ efflinvol
CMP R5,#&E
BLEQ effmisc
CMP R5,#&19
BLEQ effstereo
LDMFD R13!,{PC}

.effvolup
STMFD R13!,{R14}
ADD R0,R8,#1<<29
MOV R1,#0
MOV R2,#&7f
MOV R3,R6,LSL #6
SWI Stasis_Slide
LDMFD R13!,{PC}

.effvoldown
STMFD R13!,{R14}
ADD R0,R8,#1<<29
MOV R1,#0
MOV R2,#&0
MOV R3,R6,LSL #6
RSB R3,R3,#0
SWI Stasis_Slide
LDMFD R13!,{PC}

.volslide

STMFD R13!,{R14}
ANDS R3,R6,#&F0
BEQ volslideup
ADD R0,R8,#1<<29
MOV R1,#0
MOV R2,#&7F
MOV R3,R3,LSL #2
SWI Stasis_Slide
LDMFD R13!,{PC}
.volslideup
AND R3,R6,#&0F
ADD R0,R8,#1<<29
MOV R1,#0
MOV R2,#&0
MOV R3,R3,LSL #6
RSB R3,R3,#0
SWI Stasis_Slide
LDMFD R13!,{PC}

.effpitchup
STMFD R13!,{R14}
ADD R0,R8,#1<<29
MOV R1,#1
MOV R2,#&6555
LDR R3,[R12,#v.realtune]
MUL R3,R6,R3
SWI Stasis_Slide
LDMFD R13!,{PC}

.effpitchdown
STMFD R13!,{R14}
ADD R0,R8,#1<<29
MOV R1,#1
MOV R2,#&0
LDR R3,[R12,#v.realtune]
MUL R3,R6,R3
RSB R3,R3,#0
SWI Stasis_Slide
LDMFD R13!,{PC}

.effspeed
AND R0,R6,#&1F
STR R0,[R12,#v.speed]
MOV PC,R14

.efflinvol
STMFD R13!,{R14}
MOV R0,R8
MOV R1,R6,LSR #1
SWI Stasis_Volume
LDMFD R13!,{PC}

.efflogvol
STMFD R13!,{R14}
MOV R0,R8
MOV R1,R6
ADR R2,loglintab
CMP R1,#&40
MOVGT R1,#&40
LDRB R3,[R2,R1]
MOV R1,R3,LSR #1
SWI Stasis_Volume
LDMFD R13!,{PC}

.effbreak
MOV R0,#&FF
STR R0,[R12,#v.noteno]
MOV PC,R14

.effjump
STR R6,[R12,#v.patno]
MOV R0,#&FF
STR R0,[R12,#v.noteno]
MOV PC,R14

.effstereo
STMFD R13!,{R14}
AND R6,R6,#7
MOV R1,#0
CMP R6,#1
MOVEQ R1,#-96
CMP R6,#2
MOVEQ R1,#-64
CMP R6,#3
MOVEQ R1,#-32

CMP R6,#5
MOVEQ R1,#32
CMP R6,#6
MOVEQ R1,#64
CMP R6,#7
MOVEQ R1,#96
MOV R0,R8
SWI Sound_Stereo
LDMFD R13!,{PC}

.effmisc
STMFD R13!,{R5,R14}
AND R5,R6,#&F0
AND R6,R6,#&F
MOV R5,R5,LSR #4
CMP R5,#&E
BLEQ effdelay
LDMFD R13!,{R5,PC}

.effdelay
LDR R0,[R12,#v.delay]
CMP R0,#0
ADD R0,R6,#1
STREQ R0,[R12,#v.delay]
MOV PC,R14

.loglintab
incbin StasisMod:LogLinTab
.linlogtab
incbin StasisMod:LinLog2
ALIGN
.terminate
STMFD R13!,{R14}
ADD R1,R0,#4
ADR R0,message
SWI OS_AddCallBack

MVN R0,#0
STR R0,[R12,#v.linkedmod]
ADR R0,message
ADR R1,termtext
SWI OS_AddCallBack
LDMFD R13!,{PC}
.termtext
DCB 10,13,"StasisMod : Module play terminated by error",10,13,0
ALIGN

.playstart
STMFD R13!,{R1-R11,R14}
;MOV R0,#0
MOV R9,R0
get_m
LDR R11,[R10,#m.addr]
CMP R11,#0
LDMEQFD R13!,{R1-R11,R14}
BEQ nomoderr
BL sortvoices
LDR R0,[R12,#v.linkedmod]
CMP R0,#0
STR R9,[R12,#v.nextmod]
STRLT R9,[R12,#v.linkedmod]
LDR R0,[R12,#v.status]
ORR R0,R0,#status_pending+status_fade
STR R0,[R12,#v.status]
LDMFD R13!,{R1-R11,PC}

.playinit
STMFD R13!,{R14}
MOV R0,#6
STR R0,[R12,#v.speed]
MOV R0,#0
STR R0,[R12,#v.seqno]
STR R0,[R12,#v.delay]
BL patinit
LDMFD R13!,{PC}

.sortvoices
STMFD R13!,{R14}

MOV R0,#0
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
MOV R4,R0
CMP R0,#8
MOV R3,#1
MOVEQ R3,#5
MOV R0,R3
MOV R1,R3
SWI Stasis_Attach
ADD R3,R3,#1
MOV R0,R3
MOV R1,R3
SWI Stasis_Attach
ADD R3,R3,#1
MOV R0,R3
MOV R1,R3
SWI Stasis_Attach
ADD R3,R3,#1
MOV R0,R3
MOV R1,R3
SWI Stasis_Attach
CMP R4,#4
LDMGEFD R13!,{PC}
MOV R0,#4
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
LDMFD R13!,{PC}

.swapin
STMFD R13!,{R14}
;ADR R0,message
;ADR R1,swaptext
;SWI OS_AddCallBack
BL unlinkmod
LDR R0,[R12,#v.nextmod]
BL linkmod
LDMVSFD R13!,{PC}
BL playinit
LDMFD R13!,{PC}
.swaptext
DCB "StasisMod : Module swapped in",10,13,0
ALIGN

.modrelease
STMFD R13!,{R14}
LDR R1,[R12,#v.linkedmod]
CMP R0,R1
BLEQ nukemod
get_m
LDR R9,[R10,#m.type]
CMP R9,#type_rma
BLEQ rmarelease
CMP R9,#type_amnesia
;BLEQ amnesiarelease
LDMFD R13!,{PC}



.message
STMFD R13!,{R0,R14}
MOV R0,R12
SWI OS_Write0
LDMFD R13!,{R0,PC}

.number
STMFD R13!,{R0-R2,R14}
MOV R0,R12
ADR R1,buffer
MOV R2,#16
SWI OS_ConvertHex8
SWI OS_Write0
SWI OS_NewLine
LDMFD R13!,{R0-R2,PC}
.buffer
DBB 16

.fadeall
STMFD R13!,{R14}
MOV R4,#0
.fadeallloop
LDR R0,[R12,#v.voices]
CMP R0,#8
MOV R0,R4
ADDEQ R0,R0,#4
MOV R1,#0
MOV R2,#0
MOV R3,#200
SWI Stasis_Slide
ADD R4,R4,#1
CMP R4,#4
BLT fadeallloop
LDMFD R13!,{PC}

.stopcom
STMFD R13!,{R14}
LDR R12,[R12]        ;where's my workspace?
BL stopswi
LDMFD R13!,{PC}

.stopswi
STMFD R13!,{R0-R11,R14}
BL unlinkmod
LDMFD R13!,{R0-R11,PC}

.voicescom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned
MOV R0,R2
BL voicesswi
LDMFD R13!,{PC}

.voicesswi
STR R0,[R12,#v.voices]
MOV PC,R14

.pausecom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned
MOV R0,R2
BL pauseswi
LDMFD R13!,{PC}

.pauseswi
STMFD R13!,{R0,R14}
CMP R0,#1
MOVNE R0,#0
STR R0,[R12,#v.pause]
BL fadeall
LDMFD R13!,{R0,PC}

.loadcom
STMFD R13!,{R14}
LDR R12,[R12]        ;where's my workspace?
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned
MOV R0,R2
BL loadswi
MOV R0,R2
BL playstart
LDMFD R13!,{PC}

.loadswi
STMFD R13!,{R1-R9,R14}
;MOV R0,#0
MOV R9,R0
STMFD R13!,{R0-R1}
BL modrelease
LDMFD R13!,{R0-R1}
get_m
MOV R0,#5
SWI XOS_File
LDMVSFD R13!,{R1-R9,PC}
MOV R4,R2,LSL #12
MOV R4,R4,LSR #20
CMP R0,#1
LDMNEFD R13!,{R1-R9,R14}
BNE notafileerr
STR R4,[R12,#v.filetype]
BL rmahamload
LDMVSFD R13!,{R1-R9,PC}
LDMFD R13!,{R1-R9,PC}

.rmarelease
STMFD R13!,{R14}
LDR R0,[R10,#m.addr]
releaserma R0
MOV R0,#type_empty
STR R0,[R10,#m.type]
LDMFD R13!,{PC}

;.amnesiaload
;STMFD R13!,{R2,R14}
;ADD R0,R10,#m.addr
;MOV R2,#0
;SWI XAmnesia_LoadFile
;MOV R2,#type_amnesia
;MOVVS R2,#type_empty
;STR R2,[R10,#m.type]
;LDMFD R13!,{R2,PC}

.rmaload
STMFD R13!,{R1-R2,R14}
loadrma R1,R2
LDMVSFD R13!,{R1-R2,PC}
STR R2,[R10,#m.addr]
MOV R2,#type_rma
STR R2,[R10,#m.type]
LDMFD R13!,{R1-R2,PC}

.rmahamload
STMFD R13!,{R1-R2,R14}
MOV R0,#0
MOV R2,#0
SWI XBlitz_HammerOp
LDMVSFD R13!,{R1-R2,R14}
BVS rmaload
CMP R3,#0
LDMEQFD R13!,{R1-R2,R14}
BEQ rmaload
claimrma R3,R3
LDMVSFD R13!,{R1-R2,PC}
MOV R0,#1
SWI Blitz_HammerOp
STR R3,[R10,#m.addr]
MOV R2,#type_rma
STR R2,[R10,#m.type]
LDMFD R13!,{R1-R2,PC}

.unlinkmod
STMFD R13!,{R0,R14}
MVN R0,#0
STR R0,[R12,#v.linkedmod]
MOV R0,#0
STR R0,[R12,#v.linkedadr]
LDMFD R13!,{R0,R14}

.nukemod
STMFD R13!,{R0-R11,R14}
MVN R0,#0
STR R0,[R12,#v.linkedmod]
MOV R0,#0
STR R0,[R12,#v.linkedadr]
MOV R9,#startslot
.nukeloop
MOV R0,R9
MOV R1,#0
MOV R2,#0
SWI Stasis_Sample
ADD R9,R9,#1
CMP R9,#startslot+48
BLT nukeloop
LDMFD R13!,{R0-R11,PC}

.ids
DCB "MUSX","TINF","MVOX","STER","MNAM","ANAM","MLEN","PNUM"
DCB "PLEN","SEQU"
.songid
DCB "SONG"

.linkmod
STMFD R13!,{R0-R11,R14}
STR R0,[R12,#v.linkedmod]
MOV R9,#0
STR R9,[R12,#v.songtype]
get_m
LDR R9,[R10,#m.addr]
ADR R11,ids
MOV R8,#0
.linkloop
LDR R0,[R9]
LDR R1,[R11]
CMP R0,R1
BNE failmod
.failins
LDR R0,[R9,#4]
CMP R8,#0
MOVEQ R0,#0
ADD R0,R0,#8
ADD R9,R9,R0
ADD R11,R11,#4
ADD R8,R8,#1
CMP R8,#10
BLT linkloop
LDR R0,[R10,#m.addr]
SUB R9,R9,R0
STR R9,[R10,#m.pattarea]
BL getpatts
BVS failmessage
LDR R0,[R12,#v.songtype]
CMP R0,#0
BLEQ getsounds
BVS failmessage

.linkend
LDR R0,[R10,#m.addr]
STR R0,[R12,#v.linkedadr]

LDMFD R13!,{R0-R11,R14}
BIC R14,R14,#1<<28
MOVS PC,R14

.failmod
CMP R8,#0
BNE failmessage
LDR R1,songid
CMP R1,R0
BNE failmessage
MOV R1,#1
STR R1,[R12,#v.songtype]
B failins
.failmessage
LDMFD R13!,{R0-R11,R14}
ADR R0,failedmodtext
ORR R14,R14,#1<<28
MOVS PC,R14
.failedmodtext
DCD &666
DCB "StasisMod : Unrecognised module type",0
ALIGN
.soundid
DCB "SAMP"
.pattid
DCB "PATT"


.getpatts
STMFD R13!,{R14}
ADD R5,R12,#v.pattab
LDR R9,[R10,#m.pattarea]
CMP R9,#0
BEQ getpattsfail
LDR R11,[R10,#m.addr]
ADD R9,R11,R9
LDR R8,[R11,#mod.patterns]
AND R8,R8,#&7F
MOV R7,#0
.patloop
LDR R0,[R9]
LDR R1,pattid
CMP R0,R1
BNE getpattsfail
SUB R0,R9,R11
ADD R0,R0,#8
STR R0,[R5],#4
LDR R0,[R9,#4]
ADD R0,R0,#8
ADD R9,R9,R0
ADD R7,R7,#1
CMP R7,R8
BLT patloop
SUB R9,R9,R11
STR R9,[R10,#m.samparea]
LDMFD R13!,{R14}
BIC R14,R14,#1<<28
MOVS PC,R14

.getpattsfail
MOV R0,R7
ADR R1,getpattsnum
MOV R2,#5
SWI OS_ConvertHex2
ADR R0,message
ADR R1,getpattstext
SWI OS_AddCallBack
LDMFD R13!,{R14}
ORR R14,R14,#1<<28
MOVS PC,R14
.getpattstext
DCB "Pattern ID &"
.getpattsnum
DCB "   incorrect.",10,13,0
ALIGN

.makesoundtab
STMFD R13!,{R14}
MOV R0,#1
ADD R1,R12,#v.soundtab
.soundtabloop
STMFD R13!,{R0-R1}
ADD R0,R0,#startslot-1
SWI Stasis_GetSlotInfo
LDMFD R13!,{R0-R1}
STRB R7,[R1,R0]
ADD R0,R0,#1
CMP R0,#48
BLT soundtabloop
LDMFD R13!,{PC}

.getsounds
STMFD R13!,{R14}
LDR R11,[R10,#m.addr]
LDR R9,[R10,#m.samparea]
CMP R9,#0
MOV R7,#0
BEQ getsoundsfail
ADD R9,R9,R11
LDR R8,[R11,#mod.length]
ADD R8,R8,R11
MOV R7,#80
.getloop
CMP R9,R8
BGE getsoundsend
LDR R0,[R9]
LDR R1,soundid
CMP R0,R1
BNE getsoundsfail
LDR R0,[R9,#4]
CMP R0,#64
BLE emptysound
MOV R0,R7
MOV R1,R9
MOV R2,#1
SWI Stasis_MakeLink
.emptysound
LDR R0,[R9,#4]
ADD R0,R0,#8
ADD R9,R9,R0
ADD R7,R7,#1
CMP R7,#128
BLT getloop
.getsoundsend
BL makesoundtab
LDMFD R13!,{R14}
BIC R14,R14,#1<<28
MOVS PC,R14

.getsoundsfail
MOV R0,R7
ADR R1,getsoundsnum
MOV R2,#5
SWI OS_ConvertHex2
ADR R0,message
ADR R1,getsoundstext
SWI OS_AddCallBack
LDMFD R13!,{R14}
ORR R14,R14,#1<<28
MOVS PC,R14

.getsoundstext
DCB "Pattern ID &"
.getsoundsnum
DCB "   incorrect.",10,13,0
ALIGN


.service
STMFD R13!,{R0}
MOV R0,#Service_StasisRate
CMP R1,R0
BEQ rateservice
MOV R0,#Service_PsychoDying
CMP R1,R0
BEQ dyingservice
LDMFD R13!,{R0}
MOVNES PC,R14
.rateservice
LDMFD R13!,{R0}
LDR R12,[R12]
STR R2,[R12,#v.realtune]
MOV PC,R14

.dyingservice
LDMFD R13!,{R0}
LDR R12,[R12]
STMFD R13!,{R0-R11,R14}
MVN R0,#0
STR R0,[R12,#v.linkedmod]
MOV R0,#0
STR R0,[R12,#v.linkedadr]
LDMFD R13!,{R0-R11,PC}

.readbaserate
STMFD R13!,{R14}
SWI XStasis_BaseRate
MOVVS R0,#48
STR R1,[R12,#v.realtune]
LDMFD R13!,{PC}

.init
STMFD R13!,{R7-R11,R14}
LDR R0,[R12]
CMP R0,#0
BNE clskip
MOV R3,#v.sizeof
claimrma R3,R2
LDMVSFD R13!,{R7-R11,R14} 
BVS noroomerr
STR R2,[R12]
.clskip
LDR R12,[R12]  ;real workspace
BL clearspace
MVN R0,#0
STR R0,[R12,#v.linkedmod]
STR R0,[R12,#v.linkedadr]
STR R0,[R12,#v.pause]
MOV R0,#4
STR R0,[R12,#v.voices]
BL readbaserate
BL claimvector

LDMFD R13!,{R7-R11,PC}

.claimvector
STMFD R13!,{R14}
MOV R0,#&1C
ADR R1,routine
MOV R2,R12
SWI OS_Claim
LDMFD R13!,{PC}

.releasevector
STMFD R13!,{R14}
MOV R0,#&1C
ADR R1,routine
MOV R2,R12
SWI OS_Release
LDMFD R13!,{PC}

.clearspace
STMFD R13!,{R14}
MOV R0,#0
MOV R1,#0
.clearloop
STR R0,[R12,R1]
ADD R1,R1,#4
CMP R1,#v.sizeof
BLT clearloop
LDMFD R13!,{PC}

.final
STMFD R13!,{R7-R11,R14}
LDR R12,[R12]
BL releasevector
MOV R0,#0
.releaseloop
STMFD R13!,{R0,R10}
BL modrelease
ADDVS R0,R0,#4
SWIVS OS_Write0
SWIVS OS_NewLine
LDMFD R13!,{R0,R10}
ADD R0,R0,#1
CMP R0,#8
BLT releaseloop

CMP R10,#0
BLNE releasespace
LDMFD R13!,{R7-R11,PC}^

.releasespace
STMFD R13!,{R1-R11,R14}
releaserma R12
LDMFD R13!,{R1-R11,PC}^

.err
ORR R14,R14,#1<<28
MOVS PC,R14

.notafileerr
STMFD R13!,{R14}
MOV R2,R0
MOV R0,#19
SWI XOS_File
LDMFD R13!,{R14}
B err

.noroomerr
ADR R0,noroomerrtext
B err
.noroomerrtext
DCD &666
DCB "StasisMod : No room in module area",0
ALIGN

.nomoderr
ADR R0,nomoderrtext
B err
.nomoderrtext
DCD &666
DCB "StasisMod : No module to play",0
ALIGN

.badswino
ADR R0,badswinotext
B err
.badswinotext
DCD &666
DCB "StasisMod : Bad SWI number",0
ALIGN
macro get_m {
AND R0,R0,#7
ADD R10,R12,#v.modtab
ADD R10,R10,R0,LSL #m_shift
}

macro get_ch m0,m1 {
SUB m0,m0,#1
ADD m1,R12,#v.chantab
ADD m1,m1,m0,LSL #h_shift
}
