#type &ffa
#name Stasis
#base 0
#include ASMLib:Standard
#set Service_PsychoStarting=&80300
#set Service_PsychoDying   =&80301
#set Service_UKStasisFormat=&80310
#set Service_StasisSave    =&80311
#set Service_StasisIdentify=&80312
#set Service_StasisRate    =&80313
#set Service_Amnesia=&80320
#set stasis_alien          =1

struct v {
  .linktab	DBB 8  ; variables
  .slot		DCD 0
  .mastertune	DCD 0
  .samprate	DCD 0
  .newrate	DCD 0
  .oldchan	DCD 0
  .realtune	DCD 0
  .timer	DCD 0
  .logampadr	DCD 0
  .filetype	DCD 0
  .saveslot	DCD 0
  .savename	DCD 0
  .callbacks	DCD 0
  .received	DCD 0
  .textbuf	DBB 16
  .contab   	DBB 8*con.sizeof
  .slottab	DBB entries*s.sizeof
  .sizeof
}

struct s {             ;data structure for slot table
  .addr         DCD 0
  .length       DCD 0
  .type		DCD 0
  .format	DCD 0
  .alien        DCD 0
  .spare	DBD 3
  .sizeof
}

struct sccb {
  .volume	DCB 0
  .index	DCB 0
  .instance	DCB 0
  .control	DCB 0
  .pitch	DCD 0
  .timbre	DCD 0
  .duration	DCD 0
  .sizeof
}

struct alien {
  .id		DCD 0
  .getinfo	DCD 0
  .putinfo	DCD 0
  .release	DCD 0
  .zero		DCD 0
  .reserved1	DCD 0
  .reserved2	DCD 0
  .name		DCD 0
  .formatname	DCD 0
  .filetype	DCD 0
  .modname	DCD 0
  .sizeof
  
}

struct con {       
  .buf1		DCD 0;don't touch the first few
  .buf2		DCD 0;they're loaded by an LDM
  .addr		DCD 0
  .length	DCD 0
  .acc		DCD 0
  .replen	DCD 0
  .pitch	DCD 0
  .status	DCD 0
  .repofs	DCD 0
  .slot		DCD 0
  .volume	DCD 0
  .finetune	DCD 0
  .lastbuf	DCD 0
  .rawpitch	DCD 0
  .logampadr    DCD 0
  .slowbufs 	DCD 0
  .fastbufs	DCD 0
  .flashbufs	DCD 0
  .fixedbufs    DCD 0
  .flushes	DCD 0
  .kicks	DCD 0;intentional gap below
  .slides
  .volslide	DCD 0
  .volrate	DCD 0
  .pitchslide	DCD 0
  .pitchrate	DCD 0
  .ratechange	DCD 0
  .states	DCD 0
  .prevstate	DCD 0
  .laststate	DCD 0
  .samprate	DCD 0
  .spare	DBD 2
  .sizeof
}
;output con.sizeof  

#set stac_shift=7    ;con_shift

#set s_shift=5
#set status_gated = 1<<0

#set status_q1    = 1<<3
#set status_q2    = 1<<4
#set status_live  = 1<<5
#set status_escape= 1<<6
#set status_kick  = 1<<7
#set status_off   = 1<<8
#set status_fresh = 1<<9
#set status_slide	= 1<<10
#set status_volslide	= 1<<10
#set status_pitchslide 	= 1<<11
#set status_resslide 	= 1<<12
#set status_resslide 	= 1<<13
#set status_safe	= 1<<14
#set status_attached	= 1<<15
#set status_qshift = 3

#set ig_slot	= 1<<0
#set ig_volume	= 1<<1
#set ig_pitch	= 1<<2
#set ig_update  = 1<<3
#set ig_rawpitch= 1<<4
#set ig_escape  = 1<<5
#set ig_retrig	= 1<<6
#set ig_fromgate= 1<<31
struct stasisform {    ;stasis format
  .id           DCD 0
  .name		DBB 20
  .len		DCD 0
  .repofs	DCD 0

  .replen	DCD 0
  .finetune     DCD 0
  .dataofs	DCD 0
  .sizeof
}

struct tffstart {   ; TFF (tracker) format
  		DCD 0; "SAMP"
  .blocklen	DCD 0
		DCD 0; "SNAM"
  .namelen	DCD 20
  .name		DBB 20;"Name of the voice   "
  .sizeof
}
struct tffend {
 		DCD 0; "SVOL"
		DCD 4
  .finetune	DCD 255
		DCD 0; "SLEN"
		DCD 4
  .len		DCD 0
		DCD 0; "ROFS"
		DCD 4
  .repofs	DCD 0
		DCD 0; "RLEN"
		DCD 4
  .replen	DCD 2
		DCD 0;"SDAT"
  .dataofs	DCD 0
  .sizeof
}

struct userform {   ;user format
  .id		DCB "User"
  .addr		DCD 0
  .len		DCD 0
  .repofs	DCD 0
  .replen	DCD 0
  .sizeof
}
  
#set finetune_default=&4000
#set finetune_shift=14
#set tune_default=&4000
#set tune_shift=12

#set entryshift=7
#set entries=128
#set namelen=20
#set type_empty=0
#set type_rma=1
#set type_user=2
#set type_amnesia=3
#set type_link=4
#set type_safelink=5

#set format_unknown=0
#set format_stasis=1
#set format_tracker=2
#set format_user=3
#set format_alien=4

#set filetype_stasis=&112
#set filetype_tracker=&CB5

.ModuleHeader
DCD 0
DCD init
DCD final
DCD service
DCD title
DCD help
DCD helptable
DCD &47D40
DCD swicode
DCD switab
DCD 0
.title
DCB  "Stasis"
DCB 0
ALIGN
.help
DCB  "Stasis Voices",9,"1.11 (5 March 1995)"
DCB 0
ALIGN
.helptable
DCB  "Stasis"
DCB 0
ALIGN
DCD 0
DCD 0
DCD 0
DCD stasishelp
DCB "StasisSample"
DCB 0
ALIGN
DCD sample
DCD &0005FF03
DCD samplesyn
DCD samplehelp
DCB  "StasisLoad"
DCB 0
ALIGN
DCD sampleload
DCD &0003FF02
DCD loadsyn
DCD loadhelp
DCB  "StasisSave"
DCB 0
ALIGN
DCD savecommand
DCD &0003FF02
DCD savesyn
DCD savehelp
DCB  "StasisLink"
DCB 0
ALIGN
DCD samplelink
DCD &0002FF02
DCD linksyn
DCD linkhelp
DCB  "StasisTune"
DCB 0
ALIGN
DCD tunecommand
DCD &0001FF01
DCD tunesyn
DCD tunehelp
DCB  "StasisCat"
DCB 0
ALIGN
DCD samplecat
DCD &0002FF00
DCD catsyn
DCD cathelp
DCB  "StasisState"
DCB 0
ALIGN
DCD statecom
DCD &0001FF00
DCD statesyn
DCD statehelp
DCB  "StasisInfo"
DCB 0
ALIGN
DCD infocom
DCD &0001FF00
DCD infosyn
DCD infohelp

DCB  "StasisFineTune"
DCB 0
ALIGN
DCD setfinetune
DCD &0002FF02
DCD setfinetunesyn
DCD setfinetunehelp
DCB  "StasisName"
DCB 0
ALIGN
DCD setname
DCD &000CFF02
DCD setnamesyn
DCD setnamehelp
DCB  "StasisRepeat"
DCB 0
ALIGN
DCD setrepeat
DCD &0003FF03
DCD setrepeatsyn
DCD setrepeathelp
DCB  "StasisLength"
DCB 0
ALIGN
DCD setlength
DCD &0002FF02
DCD setlengthsyn
DCD setlengthhelp
DCB  "StasisVolume"
DCB 0
ALIGN
DCD setvolume
DCD &0002FF02
DCD setvolumesyn
DCD setvolumehelp

DCB "StasisVolSlide",0
ALIGN
DCD volslidecom
DCD &0003FF03
DCD volslidesyn
DCD volslidehelp

DCB "StasisPitchSlide",0
ALIGN
DCD pitchslidecom
DCD &0003FF03
DCD pitchslidesyn
DCD pitchslidehelp


DCB "StasisOverdrive"
DCB 0
ALIGN
DCD nullcommand
DCD &0001FF01
DCD odrsyn
DCD odrhelp
DCB "StasisSound"
DCB 0
ALIGN
DCD soundcommand
DCD &0004FF04
DCD soundsyn
DCD soundhelp
DCB  "StasisSWIs"
DCB 0
ALIGN
DCD 0
DCD 0
DCD 0
DCD swishelp

DCD 0 ;           end marker

.stasishelp
DCB "A voice generator using samples.  Andy Southgate but use freely."

DCB 0

.samplehelp
DCB 27
DCB 0
DCB  " sets details of a user defined sample."
DCB 13
DCB 10
.samplesyn
DCB 27
DCB 1
DCB  " <Slot> <Start> <Length> [<repeat offset> <repeat length>]"
DCB 0
.loadhelp
DCB 27
DCB 0
DCB  " loads a sample into memory, in the specified slot."
DCB 13
DCB 10
DCB  "The native file format is a compact header block, followed by 8 bit log scaled data."
DCB 10
DCB 13
.loadsyn
DCB 27
DCB 1
DCB  " <Slot> <Filename>"
DCB 0

.savehelp
DCB 27
DCB 0
DCB " saves a sample.  Either Stasis or Tracker format can be specified by using "
DCB  "StasisSave S (or just StasisSave ) or StasisSave T.  Stasis format is a little shorter."
DCB 10
DCB 13
.savesyn
DCB 27
DCB 1
DCB  " [format] <Slot> <Filename>"
DCB 0


.linkhelp
DCB 27
DCB 0
DCB  " attaches a channel to a sample slot."
DCB 13
DCB 10
.linksyn
DCB 27
DCB 1
DCB  " <channel> <slot> "
DCB 0
.tunehelp
DCB 27,0," sets the master tuning of the sounds. The default value is &4000.",10,13
.tunesyn
DCB 27,1," <value>",0
.cathelp
DCB 27,0," displays information about the samples present. Default is samples 0-15.",10,13
.catsyn
DCB 27,1," [<start> [<finish>]]",0
.statehelp
DCB 27,0," displays information about the state of the sound playing on a channel.",10,13
.statesyn
DCB 27,1," [<channel>]",0
.infohelp
DCB 27,0," displays information the sample in the specified slot.",10,13
.infosyn
DCB 27,1," [<channel>]",0
.setfinetunehelp
DCB 27,0," sets the fine tune value for a sample.  The normal value is &4000.",10,13
.setfinetunesyn
DCB 27,1," <slot> <value>",0
.setnamehelp
DCB 27,0," sets the name of a sample to a string of up to 20 characters.",10,13
.setnamesyn
DCB 27,1," <slot> <name>",0
.setrepeathelp
DCB 27,0," sets the repeat loop of a sample.",10,13
.setrepeatsyn
DCB 27,1," <slot> <repeat offset> <repeat length>",0
.setlengthhelp
DCB 27,0," sets the length of the sample.  Simply rewrites the length - doesnt change the memory allocation.",10,13
.setlengthsyn
DCB 27,1," <slot> <length>",0
.setvolumehelp
DCB 27,0," sets the volume of a sample in the range 0-&ff.",10,13
.setvolumesyn
DCB 27,1," <slot> <volume>",0
.volslidehelp
DCB 27,0," sets the volume slide for a channel.",10,13
.volslidesyn
DCB 27,1," <channel> <rate> <target>",0
.pitchslidehelp
DCB 27,0," sets the pitch slide for a channel.",10,13
.pitchslidesyn
DCB 27,1," <channel> <rate> <target>",0
.odrhelp
.odrsyn
DCB 27,0," is no longer available on this module."
.soundhelp
DCB 27,0," makes a sound, in a similar way to the *Sound command.",10,13
.soundsyn
DCB 27,1," <channel> <slot> <volume> <pitch> [<duration>]",0
.swishelp
DCB "Stasis supports the following SWIs:",10,13
DCB 34,"Stasis_Sample",34,",slot,start,length,repofs,replen",10,13
DCB 34,"Stasis_Load",34,",slot,filename,storage_type",10,13
DCB 34,"Stasis_Save",34,",slot,filename,save_type_string",10,13
DCB 34,"Stasis_Link",34,",channel,slot",10,13
DCB 34,"Stasis_Name",34,",slot,name",10,13
DCB 34,"Stasis_FineTune",34,",slot,finetune",10,13
DCB 34,"Stasis_Volume",34,",slot,volume",10,13
DCB 34,"Stasis_Sound",34,",channel,slot,volume,pitch,ignore",10,13
DCB 34,"Stasis_GetSlotInfo",34,",slot TO slot,name,pitch,finetune,repofs,replen,",10,13,"datastart,volume,formatstring",10,13
DCB 34,"Stasis_PutSlotInfo",34,",slot,name,pitch,finetune,repofs,replen,",10,13,"datastart,volume,bitfield",10,13
DCB 34,"Stasis_VolSlide",34,",channel,rate,target_volume",10,13
DCB 34,"Stasis_PitchSlide",34,",channel,rate,target_pitch",10,13
DCB 34,"Stasis_Slide",34,",channel,type,target,time",10,13

DCB 0

.switab
DCB "Stasis",0

DCB "GetAddress",0
DCB "Sample",0
DCB "Load",0
DCB "Save",0
DCB "Link",0
DCB "Name",0
DCB "VolSlide",0
DCB "PitchSlide",0
DCB "Control",0
DCB "FineTune",0
DCB "Volume",0
DCB "Sound",0
DCB "GetSlotInfo",0
DCB "PutSlotInfo",0
DCB "Slide",0
DCB "MakeLink",0
DCB "Tune",0
DCB "Attach",0
DCB "BaseRate",0
DCB "GetControlAddress",0
DCB "GetSlotAddress",0
DCB 0;end marker
ALIGN
#set swino=21

.swicode
CMP R11,#swino
BGE badswino
LDR R12,[R12]
ADR R10,swiofstab
LDR R10,[R10,R11,LSL #2]
ADR R11,swiofstab
ADD PC,R10,R11
.swiofstab
DCD getaddressswi 	- swiofstab
DCD sampleswi	 	- swiofstab
DCD loadswi 		- swiofstab
DCD saveswi		- swiofstab
DCD linkswi 		- swiofstab
DCD nameswi 		- swiofstab
DCD volslideswi		- swiofstab
DCD pitchslideswi 	- swiofstab
DCD nullswi 		- swiofstab
DCD nullswi	 	- swiofstab
DCD volumeswi 		- swiofstab
DCD soundswi		- swiofstab
DCD getslotinfo		- swiofstab
DCD putslotinfo		- swiofstab
DCD slideswi		- swiofstab
DCD makelinkswi		- swiofstab
DCD tuneswi		- swiofstab
DCD attachswi		- swiofstab
DCD baserateswi		- swiofstab
DCD getcontrolswi	- swiofstab
DCD getslotswi		- swiofstab
ALIGN
.nullswi
.nullcommand
MOV PC,R14
.stasisformat
.stasbeg
DCB  "Sta1"
.stas_name
DCB  "Name of the voice   "
DCD 0
DCD 0
DCD 0
DCD 0

.trackerformat
DCB  "SAMP"
DCD 0
DCB  "SNAM"
DCD 20
DCB  "Name of the voice   "
DCB  "SVOL"
DCD 4
DCD 255
DCB  "SLEN"
DCD 4
DCD 0
DCB  "ROFS"
DCD 4
DCD 0
DCB  "RLEN"
DCD 4
DCD 2
DCB  "SDAT"
DCD 0
.userformat
DCB "User"
DCD 0
DCD 0
DCD 0
DCD 0

.savecommand
STMFD R13!,{R14}
LDR R12,[R12]
CMP R1,#3
MOV R4,#0
BLT nosavespec
.savespaceloop
LDRB R3,[R0]
CMP R3,#&20
ADDEQ R0,R0,#1
BEQ savespaceloop
MOV R4,R0
.savenospaceloop
LDRB R3,[R0],#1
CMP R3,#&20
BGT savenospaceloop
.nosavespec
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R0,R2
MOV R2,R4
BL saveswi
LDMFD R13!,{PC}

.saveswi
STMFD R13!,{R4-R11,R14}
MOV R11,R2
MOV R10,R1
STR R0,[R12,#v.saveslot]
BL getslotinfo
LDMVSFD R13!,{R4-R11,PC}
MOV R8,R2;sample length
CMP R6,#0
LDMEQFD R13!,{R4-R11,R14}
BEQ nosamperr
MOV R0,#&84
STMFD R13!,{R1}
MOV R1,R10
SWI XOS_Find
LDMFD R13!,{R1}
MOV R9,#0 
BVS nosave
MOV R9,R0      ;file handle
CMP R11,#0
BEQ savestasis
STR R11,[R12,#v.savename]
STMFD R13!,{R1}
ADR R1,stasisname1
BL namecheck
ADRNE R1,stasisname2
BLNE namecheck
LDMFD R13!,{R1}
BEQ savestasis
STMFD R13!,{R1}
ADR R1,trackername1
BL namecheck
ADRNE R1,trackername2
BLNE namecheck
LDMFD R13!,{R1}
BEQ savetracker
LDR R0,[R12,#v.saveslot]
MOV R2,R10
ADR R3,namecheck
MOV R1,#Service_StasisSave
SWI OS_ServiceCall
CMP R1,#0
BLNE closefile
LDMNEFD R13!,{R4-R11,R14}
BNE badsaveformaterr
CMP R2,#0
BEQ saveend
MOV R11,R2
MOV R1,R3
MOV R2,R4
B dosave

.savestasis
ADR R11,stasisformat
BL putstasisform
B dosave
.savetracker
ADR R11,trackerformat
BL puttrackerform
B dosave
;returns
;R1=length of header
;R2=filetype to save

.dosave
MOV R3,R1;header length
STMFD R13!,{R1-R6}
MOV R1,R10
MOV R0,#&12 ; set filetype
SWI XOS_File 
LDMFD R13!,{R1-R6}
STMFD R13!,{R1-R6}
MOV R0,#&01     ;Write at R4
MOV R1,R9       ;handle
MOV R2,R11      ;from address R11
;R3 from above
MOV R4,#0       ;at start of file
SWI XOS_GBPB
LDMFD R13!,{R1-R6}
BVS nosave
MOV R0,#&02 ;Write to current pointer
MOV R1,R9
MOV R3,R8
MOV R2,R6
SWI XOS_GBPB 
BVS nosave

.saveend
BL closefile
LDMFD R13!,{R4-R11,PC}

.nosave
STMFD R13!,{R0}
BL closefile
MOV R0,#6
MOV R1,R10
SWI XOS_File ; delete partial file
LDMFD R13!,{R0}
SWI XOS_WriteS 
DCB  "Stasis : Save failed - "
DCB 0
ALIGN
LDMFD R13!,{R4-R11,R14}
B nosaveerr

.stasisname1
DCB "S",0
.stasisname2
DCB "Stasis",0
.trackername1
DCB "T",0
.trackername2
DCB "Tracker",0
ALIGN

.namecheck
STMFD R13!,{R0-R3,R14}
LDR R0,varstr
LDR R0,[R0,#v.savename]
.namecheckloop
LDRB R2,[R0],#1
LDRB R3,[R1],#1
BIC R2,R2,#1<<5
BIC R3,R3,#1<<5
CMP R2,R3
LDMNEFD R13!,{R0-R3,PC}
CMP R2,#" "
BLE namecheckend
CMP R3,#0
BEQ namecheckend
B namecheckloop
.namecheckend
CMP R0,R0
LDMFD R13!,{R0-R3,PC}

.putslotinfo
;on entry
;R0=slot no
;R1=name
;R2=length
;R3=finetune
;R4=repofs
;R5=replen
;R6=datastart
;R7=volume
;R8=bit field

STMFD R13!,{R1-R11,R14}
getslotaddr R0,R10
LDR R9,[R10,#s.type]
CMP R9,#type_empty
LDMEQFD R13!,{R1-R11,R14}
BEQ nosamperr
LDR R9,[R10,#s.format]
LDR R11,[R10,#s.addr]
CMP R9,#format_stasis
BEQ putstasisinfo
CMP R9,#format_tracker
BEQ puttrackerinfo
CMP R9,#format_alien
BEQ putalieninfo
CMP R9,#format_user
BEQ putuserinfo
MOV R6,R11
LDMFD R13!,{R1-R11,R14}
B badformaterr

.putstasisinfo
TST R8,#1<<1
ADDNE R0,R11,#stasisform.name
STMFD R13!,{R5}
MOV R5,#namelen
BLNE namecopy
LDMFD R13!,{R5}
TST R8,#1<<2
STRNE R2,[R11,#stasisform.len]
TST R8,#1<<3
STRNE R3,[R11,#stasisform.finetune]
TST R8,#1<<4
STRNE R4,[R11,#stasisform.repofs]
TST R8,#1<<5
STRNE R5,[R11,#stasisform.replen]
TST R8,#1<<6
SUBNE R6,R6,R11
STRNE R6,[R11,#stasisform.dataofs]
ANDS R0,R8,#1<<7
LDMNEFD R13!,{R1-R11,R14}
BNE puterr
LDMFD R13!,{R1-R11,PC}

.puttrackerinfo
TST R8,#1<<1
ADDNE R0,R11,#tffstart.name
STMFD R13!,{R5}
LDR R5,[R11,#tffstart.namelen]
BLNE namecopy
LDMFD R13!,{R5}

TST R8,#1<<2
LDR R0,[R11,#tffstart.namelen]
ADD R0,R0,#tffstart.name
ADD R10,R11,R0
STRNE R2,[R10,#tffend.len]
TST R8,#1<<3
LDR R0,[R10,#tffend.finetune]
SUBNE R3,R3,#finetune_default
MOVNE R3,R3,LSL #24
ANDNE R3,R3,#7<<28
BICNE R0,R0,#7<<28
ORRNE R0,R0,R3
TST R8,#1<<7
ANDNE R7,R7,#&FF
BICNE R0,R0,#&FF
ORRNE R0,R0,R7
STR R0,[R10,#tffend.finetune]
TST R8,#1<<4
STRNE R4,[R10,#tffend.repofs]
CMP R5,#2
MOVLT R5,#2
TST R8,#1<<5
STRNE R5,[R10,#tffend.replen]
ANDS R0,R8,#1<<6
LDMNEFD R13!,{R1-R11,R14}
BNE puterr
LDMFD R13!,{R1-R11,PC}

.putuserinfo
TST R8,#1<<2
STRNE R2,[R11,#userform.len]
TST R8,#1<<4
STRNE R4,[R11,#userform.repofs]
TST R8,#1<<5
STRNE R5,[R11,#userform.replen]
TST R8,#1<<6
STRNE R6,[R11,#userform.addr]
ANDS R0,R8,#%10001010
LDMNEFD R13!,{R1-R11,R14}
BNE puterr
LDMFD R13!,{R1-R11,PC}

.putalieninfo
MOV R0,#alien.putinfo
BL alienjump
LDMFD R13!,{R1-R11,R14}
CMP R0,#0
BNE puterr
MOVS PC,R14

.getslotinfo
;returns
;R0=slot no
;R1=name
;R2=length
;R3=finetune
;R4=repofs
;R5=replen
;R6=datastart
;R7=volume
;R8=format name

STMFD R13!,{R10-R11,R14}
getslotaddr R0,R10
LDR R7,[R10,#s.type]
CMP R7,#type_empty
BEQ getemptyinfo
LDR R8,[R10,#s.format]

LDR R11,[R10,#s.addr]
CMP R8,#format_stasis
BEQ getstasisinfo
CMP R8,#format_tracker
BEQ gettrackerinfo
CMP R8,#format_alien
BEQ getalieninfo
CMP R8,#format_user
BEQ getuserinfo
MOV R6,R11
B getunknowninfo

.getemptyinfo
MOV R6,#0
.getunknowninfo
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
MOV R5,#0
MOV R8,#0
LDMFD R13!,{R10-R11,PC}

.getstasisinfo
ADD R1,R11,#stasisform.name
LDR R2,[R11,#stasisform.len]
LDR R3,[R11,#stasisform.finetune]
LDR R4,[R11,#stasisform.repofs]
LDR R5,[R11,#stasisform.replen]
LDR R6,[R11,#stasisform.dataofs]
ADD R6,R11,R6
MOV R7,#0
MOV R8,#0
LDMFD R13!,{R10-R11,PC}

.gettrackerinfo
ADD R1,R11,#tffstart.name
LDR R0,[R11,#tffstart.namelen]
ADD R10,R1,R0

LDR R2,[R10,#tffend.len]
LDR R3,[R10,#tffend.finetune]
AND R7,R3,#&FF;volume entry
MOV R3,R3,LSR #24
ADD R3,R3,#finetune_default
LDR R4,[R10,#tffend.repofs]
LDR R5,[R10,#tffend.replen]
ADD R6,R10,#tffend.sizeof
MOV R8,#0
LDMFD R13!,{R10-R11,PC}

.getuserinfo
MOV R1,#0
LDR R2,[R11,#userform.len]
MOV R3,#0
LDR R4,[R11,#userform.repofs]
LDR R5,[R11,#userform.replen]
LDR R6,[R11,#userform.addr]
MOV R7,#0
MOV R8,#0
LDMFD R13!,{R10-R11,PC}

.alienid
DCB "StAl"
.getalieninfo
MOV R0,#alien.getinfo
STMFD R13!,{R9}
BL alienjump
LDMFD R13!,{R9}
MOVVS R2,#0
MOVVS R6,#0
LDMFD R13!,{R10-R11,PC}

.alienjump
STMFD R13!,{R14}
STMFD R13!,{R0-R1}
LDR R9,[R10,#s.alien]
LDR R1,[R9,#alien.id]
LDR R0,alienid
CMP R0,R1
LDMFD R13!,{R0-R1}
LDMNEFD R13!,{R14}
BNE badalienerr
LDR R14,[R9,R0]
CMP R14,#0
LDMEQFD R13!,{PC}
ADD R9,R9,R14
MOV R0,R10
MOV R1,R11
STMFD R13!,{R10-R12}
MOV R14,PC
MOV PC,R9
LDMFD R13!,{R10-R12}
LDMFD R13!,{PC}

.getalienaddr
STMFD R13!,{R1-R3,R14}
LDR R3,[R10,#s.alien]
LDR R1,[R3,#alien.id]
LDR R2,alienid
CMP R2,R1
LDMNEFD R13!,{R1-R3,R14}
BNE badalienerr
ADD R0,R0,R3
LDMFD R13!,{R1-R3,PC}

.getalienindirect
STMFD R13!,{R1-R3,R14}
LDR R3,[R10,#s.alien]
LDR R1,[R3,#alien.id]
LDR R2,alienid
CMP R2,R1
LDMNEFD R13!,{R1-R3,R14}
BNE badalienerr
LDR R0,[R3,R0]
CMP R0,#0
ADDNE R0,R0,R3
LDMFD R13!,{R1-R3,PC}


.putstasisform
STMFD R13!,{R3-R6,R10,R14}
CMP R1,#0
ADREQ R1,nullname
ADD R0,R11,#stasisform.name
STMFD R13!,{R5}
MOV R5,#namelen
BL namecopy
LDMFD R13!,{R5}
STR R2,[R11,#stasisform.len]
STR R3,[R11,#stasisform.finetune]
STR R4,[R11,#stasisform.repofs]
STR R5,[R11,#stasisform.replen]
MOV R6,#stasisform.sizeof
STR R6,[R11,#stasisform.dataofs]
MOV R1,#stasisform.sizeof
MOV R2,#filetype_stasis
LDMFD R13!,{R3-R6,R10,PC}

.puttrackerform
STMFD R13!,{R3-R6,R10,R14}
CMP R1,#0
ADREQ R1,nullname
ADD R0,R11,#tffstart.name
STMFD R13!,{R5}
MOV R5,#namelen
BL namecopy
LDMFD R13!,{R5}
ADD R10,R11,#tffstart.sizeof
STR R2,[R10,#tffend.len]
STR R2,[R10,#tffend.dataofs]
ADD R2,R2,#tffend.sizeof
SUB R2,R2,#5   ; (-8 +3)
BIC R2,R2,#3
STR R2,[R11,#tffstart.blocklen]
ORR R3,R3,#&FF
STR R3,[R10,#tffend.finetune]
STR R4,[R10,#tffend.repofs]
CMP R5,#2
MOVLT R5,#2
STR R5,[R10,#tffend.replen]

MOV R1,#tffstart.sizeof+tffend.sizeof
MOV R2,#filetype_tracker
LDMFD R13!,{R3-R6,R10,PC}
.ids
DCB "Sta1"
DCB "SAMP"
.userid
DCB "User"
ALIGN

.formatsample
STMFD R13!,{R0-R8,R14}
ADR R4,ids
LDMIA R4,{R1-R3}
LDR R0,[R10,#s.addr]
LDR R0,[R0]
MOV R4,#format_unknown
CMP R0,R1
MOVEQ R4,#format_stasis
CMP R0,R2
MOVEQ R4,#format_tracker
CMP R0,R3
MOVEQ R4,#format_user
CMP R4,#format_unknown
BLEQ vetunknown
STR R4,[R10,#s.format]
LDMFD R13!,{R0-R8,PC}

.vetunknown
STMFD R13!,{R14}
LDR R0,[R10,#s.addr]
LDR R2,[R12,#v.filetype]
LDR R3,[R10,#s.length]
MOV R1,#Service_UKStasisFormat
SWI OS_ServiceCall
CMP R1,#0
MOVNE R4,#format_unknown
LDMNEFD R13!,{PC}
STR R0,[R10,#s.alien]
MOV R4,#format_alien
LDMFD R13!,{PC}

.sampleload
STMFD R13!,{R14}
LDR R12,[R12]        ;where's my workspace?
MOV R4,R1
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R0,R2
MOV R2,#type_rma
CMP R4,#3
MOVEQ R2,#type_amnesia
ADD R1,R1,#1
BL loadswi
LDMFD R13!,{PC}

.weedslots
STMFD R13!,{R1-R11,R14}
MOV R4,R0
MOV R5,R1
ADD R11,R12,#v.slottab
MOV R3,#0
.weedloop
LDR R0,[R11,R4]
CMP R0,R5
BLEQ weedit
ADD R11,R11,#s.sizeof
ADD R3,R3,#1
CMP R3,#entries
BLT weedloop
LDMFD R13!,{R1-R11,PC}^

.weedit
STMFD R13!,{R14}
CMP R4,#s.type
CMPEQ R5,#type_amnesia
BEQ weedamnesia
MOV R0,R3
BL releaseslot
.weedins
LDMFD R13!,{PC}
.weedamnesia
MOV R0,R3
BL stopslot
MOV R0,#0
STR R0,[R11,#s.addr]
MOV R0,#type_empty
STR R0,[R11,#s.type]
B weedins

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

getslotaddr R0,R10
TEQ R2,#type_amnesia
BLEQ amnesiaload
LDMVSFD R13!,{R1-R9,PC}
TEQ R2,#type_amnesia
BLNE rmaload
LDMVSFD R13!,{R1-R9,PC}
filelength R1,R0
MOVVS R0,#0
MOVNE R0,#0
STR R0,[R10,#s.length]
BL formatsample
LDMFD R13!,{R1-R9,PC}

.releaseslot
STMFD R13!,{R1-R10,R14}
getslotaddr R0,R10
BL stopslot
LDR R0,[R10,#s.type]
CMP R0,#type_empty
LDMEQFD R13!,{R1-R10,PC}
LDR R1,[R10,#s.format]
CMP R1,#format_alien
BLEQ alienrelease
LDR R0,[R10,#s.type]
CMP R0,#type_amnesia
BEQ amnesiarelease
CMP R0,#type_rma
BEQ rmarelease
CMP R0,#type_user
BEQ rmarelease ; Yes, this is correct
CMP R0,#type_link
CMPNE R0,#type_safelink
BEQ linkrelease
LDMFD R13!,{R1-R10,R14}
B releaseerr
.releaseslotins
LDMFD R13!,{R1-R10,PC}

.stopslot
STMFD R13!,{R1-R5,R14}
MOV R3,#0
.stoploop
getconaddr R3,R5
LDR R1,[R5,#con.slot]
CMP R1,R0
LDREQ R1,[R5,#con.status]
ORREQ R1,R1,#status_gated
STREQ R1,[R5,#con.status]
ADD R3,R3,#1
CMP R3,#8
BLT stoploop
LDMFD R13!,{R1-R5,PC}

.alienrelease
STMFD R13!,{R0-R1,R7-R11,R14}
LDR R11,[R10,#s.addr]
MOV R0,#alien.release
BL alienjump
;MOV R0,#type_empty
;STR R0,[R10,#s.type]
LDMFD R13!,{R0-R1,R7-R11,PC}

.amnesiarelease
LDR R0,[R10,#s.addr]
CMP R0,#&8000
SWIGE XAmnesia_ReleaseBlock
MOV R0,#type_empty
STR R0,[R10,#s.type]
B releaseslotins

.rmarelease
LDR R0,[R10]
releaserma R0
MOV R0,#type_empty
STR R0,[R10,#s.type]
B releaseslotins

.linkrelease
MOV R0,#type_empty
STR R0,[R10,#s.type]
B releaseslotins

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

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

.usercreate
STMFD R13!,{R1-R7,R14}
MOV R0,#userform.sizeof
claimrma R0,R2
LDMVSFD R13!,{R1-R7,R14}
BVS noroomerr
STR R2,[R10,#s.addr]
MOV R0,#type_user
STR R0,[R10,#s.type]
MOV R0,#format_user
STR R0,[R10,#s.format]
ADR R0,userid
LDR R0,[R0]
STR R0,[R2]
MOV R0,#0
STR R0,[R2,#4]
STR R0,[R2,#8]
STR R0,[R2,#12]
STR R0,[R2,#16]
LDMFD R13!,{R1-R7,PC}

.closefile
STMFD R13!,{R14}
MOV R0,#0
MOV R1,R9
CMP R1,#0
SWINE XOS_Find 
LDMFD R13!,{PC}^


.namecopy
STMFD R13!,{R0-R5,R14}
;R5=namelen
MOV R4,#0
.loop10         ;Copy name
LDRB R2,[R1,R4]
CMP R2,#&20
BLT jumpout
STRB R2,[R0,R4]
ADD R4,R4,#1
CMP R4,R5
BLT loop10
LDMFD R13!,{R0-R5,PC}
.jumpout
MOV R2,#0
STRB R2,[R0,R4]
ADD R4,R4,#1
CMP R4,R5
BLT jumpout
LDMFD R13!,{R0-R5,PC}

.setname
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R0,R2
ADD R1,R1,#1
BL nameswi
LDMFD R13!,{PC}

.nameswi
STMFD R13!,{R8,R14}
MOV R8,#1<<1
BL putslotinfo
LDMFD R13!,{R8,PC}

.setfinetune
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R8,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R0,R8
MOV R3,R2
MOV R8,#1<<3
BL putslotinfo
LDMFD R13!,{PC}

.setrepeat
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R8,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R4,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R5,R2
MOV R0,R8
MOV R8,#3<<4
BL putslotinfo
LDMFD R13!,{PC}

.setlength
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R8,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R0,R8
MOV R8,#1<<2
BL putslotinfo
LDMFD R13!,{PC}

.setvolume
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R8,R2
MOV R0,#16
SWI OS_ReadUnsigned
MOV R7,R2 
MOV R0,R8
MOV R8,#1<<7
BL putslotinfo
LDMFD R13!,{PC}

.volslidecom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R3,R2
MOV R0,#16
SWI OS_ReadUnsigned
MOV R4,R2 
MOV R0,#16
SWI OS_ReadUnsigned
MOV R0,R3
MOV R1,R4
BL volslideswi
LDMFD R13!,{PC}

.volslideswi
STMFD R13!,{R14}
MOV R3,R2
MOV R2,R1
MOV R1,#0
BL slideswi
LDMFD R13!,{PC}

.pitchslidecom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R3,R2
MOV R0,#16
SWI OS_ReadUnsigned
MOV R4,R2 
MOV R0,#16
SWI OS_ReadUnsigned
MOV R0,R3
MOV R1,R4
BL pitchslideswi
LDMFD R13!,{PC}

.pitchslideswi
STMFD R13!,{R14}
MOV R3,R2
MOV R2,R1
MOV R1,#1
BL slideswi
LDMFD R13!,{PC}

.slideswi
STMFD R13!,{R1-R3,R14}
SUB R10,R0,#1
AND R10,R10,#7
getconaddr R10,R11
AND R1,R1,#3
CMP R1,#0
BLEQ slidevolconv
CMP R1,#1
BLEQ slidepitchconv
ADD R10,R11,#con.slides
ADD R10,R10,R1,LSL #3
TST R0,#1<<29   ;all of these perform the action if the bit is zero
BLEQ slidetimeconv
TST R0,#1<<29
BLNE sliderateconv
TST R0,#1<<31
STREQ R2,[R10]
TST R0,#1<<30
STREQ R3,[R10,#4]
LDR R0,[R11,#con.status]
MOV R3,#status_slide
ORR R0,R0,R3,LSL R1
STR R0,[R11,#con.status]
MOV R0,R2
LDMFD R13!,{R1-R3,PC}

.slidetimeconv
STMFD R13!,{R0-R1,R14}
CMP R1,#0
LDREQ R0,[R11,#con.volume]
CMP R1,#1
LDREQ R0,[R11,#con.pitch]
SUB R0,R2,R0
MYDIV R1,R0,R3
MOV R3,R1,ASL #1
LDMFD R13!,{R0-R1,PC}

.sliderateconv
STMFD R13!,{R0-R1,R14}
CMP R1,#0
LDREQ R0,[R11,#con.volume]
CMP R1,#1
LDREQ R0,[R11,#con.pitch]
SUBS R0,R2,R0
LDMPLFD R13!,{R0-R1,PC}
CMP R3,#0
RSBGT R3,R3,#0
LDMFD R13!,{R0-R1,PC}

.volumeswi
STMFD R13!,{R1-R4,R14}
MOV R2,R1
MOV R4,#ig_slot+ig_pitch+ig_update
BL soundswi
LDMFD R13!,{R1-R4,PC}

.odrcommand
STMFD R13!,{R14}
SWI OS_WriteS
DCB "Overdrive is no longer supported by this module",10,13,0
ALIGN
LDMFD R13!,{PC}

.getaddressswi
MOV R0,R12
MOV PC,R14

.statecom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R3,R1
MOV R1,R0
MOV R0,#10
CMP R3,#0
MOV R2,#1
SWIGT OS_ReadUnsigned 
MOV R0,R2
CMP R0,#8
ANDGT R0,R0,#7
BL stateswi
LDMFD R13!,{PC}

.stateswi
STMFD R13!,{R1-R10,R14}
BL stateinfo
LDMFD R13!,{R1-R10,PC}

.stateinfo
MOV R3,R0
SUBS R0,R0,#1
AND R0,R0,#7
BPL channelinfo
STMFD R13!,{R14}
write
DCB "State of module"
DCB 10,13,"Workspace address &"
endwrite
MOV R0,R12
BL writehex8
write
DCB 10,13,"Sample rate       &"
endwrite
LDR R0,[R12,#v.samprate]
BL writehex4
write
DCB 10,13,"Master tuning     &"
endwrite
LDR R0,[R12,#v.mastertune]
BL writehex4
write
DCB 10,13,"Real tuning       &"
endwrite
LDR R0,[R12,#v.realtune]
BL writehex4
write
DCB 10,13,"100Hz timer       &"
endwrite
LDR R0,[R12,#v.timer]
BL writehex4
write
DCB 10,13,"Rate change callbacks sent     &"
endwrite
LDR R0,[R12,#v.callbacks]
BL writehex4
write
DCB 10,13,"Rate change callbacks received &"
endwrite
LDR R0,[R12,#v.received]
BL writehex4
SWI OS_NewLine
LDMFD R13!,{PC}


.channelinfo
STMFD R13!,{R14}
getconaddr R0,R11
write
DCB "State of channel "
endwrite
MOV R0,R3
BL writecard
write
DCB 10,13,"Last played slot "
endwrite
LDR R0,[R11,#con.slot]
BL writecard
write
DCB 10,13,"Control block address &"
endwrite
MOV R0,R11
BL writehex8
write
DCB 10,13,"Sample address &"
endwrite
LDR R0,[R11,#con.addr]
BL writehex8
write
DCB 10,13,"Sample length  &"
endwrite
LDR R0,[R11,#con.length]
BL writehex8
write
DCB 10,13,"Repeat offset  &"
endwrite
LDR R0,[R11,#con.repofs]
BL writehex4
write
DCB 10,13,"Repeat length  &"
endwrite
LDR R0,[R11,#con.replen]
BL writehex4
write
DCB 10,13,"Pitch (internal)  &"
endwrite
LDR R0,[R11,#con.pitch]
BL writehex8
write
DCB 10,13,"Raw pitch         &"
endwrite
LDR R0,[R11,#con.rawpitch]
BL writehex8
write
DCB 10,13,"Volume (internal) &"
endwrite
LDR R0,[R11,#con.volume]
BL writehex8
write
DCB 10,13,"Log amp table at  &"
endwrite
LDR R0,[R11,#con.logampadr]
BL writehex8
write
DCB 10,13,"Phase accumulator &"
endwrite
LDR R0,[R11,#con.acc]
BL writehex8
write
DCB 10,13,"State changes     &"
endwrite
LDR R0,[R11,#con.states]
BL writehex4
write
DCB 10,13,"Current state     &"
endwrite
LDR R0,[R11,#con.laststate]
BL writehex8
write
DCB 10,13,"Previous state    &"
endwrite
LDR R0,[R11,#con.prevstate]
BL writehex8
write
DCB 10,13,"Auto rate changes &"
endwrite
LDR R0,[R11,#con.ratechange]
BL writehex4
write
DCB 10,13,"Buffer 1 address  &"
endwrite
LDR R0,[R11,#con.buf1]
BL writehex8
write
DCB 10,13,"Buffer 2 address  &"
endwrite
LDR R0,[R11,#con.buf2]
BL writehex8
write
DCB 10,13,"Last buffer filled = "
endwrite
LDR R0,[R11,#con.lastbuf]
BL writecard
write
DCB 10,13,"Flash buffer fills &"
endwrite
LDR R0,[R11,#con.flashbufs]
BL writehex4
write
DCB 10,13,"Fast buffer fills  &"
endwrite
LDR R0,[R11,#con.fastbufs]
BL writehex4
write
DCB 10,13,"Slow buffer fills  &"
endwrite
LDR R0,[R11,#con.slowbufs]
BL writehex4
write
DCB 10,13,"Fixed pitch fills  &"
endwrite
LDR R0,[R11,#con.fixedbufs]
BL writehex4
write
DCB 10,13,"Buffer flushes     &"
endwrite
LDR R0,[R11,#con.flushes]
BL writehex4
write
DCB 10,13,"Kicks              &"
endwrite
LDR R0,[R11,#con.kicks]
BL writehex4
write
DCB 10,13,"Channel status :",10,13
endwrite
LDR R1,[R11,#con.status]
TST R1,#status_volslide
ADRNE R0,volslidetext
ADDNE R2,R11,#con.volslide
BLNE writeslide
TST R1,#status_pitchslide
ADRNE R0,pitchslidetext
ADDNE R2,R11,#con.pitchslide
BLNE writeslide

TST R1,#status_gated
ADRNE R0,gatedtext
SWINE OS_Write0
TST R1,#status_q1
ADRNE R0,q1text
SWINE OS_Write0
TST R1,#status_q2
ADRNE R0,q2text
SWINE OS_Write0
TST R1,#status_escape
ADRNE R0,escapetext
SWINE OS_Write0
TST R1,#status_kick
ADRNE R0,kicktext
SWINE OS_Write0
TST R1,#status_off
ADRNE R0,offtext
SWINE OS_Write0
TST R1,#status_fresh
ADRNE R0,freshtext
SWINE OS_Write0
TST R1,#status_safe
ADRNE R0,safetext
SWINE OS_Write0
TST R1,#status_attached
ADRNE R0,attachedtext
SWINE OS_Write0
TST R1,#status_live
ADRNE R0,livetext
SWINE OS_Write0
SWI OS_NewLine
LDMFD R13!,{PC}



.gatedtext
DCB "Gated off",10,13,0
.q1text
DCB "Buffer 1 flushed",10,13,0
.q2text
DCB "Buffer 2 flushed",10,13,0
.escapetext
DCB "Silenced by escape",10,13,0
.livetext
DCB "Live",10,13,0
.kicktext
DCB "Kick active",10,13,0
.offtext
DCB "Off",10,13,0
.freshtext
DCB "Fresh",10,13,0
.volslidetext
DCB "Volume slide,",0
.pitchslidetext
DCB "Pitch slide, ",0
.safetext
DCB "Safe",10,13,0
.attachedtext
DCB "Attached",10,13,0
ALIGN

.writeslide
STMFD R13!,{R0-R1,R14}
SWI OS_Write0
write
DCB " target &"
endwrite
LDR R0,[R2]
BL writehex8
write
DCB ", rate &"
endwrite
LDR R0,[R2,#4]
BL writehex8
write
DCB ".",10,13
endwrite
LDMFD R13!,{R0-R1,PC}



.infocom
STMFD R13!,{R14}
LDR R12,[R12]
MOV R3,R1
MOV R1,R0
MOV R0,#10
CMP R3,#0
MOV R2,#1
SWIGT OS_ReadUnsigned 
MOV R0,R2
ANDGT R0,R0,#entries-1
BL infoswi
LDMFD R13!,{PC}

.infoswi
STMFD R13!,{R1-R10,R14}
BL infoinfo
LDMFD R13!,{R1-R10,PC}

.infoinfo
STMFD R13!,{R14}
MOV R9,R0
getslotaddr R0,R10
write
DCB "Information held by Stasis on slot "
endwrite
MOV R0,R9
BL writecard
LDR R0,[R10,#s.type]
CMP R0,#type_empty
BEQ emptyinfo
write
DCB 10,13,"======================================="
DCB 10,10,13,"Address of sample              &"
endwrite
LDR R0,[R10,#s.addr]
BL writehex8
write
DCB 10,13,   "Length of file at that address &"
endwrite
LDR R0,[R10,#s.length]
BL writehex8
write
DCB 10,13,"Storage type "
endwrite
LDR R0,[R10,#s.type]
BL writecard
SWI 256+" "
SWI 256+":"
SWI 256+" "
LDR R0,[R10,#s.type]
BL writetype
write
DCB 10,13,"Sample format  : "
endwrite
LDR R0,[R10,#s.format]
BL writeformat
LDR R0,[R10,#s.format]
CMP R0,#format_alien
BLEQ writealien
write
DCB 10,10,13,"Information held by sample data"
DCB    10,13,"===============================",10,13
endwrite
MOV R0,R9
BL getslotinfo
LDMVSFD R13!,{PC}
write
DCB 10,13,"Sample name   : "
endwrite
MOV R0,R1
CMP R0,#0
ADREQ R0,nullname
BL writename
write
DCB 10,13,   "Sample format : "
endwrite
LDR R11,[R10,#s.addr]
BL writebigformat
write
DCB 10,13,"Sample data address  &"
endwrite
MOV R0,R6
BL writehex8
write
DCB 10,13,"Sample length        &"
endwrite
MOV R0,R2
BL writehex8
write
DCB 10,13,"Sample repeat offset &"
endwrite
MOV R0,R4
BL writehex4
write
DCB 10,13,"Sample repeat length &"
endwrite
MOV R0,R5
BL writehex4
write
DCB 10,13,"Sample finetune      &"
endwrite
MOV R0,R3
BL writehex4
write
DCB 10,13,"Sample volume        &"
endwrite
MOV R0,R7
BL writehex4
SWI OS_NewLine
LDMFD R13!,{PC}^
.emptyinfo
write
DCB 10,13,"There is no sample in this slot.",10,13
endwrite
LDMFD R13!,{PC}
.writealien
STMFD R13!,{R14}
write
DCB 10,13,"Alien format description routines at &"
endwrite
LDR R0,[R10,#s.alien]
BL writehex8
MOV R0,#alien.modname
BL getalienindirect
LDMVSFD R13!,{PC}
LDMEQFD R13!,{PC}
write
DCB " in module "
endwrite
SWI OS_Write0
LDMFD R13!,{PC}

.nullname
DCB "Sample has no name  ",0
.nullformat
DCB "Sample has no format description",0
ALIGN

.writebigformat
STMFD R13!,{R1,R14}
LDR R0,[R10,#s.format]
CMP R0,#format_alien
BEQ writealienformat
BL writeformat
MOV R1,#0
LDR R0,[R10,#s.format]
CMP R0,#format_stasis
MOVEQ R1,#filetype_stasis
CMP R0,#format_tracker
MOVEQ R1,#filetype_tracker
.writefiletype
CMP R1,#0
BEQ writefiletypeend
write
DCB " (filetype &"
endwrite
MOV R0,R1
BL writehex3
SWI 256+")"
.writefiletypeend
LDMFD R13!,{R1,PC}

.writealienformat
MOV R1,#0
MOV R0,#alien.formatname
BL getalienindirect
BVS writefiletype
SWINE OS_Write0
write 
DCB ", savename "
endwrite
MOV R0,#alien.name
BL getalienindirect
BVS writefiletype
SWINE OS_Write0
MOV R0,#alien.filetype
BL getalienaddr
BVS writefiletype
LDR R1,[R0]
B writefiletype

.writeformat
STMFD R13!,{R1,R14}
MOV R1,#0
CMP R0,#format_unknown
ADREQ R1,format_unknowntext
CMP R0,#format_stasis
ADREQ R1,format_stasistext
CMP R0,#format_tracker
ADREQ R1,format_trackertext
CMP R0,#format_user
ADREQ R1,format_usertext
CMP R0,#format_alien
ADREQ R1,format_alientext
CMP R1,#0
ADREQ R1,format_unidentifiedtext
MOV R0,R1
SWI OS_Write0
LDMFD R13!,{R1,PC}
.format_unknowntext
DCB "Unknown - checked but not matched to any known format",0
.format_stasistext
DCB "Stasis - native format",0
.format_trackertext
DCB "Tracker - TFF",0
.format_usertext
DCB "User - pointers to user specified memory",0
.format_alientext
DCB "Alien - supported by an external module",0
.format_unidentifiedtext
DCB "Unidentified - no attempt has been made",0
ALIGN


.writetype
STMFD R13!,{R1,R14}
MOV R1,#0
CMP R0,#type_empty
ADREQ R1,type_emptytext
CMP R0,#type_rma
ADREQ R1,type_rmatext
CMP R0,#type_amnesia
ADREQ R1,type_amnesiatext
CMP R0,#type_user
ADREQ R1,type_usertext
CMP R0,#type_link
ADREQ R1,type_linktext
CMP R0,#type_safelink
ADREQ R1,type_safelinktext
CMP R1,#0
ADREQ R1,type_unidentifiedtext
MOV R0,R1
SWI OS_Write0
LDMFD R13!,{R1,PC}
.type_emptytext
DCB "Empty - no sample in this slot",0
.type_rmatext
DCB "RMA - stored in the relocatable module area",0
.type_amnesiatext
DCB "Amnesia - stored in the current Amnesia area",0
.type_usertext
DCB "User - a block of pointers in the RMA point to user memory",0
.type_linktext
DCB "Link - a link to a sample in user memory",0
.type_safelinktext
DCB "Safe Link - a link to a sample in the RMA",0
.type_unidentifiedtext
DCB "Unidentified - storage type is not known - indicates an error",0
ALIGN

.samplecat
STMFD R13!,{R14}
LDR R12,[R12]
MOV R3,R1
MOV R1,R0
MOV R0,#10
CMP R3,#0
MVN R2,#0
SWIGT OS_ReadUnsigned 
MOV R4,R2
CMP R3,#1
MVN R2,#0
SWIGT OS_ReadUnsigned 
MOV R0,R4
MOV R1,R2
BL catswi
LDMFD R13!,{PC}

.catswi
STMFD R13!,{R14}
SWI 256+14; page mode on
SWI OS_WriteS 
DCB  " Channel  Slot      Sample Name        Where   Address   Length Repeat Repeat"
DCB 10
DCB 13
DCB  "                                                                Offset Length"
DCB 10
DCB 13
DCB  "=========|====|======================|=======|==========|======|======|======"
DCB 13
DCB 10
DCB 0
ALIGN

CMN R0,#1
MOVEQ R0,#0
MOVEQ R1,#16
CMN R1,#1
MOVEQ R1,R0
limit R0
limit R1
.loop12
BL sampleinfo
ADD R0,R0,#1
CMP R0,R1
BLE loop12
LDMFD R13!,{PC}

.sampleinfo
STMFD R13!,{R0-R4,R14}
MOV R5,R0
ADD R4,R12,#v.linktab
MOV R3,#0
.loop13
LDRB R0,[R4,R3]
CMP R0,R5
ADDEQ R0,R3,#"1"   
SWIEQ OS_WriteC 
SWINE &120
ADD R3,R3,#1
CMP R3,#8
BLT loop13

SWI OS_WriteS 
DCB  " | "
DCB 0
ALIGN
MOV R0,R5
CMP R0,#10
SWILT &120
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertCardinal1 
MOV R1,#2
SWI OS_Write0 
SWI OS_WriteS 
DCB  " | "
DCB 0
ALIGN
MOV R0,R5
getslotaddr R0,R7
LDR R7,[R7,#s.type]
STMFD R13!,{R7}
BL getslotinfo
LDMFD R13!,{R7}
LDMVSFD R13!,{R0-R4,PC}
STMFD R13!,{R0-R6}
MOV R0,R1
BL writename
SWI OS_WriteS 
DCB  " | "
DCB 0
ALIGN
LDMFD R13!,{R0-R6}

ADR R0,textnowhere
CMP R7,#type_rma
ADREQ R0,textrma
CMP R7,#type_user
ADREQ R0,textuser
CMP R7,#type_link
ADREQ R0,textlink
CMP R7,#type_safelink
ADREQ R0,textsafelink
CMP R7,#type_amnesia
ADREQ R0,textamnesia
MOV R1,#5
SWI OS_WriteN 
MOV R0,R6
BL printhex8
MOV R0,R2
BL printhex4
MOV R0,R4
BL printhex4
MOV R0,R5
BL printhex4
SWI OS_NewLine 
LDMFD R13!,{R0-R4,PC}

.printhex4
STMFD R13!,{R1-R3,R14}
SWI OS_WriteS 
DCB  " |"
DCB 0
ALIGN
CMP R0,#2
BLE printnone4
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertHex8 
LDRB R3,[R0,#3]
CMP R3,#"0"   
SWIEQ &120
MOVEQ R1,#4
ADDEQ R0,R0,#4
MOVNE R1,#5
ADDNE R0,R0,#3
SWI OS_WriteN
.print4ins 
LDMFD R13!,{R1-R3,PC}

.printhex8
STMFD R13!,{R1-R2,R14}
SWI OS_WriteS 
DCB  " | "
DCB 0
ALIGN
CMP R0,#0
BEQ printnone8
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertHex8 
MOV R1,#8
SWI OS_WriteN
.print8ins 
LDMFD R13!,{R1-R2,PC}

.printnone4
SWI OS_WriteS 
DCB  "  -- "
DCB 0
ALIGN
B print4ins

.printnone8
SWI OS_WriteS 
DCB  "  ----  "
DCB 0
ALIGN
B print8ins

.textnowhere
DCB  "Empty"
.textrma
DCB  " RMA "
.textuser
DCB  "User "
.textlink
DCB  "Link "
.textsafelink
DCB  "SLink"
.textamnesia
DCB "Amsia"
ALIGN

.writename
STMFD R13!,{R1-R2,R14}
MOV R2,R0
MOV R1,#0
.loop14
CMP R2,#0
LDRNEB R0,[R2,R1]
MOVEQ R0,#" "
CMP R0,#" "
MOVLT R0,#" "
MOVLT R2,#0
CMP R0,#&7F
MOVGE R0,#"?"   
SWI OS_WriteC 
ADD R1,R1,#1
CMP R1,#namelen
BLT loop14
LDMFD R13!,{R1-R2,PC}

.writehex8
STMFD R13!,{R1-R2,R14}
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertHex8 
SWI OS_Write0
LDMFD R13!,{R1-R2,PC}

.writehex4
STMFD R13!,{R1-R2,R14}
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertHex8
#rept 4
LDRB R1,[R0]
CMP R1,#"0"
ADDEQ R0,R0,#1
#endr 
SWI OS_Write0
LDMFD R13!,{R1-R2,PC}

.writehex3
STMFD R13!,{R1-R2,R14}
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertHex4
LDRB R1,[R0]
CMP R1,#"0"
ADDEQ R0,R0,#1
SWI OS_Write0
LDMFD R13!,{R1-R2,PC}

.writecard
STMFD R13!,{R1-R2,R14}
ADD R1,R12,#v.textbuf
MOV R2,#16
SWI OS_ConvertCardinal1
SWI OS_Write0
LDMFD R13!,{R1-R2,PC}

.sample
STMFD R13!,{R14}
LDR R12,[R12]
MOV R10,R1  ;no of params
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R5,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R6,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R7,R2
MOV R8,#0
MOV R9,#0
CMP R10,#5
BLT norepspec
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R8,R2
MOV R0,#16
SWI OS_ReadUnsigned 
MOV R9,R2
.norepspec
MOV R0,R5
MOV R1,R6
MOV R2,R7
MOV R3,R8
MOV R4,R9
BL sampleswi
LDMFD R13!,{PC}

.sampleswi
STMFD R13!,{R1-R9,R14}
CMP R1,#0
BEQ samplerelease
getslotaddr R0,R10
LDR R9,[R10,#s.type]
CMP R9,#type_user
BEQ samplenorelease
STMFD R13!,{R0-R4}
BL releaseslot
MOVVS R14,R0
LDMFD R13!,{R0-R4}
MOVVS R0,R14
LDMVSFD R13!,{R1-R9,PC}
getslotaddr R0,R10
BL usercreate
LDMVSFD R13!,{R1-R9,PC}
.samplenorelease
LDR R10,[R10,#s.addr]
CMN R1,#1
STRNE R1,[R10,#userform.addr]
CMN R2,#1
STRNE R2,[R10,#userform.len]
CMN R3,#1
STRNE R3,[R10,#userform.repofs]
CMN R4,#1
STRNE R4,[R10,#userform.replen]
LDMFD R13!,{R1-R9,PC}
.samplerelease  
BL releaseslot
LDMFD R13!,{R1-R9,PC}

.makelinkswi
STMFD R13!,{R1-R9,R14}
getslotaddr R0,R10

STR R1,[R10,#s.addr]
CMP R2,#1
MOV R2,#type_link
MOVEQ R2,#type_safelink
STR R2,[R10,#s.type]
BL formatsample
LDMFD R13!,{R1-R9,PC}

.samplelink
STMFD R13!,{R9-R12,R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R4,R2
SWI OS_ReadUnsigned 
MOV R1,R2
MOV R0,R4
BL linkswi
ADD R0,R0,#1
BL attachswi
LDMFD R13!,{R9-R12,R14}
BVS attacherr
MOV PC,R14

.attachswi
STMFD R13!,{R1-R4,R14}
ADR R1,voicename
SWI XSound_AttachNamedVoice
LDMVSFD R13!,{R1-R4,PC}
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
BL soundswi
LDMFD R13!,{R1-R4,PC}

.linkswi
STMFD R13!,{R2,R14}
SUB R0,R0,#1
AND R0,R0,#7
ADD R2,R12,#v.linktab
AND R1,R1,#entries-1
STRB R1,[R2,R0]
LDMFD R13!,{R2,PC}

.tunecommand
STMFD R13!,{R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#16
SWI OS_ReadUnsigned
MOV R0,R2
BL tuneswi 
LDMFD R13!,{PC}

.tuneswi
STMFD R13!,{R0,R14}
CMP R0,#0
MOVEQ R0,#tune_default
STR R0,[R12,#v.mastertune]
BL rateupdate
LDMFD R13!,{R0,PC}

.service
CMP R1,#&46
BEQ modechange
CMP R1,#&4E
BEQ newapplication
STMFD R13!,{R0}
MOV R0,#Service_Amnesia
CMP R1,R0
LDMFD R13!,{R0}
MOVNES PC,R14
CMP R3,#0; Area discard
MOVNES PC,R14
STMFD R13!,{R0-R1,R14}
LDR R12,[R12]
MOV R0,#s.type
MOV R1,#type_amnesia
BL weedslots
LDMFD R13!,{R0-R1,PC}

.newapplication
STMFD R13!,{R0-R1,R14}
LDR R12,[R12]
MOV R0,#s.type
MOV R1,#type_link
BL weedslots
MOV R0,#s.type
MOV R1,#type_user
BL weedslots
LDMFD R13!,{R0-R1,PC}

.modechange
STMFD R13!,{R0-R11,R14}
MOV R0,#0
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
MOV R5,R0
MOV R0,#1
MOV R1,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
MOV R0,R5
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
LDMFD R13!,{R0-R11,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]
MOV R0,#0
MOV R1,#v.sizeof
.wloop1
STR R0,[R2],#4
SUBS R1,R1,#4
BGT wloop1
.clskip
LDR R12,[R12]  ;real workspace
STR R12,varstr
ADD R0,R12,#v.contab
STR R0,constr
ADR R1,waveinit
ADD R2,R12,#v.linktab
LDMIA R1,{R3,R4}
STMIA R2,{R3,R4};set up the link table
MOV R0,#tune_default
STR R0,[R12,#v.mastertune]
.gameloop
LDRB R1,[R10],#1
CMP R1,#32
BEQ gameloop
BIC R1,R1,#1<<5
CMP R1,#"G"   
BLEQ stasisgame
MOV R3,#entries
ADD R2,R12,#v.slottab
MOV R0,#type_empty
.loop2
STR R0,[R2,#s.type]
ADD R2,R2,#s.sizeof
SUBS R3,R3,#1
BGT loop2
ADD R2,R12,#v.contab
MOV R3,#con.sizeof*8
MOV R0,#0
.loop3
STR R0,[R2],#4
SUBS R3,R3,#4
BGT loop3
ADR R0,voicebase
MOV R1,#0
SWI XSound_InstallVoice
LDMVSFD R13!,{R7-R11,R14}
BVS attacherr
STR R1,[R12,#v.slot]
BL modechange
BL rateupdate
BL claimvector
MOV R1,#Service_PsychoStarting
MOV R0,#1
MOV R2,R12
SWI OS_ServiceCall
LDMFD R13!,{R7-R11,PC}

.stasisgame
STMFD R13!,{R14}
MOV R0,#0
MOV R1,#208
MOV R2,#48
MOV R3,#0
MOV R4,#0
SWI Sound_Configure 
LDMFD R13!,{PC}
.waveinit
DCD &04030201
DCD &08070605

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

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

.final
STMFD R13!,{R7-R11,R14}
LDR R12,[R12]
MOV R1,#Service_PsychoDying
MOV R0,#1
MOV R2,R12
SWI OS_ServiceCall

BL releasevector
LDR R1,[R12,#v.slot]
SWI XSound_RemoveVoice 
ADDVS R0,R0,#4
SWIVS OS_Write0
CMP R10,#0
BLNE releasespace

LDMFD R13!,{R7-R11,PC}^

.releasespace
STMFD R13!,{R1-R11,R14}
MOV R1,#entries-1
.loop20
MOV R0,R1
BL releaseslot
ADDVS R0,R0,#4
SWIVS OS_Write0
SUBS R1,R1,#1
BPL loop20
releaserma R12
LDMFD R13!,{R1-R11,PC}^

.voicebase
B fill
B update
B gateon
B gateoff
B instance
B free
LDMFD R13!,{PC}
DCD voicename-voicebase
.voicename
DCB  "Stasis"
DCB 0
ALIGN
.workstr
DCD 0
ALIGN

.instance
STMFD R13!,{R0-R4,R12}
LDR R12,varstr
getconaddr R0,R1
MOV R0,#status_fresh+status_attached
STR R0,[R1,#con.status]
MOV R0,#0
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure 
LDR R0,[R3,#12]
STR R0,[R12,#v.logampadr]
LDMFD R13!,{R0-R4,R12,PC}

.free
STMFD R13!,{R0-R1,R12}
LDR R12,varstr
getconaddr R0,R1
MOV R0,#0
STR R0,[R1,#con.status]
LDMFD R13!,{R0-R1,R12,PC}


.soundcommand
STMFD R13!,{R9-R12,R14}
LDR R12,[R12]
MOV R1,R0
MOV R0,#10
SWI OS_ReadUnsigned 
MOV R4,R2
SWI OS_ReadUnsigned 
MOV R5,R2
SWI OS_ReadUnsigned 
MOV R6,R2
SWI OS_ReadUnsigned 
MOV R7,R2
MOV R0,R4
MOV R1,R5
MOV R2,R6
MOV R3,R7
MOV R4,#0
MOV R5,#0
BL soundswi
LDMFD R13!,{R9-R12,PC}

.soundswi
;R0=channel
;R1=slot
;R2=volume
;R3=pitch
;R4=flags
;R5=slide time (centiseconds)
STMFD R13!,{R1-R10,R14}
SUB R0,R0,#1
getconaddr R0,R10
LDR R9,[R10,#con.status]
TST R9,#status_kick
BNE kickit
TST R4,#ig_slot
BLEQ resetslot
TSTNE R4,#ig_retrig
BLNE retrigger
TST R4,#ig_volume
BLEQ resetvolume
TST R4,#ig_pitch
BLEQ resetpitch
TST R4,#ig_update
LDMNEFD R13!,{R1-R10,PC}
TST R9,#status_live
TSTEQ R4,#ig_fromgate
BEQ kickstart
.kickit
AND R5,R9,#status_attached
ORR R5,R5,#status_live
.kickins
TST R4,#ig_escape
ANDNE R5,R9,#status_attached
ORRNE R5,R5,#status_gated+status_escape

BIC R5,R5,#status_safe
TST R4,#ig_volume
BICEQ R5,R5,#status_volslide
TST R4,#ig_pitch
BICEQ R5,R5,#status_pitchslide
LDR R0,[R10,#con.addr]
CMP R0,#0
BEQ gitskip
.gitskip
STR R5,[R10,#con.status]
LDR R0,[R12,#v.samprate]
STR R0,[R10,#con.samprate]
LDR R0,[R12,#v.logampadr]
STR R0,[R10,#con.logampadr]
LDMFD R13!,{R1-R10,PC}

.resetslot
STMFD R13!,{R0-R4,R9,R14}
CMP R1,#0
STRNE R1,[R10,#con.slot]
LDREQ R1,[R10,#con.slot]
MOV R0,R1
BL getslotinfo
STR R2,[R10,#con.length]
STR R3,[R10,#con.finetune]
STR R4,[R10,#con.repofs]
STR R5,[R10,#con.replen]
STR R6,[R10,#con.addr]
MOV R0,#0
STR R0,[R10,#con.acc]
LDMFD R13!,{R0-R4,R9,R14}
ORRVS R4,R4,#ig_escape
MOV PC,R14

.retrigger
STMFD R13!,{R0,R14}
MOV R0,#0
STR R0,[R10,#con.acc]
LDMFD R13!,{R0,PC}

.resetvolume
STMFD R13!,{R2,R14}
MOV R2,R2,LSL #9
STR R2,[R10,#con.volume]
LDMFD R13!,{R2,PC}

.slidevolconv
MOV R2,R2,LSL #9
MOV PC,R14

.resetpitch
STMFD R13!,{R0,R1,R14}
TST R4,#ig_slot
BLNE resetfinetune
TST R4,#ig_rawpitch
MOV R0,R3
STR R0,[R10,#con.rawpitch]
SWIEQ Sound_Pitch
MOVEQ R0,R0,LSR #16
LDR R1,[R10,#con.finetune]
CMP R1,#0
MULNE R0,R1,R0
MOVEQ R0,R0,LSL #finetune_shift
LDR R1,[R12,#v.realtune]
MOV R0,R0,LSR #14
MUL R0,R1,R0
STR R0,[R10,#con.pitch]
LDMFD R13!,{R0,R1,PC}

.slidepitchconv
;A mirror of above
STMFD R13!,{R0-R1,R14}
TST R0,#1<<28
MOV R0,R2
SWIEQ Sound_Pitch
MOVEQ R0,R0,LSR #16
LDR R1,[R11,#con.finetune]   ; note R11
CMP R1,#0
MULNE R0,R1,R0
MOVEQ R0,R0,LSL #finetune_shift
LDR R1,[R12,#v.realtune]
MOV R0,R0,LSR #14
MUL R0,R1,R0
MOV R2,R0
LDMFD R13!,{R0-R1,PC}


.resetfinetune
STMFD R13!,{R0-R8,R14}
BL getslotinfo
MOVVC R3,#0
STR R3,[R10,#con.finetune]
LDMFD R13!,{R0-R8,PC}

.getcontrolswi
getconaddr R0,R0
MOV PC,R14
.getslotswi
getslotaddr R0,R0
MOV PC,R14

.baserateswi
LDR R0,[R12,#v.samprate]
LDR R1,[R12,#v.realtune]
MOV PC,R14

.ratecallback
STMFD R13!,{R0}
LDR R0,[R12,#v.received]
ADD R0,R0,#1
STR R0,[R12,#v.received]
LDMFD R13!,{R0}

.rateupdate
STMFD R13!,{R0-R4,R14}
MOV R0,#0
MOV R1,#0
MOV R2,#0
MOV R3,#0
MOV R4,#0
SWI Sound_Configure
CMP R0,#1
MOVEQ R0,#0
CMP R0,#2
MOVEQ R0,#1
CMP R0,#4
MOVEQ R0,#2
CMP R0,#8
MOVEQ R0,#3

STR R0,[R12,#v.oldchan]
STR R2,[R12,#v.samprate]
STR R2,[R12,#v.newrate]
LDR R0,[R12,#v.mastertune]
MUL R0,R2,R0
MOV R2,#48
MYDIV R1,R0,R2
STR R1,[R12,#v.realtune]
MOV R1,#Service_StasisRate
LDR R0,[R12,#v.samprate]
LDR R2,[R12,#v.realtune]
SWI OS_ServiceCall
LDMFD R13!,{R0-R4,PC}

.reflush
STMFD R13!,{R0-R2,R14}
MOV R2,#0
.reflushloop
getconaddr R2,R1
LDR R0,[R1,#con.status]
BIC R0,R0,#status_q1+status_q2
STR R0,[R1,#con.status]
ADD R2,R2,#1
CMP R2,#8
BLT reflushloop
LDMFD R13!,{R0-R2,PC}

.kickstart
STMFD R13!,{R0-R4}
ADD R1,R0,#1
ADR R0,kickback
SWI OS_AddCallBack
AND R5,R9,#status_attached
ORR R5,R5,#status_kick
LDR R0,[R10,#con.kicks]
ADD R0,R0,#1
STR R0,[R10,#con.kicks]
LDMFD R13!,{R0-R4}
B kickins

.kickback
STMFD R13!,{R0-R4,R14}
MOV R0,R12
MOV R1,#&100
MOV R2,#2
MOV R3,#1
SWI Sound_Control
LDMFD R13!,{R0-R4,PC}

.varstr
DCD 0
.constr
DCD 0
.update
MOV R0,PC
ORR R0,R0,#3
TEQP R0,#0       ;switch to SVC
MOV R0,R0
STMFD R13!,{R7-R12,R14}
LDR R12,varstr

AND R7,R7,#7
ADD R0,R7,#1
MOV R1,#0
LDRB R2,[R9,#sccb.volume]
LDR R3,[R9,#sccb.duration]
BL slideswi

ADD R0,R7,#1
MOV R1,#1
LDR R2,[R9,#sccb.pitch]
LDR R3,[R9,#sccb.duration]
ORR R0,R0,#1<<28
BL slideswi

LDMFD R13!,{R7-R12,R14}
B fill

.gateon         ; ***GATE ON***
;time to stuff IRQ mode
MOV R0,PC
ORR R0,R0,#3
TEQP R0,#0       ;switch to SVC
MOV R0,R0
STMFD R13!,{R12,R14}
LDR R12,varstr

AND R7,R7,#7
ADD R1,R12,#v.linktab
ADD R0,R7,#1
LDRB R1,[R1,R7]
LDRB R2,[R9,#sccb.volume]

AND R2,R2,#&7F
LDR R3,[R9,#sccb.pitch]
MOV R4,#ig_rawpitch+ig_fromgate
CMP R2,#1  ;trap for escape silencing
ORREQ R4,R4,#ig_escape
BL soundswi
LDMFD R13!,{R12,R14}

.fill
MOV R0,PC
ORR R0,R0,#3
TEQP R0,#0  ;switch to SVC
MOV R0,R0
STMFD R13!,{R14}
AND R7,R7,#7
LDR R0,constr
ADD R7,R0,R7,LSL #stac_shift
LDR R0,[R7,#con.status]
ORR R0,R0,#status_safe
STR R0,[R7,#con.status]
TST R8,#1<<31
BLNE ratechange
LDRB R0,[R9,#sccb.volume]
LDMIA R7,{R1-R6,R8-R9}
CMP R12,R1
MOVEQ R0,#1
CMP R12,R2
MOVEQ R0,#2
CMPNE R0,#1
BLNE sortbufs
STR R0,[R7,#con.lastbuf]
;R1-R2 available

;R3=addr
;R4=len
;R5=acc
;R6=replen
;R8=pitch
;R9=status

CMP R3,#0
BLEQ adrzero
TST R9,#status_gated
BNE gatedoff
;R0 now available
LDR R1,[R7,#con.volume]
AND R1,R1,#&FF00
LDR R2,[R7,#con.logampadr]
LDRB R2,[R2,R1,LSR #8]
RSB R2,R2,#&FF
BIC R2,R2,#1
CMP R6,#2
LDRGT R4,[R7,#con.repofs];if repeat, let our sample length
ADDGT R4,R4,R6           ;be the repeat trigger point
.nofillrep
SUB R1,R10,R12
CMP R11,#2
MOVEQ R1,R1,LSR #1
CMP R11,#4
MOVEQ R1,R1,LSR #2
CMP R11,#8
MOVEQ R1,R1,LSR #3
MOV R0,R8,LSR #16
MUL R0,R1,R0
;R1 is the increment the accumulator will have at the end of the buffer bp 8
ADD R0,R0,R5,LSR #4;add to the accumulator bp 8
CMP R0,R4,LSL #8   ;compare bp 8
BGE slowfill

.fastfill
CMP R2,#0
BEQ flashfill
LDR R0,[R7,#con.fastbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.fastbufs]    ;**
CMP R8,#&01000000
BEQ fixedfastfill
CMP R8,#&00800000
BEQ halffastfill

.fastloop
#rept 16
LDRB R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #12
SUBS R0,R0,R2
MOVMI R0,#0
STRB R0,[R12],R11
#endr
CMP R12,R10
BLT fastloop
B endloop

.flashfill
LDR R0,[R7,#con.flashbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.flashbufs]    ;**
CMP R8,#&01000000
BEQ fixedflashfill
CMP R8,#&00800000
BEQ halfflashfill
.flashloop
#rept 16
LDRB R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #12
STRB R0,[R12],R11
#endr
CMP R12,R10
BLT flashloop
B endloop

.fixedflashfill
LDR R0,[R7,#con.fixedbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.fixedbufs]    ;**
BIC R5,R5,#3<<12
.fixedflashloop
#rept 4
LDR R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #10
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
#endr
CMP R12,R10
BLT fixedflashloop
B endloop

.halfflashfill
LDR R0,[R7,#con.fixedbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.fixedbufs]    ;**
BIC R5,R5,#3<<12
.halfflashloop
#rept 2
LDR R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #9
STRB R0,[R12],R11
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
STRB R0,[R12],R11
MOV R0,R0,LSR #8
STRB R0,[R12],R11
STRB R0,[R12],R11
#endr
CMP R12,R10
BLT halfflashloop
B endloop

.fixedfastfill
LDR R0,[R7,#con.fixedbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.fixedbufs]    ;**
BIC R5,R5,#3<<12
.fixedfastloop
#rept 4
LDR R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #10
AND R1,R0,#&FF
RSBS R1,R2,R1
MOVMI R1,#0
STRB R1,[R12],R11
AND R1,R0,#&FF<<8
RSBS R1,R2,R1,LSR #8
MOVMI R1,#0
STRB R1,[R12],R11
AND R1,R0,#&FF<<16
RSBS R1,R2,R1,LSR #16
MOVMI R1,#0
STRB R1,[R12],R11
AND R1,R0,#&FF<<24
RSBS R1,R2,R1,LSR #24
MOVMI R1,#0
STRB R1,[R12],R11
#endr
CMP R12,R10
BLT fixedfastloop
B endloop

.halffastfill
LDR R0,[R7,#con.fixedbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.fixedbufs]    ;**
BIC R5,R5,#3<<12
.halffastloop
#rept 2
LDR R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #9
AND R1,R0,#&FF
RSBS R1,R2,R1
MOVMI R1,#0
STRB R1,[R12],R11
STRB R1,[R12],R11
AND R1,R0,#&FF<<8
RSBS R1,R2,R1,LSR #8
MOVMI R1,#0
STRB R1,[R12],R11
STRB R1,[R12],R11
AND R1,R0,#&FF<<16
RSBS R1,R2,R1,LSR #16
MOVMI R1,#0
STRB R1,[R12],R11
STRB R1,[R12],R11
AND R1,R0,#&FF<<24
RSBS R1,R2,R1,LSR #24
MOVMI R1,#0
STRB R1,[R12],R11
STRB R1,[R12],R11
#endr
CMP R12,R10
BLT halffastloop
B endloop


.slowfill
LDR R0,[R7,#con.slowbufs]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.slowbufs]    ;**
CMP R6,#2
BGT repeatfill

.slowloop
#rept 4
LDRB R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #12
SUBS R0,R0,R2
MOVMI R0,#0
STRB R0,[R12],R11
CMP R5,R4,LSL #12
BGE endloop
#endr
CMP R12,R10
BLT slowloop
B endloop

.repeatfill
.repeatloop
#rept 4
LDRB R0,[R3,R5,LSR #12]
ADD R5,R5,R8,LSR #12
SUBS R0,R0,R2
MOVMI R0,#0
STRB R0,[R12],R11
CMP R5,R4,LSL #12
SUBGE R5,R5,R6,LSL #12
#endr
CMP R12,R10
BLT repeatloop

.endloop
LDR R9,[R7,#con.status]
TST R9,#status_safe
BEQ safeins
STR R5,[R7,#con.acc]
CMP R5,R4,LSL #12
BGE sampleend

.sampleendins
.fillend
.safeins
LDMFD R13!,{R14}
MOV R0,PC
ORR R0,R0,#2
BIC R0,R0,#1
TEQP R0,#0  ;switch to IRQ
MOV R0,#8
LDMFD R13!,{PC}


.sampleend
CMP R6,#2
BGT sampleendins
BL fineflush
BL samplekill
B fillend


.adrzero
LDR R9,[R7,#con.status]
ORR R9,R9,#status_gated
STR R9,[R7,#con.status]
MOV PC,R14


.samplekill
LDR R9,[R7,#con.status]
TST R9,#status_safe
ORRNE R9,R9,#status_gated
STRNE R9,[R7,#con.status]
MOV PC,R14

.gatedoff

TST R9,R0,LSL #status_qshift
BNE fillend
BL flush
LDR R1,[R7,#con.lastbuf]
ORR R9,R9,R1,LSL #status_qshift
STR R9,[R7,#con.status]
B fillend

.fineflush
MOV R0,#0
.fineflushloop
#rept 4
CMP R12,R10
STRLTB R0,[R12],R11
#endr
BLT fineflushloop
MOV PC,R14

.flush
LDR R0,[R7,#con.flushes]    ;**
ADD R0,R0,#1             ;**
STR R0,[R7,#con.flushes]    ;**
MOV R0,#0
.flushloop
#rept 16
STRB R0,[R12],R11
#endr
CMP R12,R10
BLT flushloop
MOV PC,R14

.sortbufs
CMP R1,#0
CMPEQ R2,#0
BEQ firstbuf
CMP R2,#0
BEQ secondbuf
.newbufs
.firstbuf
STR R12,[R7,#con.buf1]
MOV R1,#0
STR R1,[R7,#con.buf2]
MOV R0,#1
MOV PC,R14
.secondbuf
CMP R1,R12
STRGT R12,[R7,#con.buf1]
STRGT R1,[R7,#con.buf2]
STRLT R12,[R7,#con.buf2]
MOVLT R0,#1
MOVGT R0,#2
MOV PC,R14


.gateoff
MOV R0,#0
.loop1
STRB R0,[R12],R11
STRB R0,[R12],R11
STRB R0,[R12],R11
STRB R0,[R12],R11
CMP R12,R10
BLT loop1
MOV R0,#2
LDMFD R13!,{PC}

.doslides
LDR R9,[R7,#con.status]
TST R9,#status_safe
BEQ slideins
TST R9,#status_volslide
BNE dovolslide
.volslideins
TST R9,#status_pitchslide
BNE dopitchslide
B slideins

.dovolslide
LDR R0,[R7,#con.volume]
LDR R1,[R7,#con.volslide]; vol target
LDR R2,[R7,#con.volrate]
SUB R3,R1,R0
CMP R2,#0
RSBLT R3,R3,#0
CMP R3,#0
BLT killvolslide
ADDS R0,R0,R2
MOVMI R0,#0
STR R0,[R7,#con.volume]
B volslideins
.killvolslide
STR R1,[R7,#con.volume]
LDR R9,[R7,#con.status]
BIC R9,R9,#status_volslide
STR R9,[R7,#con.status]
B volslideins

.dopitchslide
LDR R0,[R7,#con.pitch]
LDR R1,[R7,#con.pitchslide]
LDR R2,[R7,#con.pitchrate]
SUB R3,R1,R0
CMP R2,#0
RSBLT R3,R3,#0
CMP R3,#0
BLT killpitchslide
ADD R0,R0,R2
STR R0,[R7,#con.pitch]
B slideins
.killpitchslide
STR R1,[R7,#con.pitch]
LDR R9,[R7,#con.status]
BIC R9,R9,#status_pitchslide
STR R9,[R7,#con.status]
B slideins

.ratechange
STMFD R13!,{R0-R12,R14}
LDR R12,varstr
LDR R0,[R7,#con.laststate]
STR R0,[R7,#con.prevstate]
STR R8,[R7,#con.laststate]
LDR R0,[R7,#con.states] ;***
ADD R0,R0,#1            ;***
STR R0,[R7,#con.states] ;***
AND R0,R8,#7<<24
MOV R0,R0,LSR #24
LDR R9,[R12,#v.oldchan]
CMP R0,R9
STR R0,[R12,#v.oldchan]
BLNE reflush

LDR R9,[R12,#v.newrate]
AND R8,R8,#&FF0000
MOV R8,R8,LSR #16
STR R8,[R12,#v.newrate]

CMP R8,R9
LDMEQFD R13!,{R0-R12,PC}
MOV R11,#0

.ratechangeloop
getconaddr R11,R10
LDR R9,[R10,#con.samprate]
CMP R8,R9
BEQ ratechskip
LDR R0,[R10,#con.ratechange] ;***
ADD R0,R0,#1                 ;***
STR R0,[R10,#con.ratechange] ;***
LDR R0,[R10,#con.pitch]
MOV R0,R0,LSR #8
MUL R1,R8,R0
BL div
MOV R0,R0,LSL #8
STR R0,[R10,#con.pitch]
LDR R0,[R10,#con.pitchslide]
MOV R0,R0,LSR #8
MUL R1,R8,R0
BL div
MOV R0,R0,LSL #8
STR R0,[R10,#con.pitchslide]
LDR R0,[R10,#con.pitchrate]
MOV R0,R0,LSR #8
MUL R1,R8,R0
BL div
MOV R0,R0,LSL #8
STR R0,[R10,#con.pitchrate]
STR R8,[R10,#con.samprate]
.ratechskip
ADD R11,R11,#1
CMP R11,#8
BLT ratechangeloop
LDR R0,[R12,#v.callbacks]
ADD R0,R0,#1
STR R0,[R12,#v.callbacks]
ADR R0,ratecallback
MOV R1,R12
SWI OS_AddCallBack
LDMFD R13!,{R0-R12,PC}

.div
MYDIV R0,R1,R9
MOV PC,R14

.ticker
STMFD R13!,{R0-R11,R14}
LDR R0,[R12,#v.timer]
ADD R0,R0,#1
STR R0,[R12,#v.timer]
MOV R11,#0
.tickerloop
getconaddr R11,R7
LDR R0,[R7,#con.status]
TST R0,#status_volslide+status_pitchslide
BNE doslides
.slideins
ADD R11,R11,#1
CMP R11,#8
BLT tickerloop
LDMFD R13!,{R0-R11,PC}

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

.nosaveerr
MOV R1,R10
ORR R14,R14,#1<<28
MOVS PC,R14

.nosamperr
ADR R0,nosamperrtext
B err
.nosamperrtext
DCD &809D06
DCB  "Stasis : No sample in that slot"
DCB 0
ALIGN

.attacherr
ADR R0,attacherrtext
B err
.attacherrtext
DCD &809D07
DCB  "Stasis : Voice attach/detach failure"
DCB 0
ALIGN
.noroomerr
ADR R0,noroomerrtext
B err
.noroomerrtext
DCD &809D08
DCB  "Stasis : No room in RMA"
DCB 0
ALIGN

.badswino
ADR R0,badswinotext
B err
.badswinotext
DCD &809D11
DCB  "Stasis : Unknown SWI"
DCB 0
ALIGN

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

.releaseerr
ADR R0,releaseerrtext
B err
.releaseerrtext
DCD &809D12
DCB "Stasis : Release of block of unknown type",0
ALIGN
.badsaveformaterr
.badformaterr
ADR R0,badsaveformaterrtext
B err
.badsaveformaterrtext
DCD &809D13
DCB "Stasis : Unknown sample format",0
ALIGN
.badalienerr
ADR R0,badalienerrtext
B err
.badalienerrtext
DCD &809D14
DCB "Stasis : Alien format handler guard word corrupt",0
ALIGN
.puterr
STMFD R13!,{R14}
write
DCB "Stasis : With reference to "
endwrite
MOV R1,R0
TST R1,#1<<1
ADRNE R0,putnameerr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<2
ADRNE R0,putlenerr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<3
ADRNE R0,putfinetuneerr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<4
ADRNE R0,putrepofserr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<5
ADRNE R0,putreplenerr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<6
ADRNE R0,putdataofserr
SWINE OS_Write0
SWINE 256+","
TST R1,#1<<7
ADRNE R0,putvolumeerr
SWINE OS_Write0
SWINE 256+","
SWI 256+8
SWI 256+";"
SWI OS_NewLine
LDMFD R13!,{R14}
ADR R0,puterrtext
B err
.puterrtext
DCD &809D15
DCB "Stasis : Cannot make requested alteration - sample format does not allow it",0
.putnameerr
DCB "name",0
.putlenerr
DCB "length",0
.putfinetuneerr
DCB "finetune",0
.putrepofserr
DCB "repeat offset",0
.putreplenerr
DCB "repeat length",0
.putdataofserr
DCB "sample data address",0
.putvolumeerr
DCB "volume",0

ALIGN

macro getslotaddr m0,m1 {
AND m1,m0,#entries-1
ADD m1,R12,m1,LSL #s_shift
ADD m1,m1,#v.slottab
}

macro getconaddr m0,m1 {
AND m1,m0,#7
ADD m1,R12,m1,LSL #stac_shift
ADD m1,m1,#v.contab
}

macro limit m0 {
AND m0,m0,#entries-1
}

macro write {
SWI OS_WriteS
}

macro endwrite {
DCB 0
ALIGN
}