12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326 |
- ;----------------------------------------------------------------------------------------
- ;pro tracker (mod) player for the spc700 (c)d4s in 2005
- ;----------------------------------------------------------------------------------------
- .MEMORYMAP ; Tell WLA that the SPC has RAM at locations ;$0000-$ffff in every bank
- SLOTSIZE $10000 ; and that this area is $10000 bytes in size.
- DEFAULTSLOT 0 ; There is only a single slot in SNES, other consoles
- SLOT 0 $0000 ; may have more slots per bank.
- .ENDME
- .ROMBANKSIZE $10000 ; Every ROM bank is 64 KBytes in size
- .ROMBANKS 1
- ;----------------------------------------------------------------------------------------
- .BANK 0 SLOT 0
- .define SpcCmdUploadSong $f1 ;indicates that a song is to be uploaded
- .define SpcCmdUploadSongT1 $f2 ;indicates that data for transfer1 is on apu ports
- .define SpcCmdUploadSongT2 $f3 ;indicates that data for transfer2 is on apu ports
- .define SpcCmdUploadSongDone $f4 ;indicates that song upload is complete
- .define SpcCmdReceiveStream $f5 ;indicates that 65816 wants to stream brr data to spc
- .define SpcCmdSubmitStreamNumber $f7 ;indicates that 65816 wants to stream brr data to spc
- .define SpcCmdReceiveStreamComplete $f6 ;spc wants to end stream transmission
- .define SpcCmdUploadSamplePack $f8 ;indicates that a sample pack is to be uploaded. the rest of the commands are taken from normal song upload
- .define SpcCmdUploadSamplePackDone $f9 ;indicates that sample pack upload is complete
- .define SpcCmdPlaySoundEffect $fa ;play a sound effect
- .define SpcCmdStopSong $fb
- .define SpcCmdSetSongSpeed $fc ;set timer speed of mod playback routine
- .define SpcCmdSetSongChMask $fd ;song channel mask
- .define SpcCmdReportType $fe ;type of data spc should respond with
- .define SpcCmdSetSongVolume $ff
- .define SpcStreamLatency 7 ;number of frames to load before actually playing sample
- .define SpcStreamSampleNumber 33 ;number of dsp sample to use as streamer
- .define StreamerTimer0 $00 ;how long to wait before downloading next frame
- .define ChannelArray $0
- .define ExtSample $20 ;this sample is used for set sample offset effect
- .define Stack $ff
- .define ApuCodeBaseAdress $300
- .define SampleSource $0200 ;$ff bytes long
- .define StreamBuffer $fb80 ;480 bytes long
- .define HighestPortaPeriod $0071
- .define LowestPortaPeriod $0358
- .define EchoStartAdress $f8
- .define EchoDelay $01
- .define SongEffectsUploaded $ef ;flags that indicate whether a song or sample pack have already been uploaded.bit0=song bit1=sample pack. wla is too stupid to recognize a variable here, so we have to use a static one.
- ;variables:
- ;.........................................................
- .enum $60
- WaitCounter dw
- CurrentPatternPointerLo db
- CurrentPatternPointerHi db
- InitPatternPointerLo db
- InitPatternPointerHi db
- PortamentoDownLimitLo db
- PortamentoDownLimitHi db
- PortamentoUpLimitLo db
- PortamentoUpLimitHi db
- CurrentChDataLo db
- CurrentChDataHi db
- TempBuffer1 db
- TempBuffer2 db
- TempBuffer3 db
- TempBuffer4 db
- TempBuffer5 db
- TempBuffer6 db
- TempBuffer7 db
- TempBuffer8 db
- TempBuffer9 db
- TempBuffer10 db
- TempVol db
- KeyOn db
- CurrentChannel db
- CurrentVolume db
- PitchBufferLo db
- PitchBufferHi db
- CurrentPatternNumber db
- PortamentoSpeedMask db
- NotUsedVariable db
- CurrentPeriodPointer db
- CurrentPeriodPointerHi db
- PeriodTablePointerLo db
- PeriodTablePointerHi db
- SpcDataPointerLo db
- SpcDataPointerHi db
- ModFilePointerLo db
- ModFilePointerHi db
- ModFilePointer2Lo db
- ModFilePointer2Hi db
- ;added variables
- ScratchPad1 db
- ScratchPad2 db
- ScratchPad3 db
- PeriodBufferLo db
- PeriodBufferHi db
- NumberOfPatterns db
- PatternSpeed db
- NextRowChFadeOuts db ;lower nibble bits0-4:channels to fade out for next row
- NextRowChFadeOutTime db ;patternspeed-2
- PortamentoLUTLo db ;table for portamento up/down
- PortamentoLUTHi db ;table for portamento up/down
- TonePortamentoLUTLo db ;table for portamento up/down
- TonePortamentoLUTHi db ;table for portamento up/down
- CurrentRowPointerLo db
- CurrentRowPointerHi db
- CurrentLoopPointerLo db
- CurrentLoopPointerHi db
- LoopCounter db
- PatternBreakFlag db ;if bit0 is set, break to next pattern
- ;main volume section:
- MainVolL db
- MainVolR db
- EchoVolL db
- EchoVolR db
- ChannelEnable db
- ChannelEchoEnable db
- PitchTablePointerLo db
- PitchTablePointerHi db
- Channel1Array dw
- Channel2Array dw
- Channel3Array dw
- Channel4Array dw
- ;apu streaming stuff
- StreamState db ;variable for streaming state machine
- StreamCurrentBuffer db ;indicates currently active stream buffer out of 8
- StreamVolume db
- ActiveSoundEffectCh db ;0-3
- ModPlayerTimer0 db
- SongChannelMask db ;mask variable for 4 song channels. default $0f
- SpcReportType db
- ModTimecode dw ;timecode for mod currently playing. reset after song upload
- SpecialReportCmd db
- SoundEffectFlipFlag db
- TickSampleStart db ;channel mask to start samples on the next tick. used for delay and retrigger
- MusicVol1 db ;mod channel 0,2 volume
- MusicVol2 db ;mod channel 1,3 volume
- .ende
- ;channel variables
- .enum $00
- ch_instrument db ;00
- ch_note db ;01
- ch_effect db ;02
- ch_effect_data db ;03
- ch_finetune db ;04
- ch_current_volume db ;05
- ch_current_pitch_lo db ;06 this gets updated on portamento etc
- ch_current_pitch_hi db ;07 (not directly used in sourcecode)
- ch_target_pitch_lo db ;08 (not used at all in sourcecode) target pitch for tone portamento
- ch_target_pitch_hi db ;09 (not used at all in sourcecode)
- ch_tone_portamento_speed db ;0a
- ch_portamento_slide_dir db ;0b bit0 sets up/down
- ch_vibrato_command_buffer db ;0c this is a buffer for depth and speed when using vibrato continue
- ch_vibrato_position db ;0d
- ch_vibrato_tremolo_waveform db ;0e 0=sine, 1=ramp down, 2=square
- ch_tremolo_position db ;0f
- ch_tremolo_command_buffer db ;10
- ch_arpeggio_note_buffer db ;11
- ch_tick_delay db ;12
- ch_amiga_period_lo db ;13 this is the current amiga period
- ch_amiga_period_hi db ;14 (not directly used in sourcecode)
- ch_current_amiga_period_lo db ;15 this is the tone portamento target amiga period
- ch_current_amiga_period_hi db ;16 (not directly used in sourcecode)
- ;next must be the last entry in this array:
- ch_current_channelmask db ;last byte in array and mask for channel
- .ende
- ;.........................................................
- .ORGA (ApuCodeBaseAdress-2) ;$2FC
- .DW ApuCodeBaseAdress ;spcram copy offset
- BootInit:
- clrp
- mov $f1,#$f0
- mov a,#$ff
- mov !$fff0,a
- mov x,#Stack ;set stack pointer (old: $cf)
- mov sp,x
- mov a,#$00
- mov x,a
- jmp !ClearVariables
- CopyRight:
- .db "matt@dforce3000.de"
- CopyRightEnd:
- ClearVariables:
- mov (x)+,a
- cmp x,#$f0
- bne ClearVariables
- mov MainVolL,#$7f
- mov MainVolR,#$7f
- mov EchoVolL,#$00
- mov EchoVolR,#$00
- mov ChannelEnable,#$0f
- mov ChannelEchoEnable,#$0f
- mov SpcReportType,#0 ;reset report type to void
- mov MusicVol1,#$7f ;init volume. narrow stereo, a little bit stereo separation
- mov MusicVol2,#$7f
-
- mov SpcDataPointerLo,#(ModFile & $00ff) ;setup mod pointer
- mov SpcDataPointerHi,#(ModFile >> 8)
- call !ClearAllChannelArray
- call !SetupDspRegsAndTimers ;reset dsp regs first.
- call !InitVariables ;set up pointers to first pattern
- call !UpdateVolEchoVariablesOnly
-
- MainLoop:
- mov a,$fd ;clear counter0
- MainLoop1:
- mov a,$fd ;wait for counter 0 to become zero
- beq MainLoop1 ;takes roughly 44 scanlines total
- call !MainWaitLoop
- call !SendReportData
- mov a,$f4 ;check if command present on port0
- and a,#$f0
- cmp a,#$f0
- bne MainLoop ;return to mainloop if there isn't
- mov a,$f4 ;get command
- and a,#$0f
- asl a
- mov x,a ;pointer into jump table
- jmp [!CommandJumpTable+x]
-
- CommandJumpTable:
- .dw CommandVoid ;0
- .dw ReceiveSong
- .dw CommandVoid
- .dw CommandVoid
- .dw CommandVoid
- .dw ReceiveStream ;5
- .dw CommandVoid
- .dw CommandVoid
- .dw ReceiveSamplePack
- .dw CommandVoid
- .dw PlaySoundEffect ;10
- .dw StopSongStream
- .dw SetSongSpeed
- .dw SetSongChannelMask
- .dw SetReportType
- .dw SetSongVolume
- ReceiveSong:
- ;timers must be reset before receiving a song, else we can't wait properly for the echo buffer to initialize
- call !ReceiveSongHandler
- call !ClearAllChannelArray
- call !SetupSamples ;set up sample offsets
- call !SetupDspRegsAndTimers ;reset dsp regs first.
- call !InitVariables ;set up pointers to first pattern
- call !UpdateVolEchoVariablesOnly
- ;return to mainloop:
- bra MainLoop
- UpdateVolEcho:
- call !UpdateVolEchoHandler
- bra MainLoop
- ResetHandler:
- ;clear apu ports:
- mov y,#$00
- mov $f4,y
- mov $f5,y
- mov $f6,y
- mov $f7,y
- ;clear dsp regs:
- mov a,#$6c
- mov y,#$e0 ;reset dsp, mute on, echo off
- movw $f2,ya
- mov a,#$0c
- movw $f2,ya
- mov a,#$1c
- movw $f2,ya
- mov a,#$2c
- movw $f2,ya
- mov a,#$3c
- movw $f2,ya
- mov a,#$4c
- movw $f2,ya
- mov y,#$ff
- mov a,#$5c
- movw $f2,ya
- mov y,#$00
- mov a,#$0d
- movw $f2,ya
- mov a,#$2d
- movw $f2,ya
- mov a,#$3d
- movw $f2,ya
- mov a,#$4d
- movw $f2,ya
- mov a,#$5d
- movw $f2,ya
- mov a,#$6d
- movw $f2,ya
- mov a,#$7d
- movw $f2,ya
- mov $f1,#$f0
- ;jump to ipl rom:
- jmp !$ffc0
- jmp !$ffc0
- MainWaitLoop:
- bbs $ef.0,MainWaitLoopSongPresent ;only process song if song has been uploaded before
- ret
-
- MainWaitLoopSongPresent:
- inc WaitCounter
- InnerWaitLoop:
- cmp WaitCounter,PatternSpeed ;old #$04 incremet WaitCounter until 4, selfmodying code changes the default speed(command setspeed0x0f) by writing to the second operand
- bne UpdateTickBasedEffectsOnly
- mov WaitCounter,#$00
- mov y,NextRowChFadeOuts
- mov a,#$5c
- movw $f2,ya
- mov a,$fe ;clear 4bit counter
- mov y,#2
- KofWaitLoop:
- mov a,$fe ;wait for 2mS
- beq KofWaitLoop
- ;**************************************************
- dbnz y,KofWaitLoop
- call !ProcessNextRow
- call !PreTestRow
- ret
- UpdateTickBasedEffectsOnly:
- movw ya,Channel1Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$00
- call !CheckForTickBasedEffects
- movw ya,Channel2Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$10
- call !CheckForTickBasedEffects
- movw ya,Channel3Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$20
- call !CheckForTickBasedEffects
- movw ya,Channel4Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$30
- call !CheckForTickBasedEffects
- mov a,TickSampleStart
- beq UpdateTickBasedEffectsOnlyNoRetrigger
- mov $f2,#$4c
- mov $f3,a ;retrigger recently started samples
-
- mov TickSampleStart,#0
- UpdateTickBasedEffectsOnlyNoRetrigger:
- ret
- ProcessNextRow:
- movw ya,CurrentPatternPointerLo ;mark beginning of current row
- movw CurrentRowPointerLo,ya
- incw ModTimecode
- mov KeyOn,#$00 ;clear key on
- movw ya,Channel1Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$00
- call !GetDataFromPattern
- call !SetVolume
- movw ya,Channel2Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$10
- call !GetDataFromPattern
- call !SetVolume
- movw ya,Channel3Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$20
- call !GetDataFromPattern
- call !SetVolume
- movw ya,Channel4Array
- movw CurrentChDataLo,ya
- mov CurrentChannel,#$30
- call !GetDataFromPattern
- call !SetVolume
-
- call !KeyOnKeyOff
- call !PatternLoopJumper
- jmp !GetDataFromPatternCheckPatternPosition
- GetDataFromPatternEntryIsVoid:
- incw CurrentPatternPointerLo
- mov y,#ch_instrument
- mov a,#$ff ;store $ff in all 4 channel input buffers
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- ret
- GetDataFromPattern:
- mov y,#ch_instrument
- mov a,[CurrentChDataLo]+y ;get last rows instrument, pitch and effects
- mov TempBuffer1,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer5,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer6,a
- or TempBuffer1,TempBuffer2
- or TempBuffer1,TempBuffer5
- or TempBuffer1,TempBuffer6 ;check if a note was present
- mov a,TempBuffer1
- bne GetDataFromPatternEntryContainsNewData
- call !GetPitchFromBufferAndSet
- GetDataFromPatternEntryContainsNewData:
- mov y,#$00
- mov a,[CurrentPatternPointerLo]+y
- cmp a,#$ff ;compare if channel entry is $ff(skip)
- beq GetDataFromPatternEntryIsVoid
- ;there is a new note to trigger, copy data from pattern to current channel data buffer:
-
- mov [CurrentChDataLo]+y,a ;copy instrument
- inc y
- mov a,[CurrentPatternPointerLo]+y ;copy note
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,[CurrentPatternPointerLo]+y ;copy effect
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,[CurrentPatternPointerLo]+y ;copy effect data
- mov [CurrentChDataLo]+y,a
- incw CurrentPatternPointerLo
- incw CurrentPatternPointerLo
- incw CurrentPatternPointerLo
- incw CurrentPatternPointerLo
- mov y,#ch_effect
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov TempBuffer1,a
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$f0
- or a,TempBuffer1
- cmp a,#$de ;delay sample effect present? if yes, don't trigger sample
- beq DontSetNewSample
-
- call !SetNewSample
-
- DontSetNewSample:
- ret
-
- SetNewSample:
- mov y,#ch_instrument ;a non-present instrument is indicated by $00
- mov a,[CurrentChDataLo]+y
- beq GetDataFromPatternInstrumentIsVoid
- ;trigger new instrument, fetch sample data for current instrument
- dec a ;multiply instrument number with 8 to get pointer into sample array
- mov y,#$08
- mul ya
- addw ya,ModFilePointer2Lo
- movw TempBuffer1,ya ;tempbuffer1 is now pointer to current sample entry
- mov y,#$02 ;get sample finetune
- mov a,[TempBuffer1]+y
- mov y,#ch_finetune ;save to current channel finetune
- mov [CurrentChDataLo]+y,a
- mov y,#$03 ;get sample volume
- mov a,[TempBuffer1]+y
- mov CurrentVolume,a ;save to current volume and current channel volume
- mov y,#ch_current_volume
- mov [CurrentChDataLo]+y,a
- GetDataFromPatternInstrumentIsVoid:
- mov y,#ch_note
- mov a,[CurrentChDataLo]+y
- cmp a,#$ff ;a non-present note is indicated by $ff
- beq GetDataFromPatternPeriodIsVoid
- mov y,#ch_effect ;check if effect command is $ff
- mov a,[CurrentChDataLo]+y
- cmp a,#$ff
- beq GetDataFromPatternCalculateNewPeriod ;if it is, directly calculate new period (why?)
- and a,#$0f ;merge effect command and data to test for finetune command
- mov TempBuffer1,a
- inc y
- mov a,[CurrentChDataLo]+y
- and a,#$f0
- or a,TempBuffer1
- xcn a
- cmp a,#$e5 ;finetune
- beq FinetuneStep
- mov y,#ch_effect
- mov a,[CurrentChDataLo]+y ;get current effect
- and a,#$0f
- cmp a,#$03 ;check if effect is tone portamento
- beq GetDataFromPatternPortamento
- cmp a,#$05 ;check if effect is tone portamento and volslide
- beq GetDataFromPatternPortamento
- bra GetDataFromPatternCalculateNewPeriod
- FinetuneStep:
- call !Finetune
- bra GetDataFromPatternCalculateNewPeriod
- GetDataFromPatternPortamento:
- call !TonePortamento
-
- jmp !GetDataFromPatternCheckEffects
- GetDataFromPatternPeriodIsVoid:
- jmp !GetDataFromPatternCheckEffects
- GetDataFromPatternCalculateNewPeriod:
- mov y,#ch_note
- mov a,[CurrentChDataLo]+y
- mov y,#ch_arpeggio_note_buffer
- mov [CurrentChDataLo]+y,a
- mov y,a ;put period in y
- push y
- mov y,#ch_finetune
- mov a,[CurrentChDataLo]+y ;calculate finetune
- mov y,#$48
- mul ya
- addw ya,PeriodTablePointerLo
- movw CurrentPeriodPointer,ya
-
- pop y ;get corresponding value in 14bit period table
- mov a,[CurrentPeriodPointer]+y ;get current period
- mov TempBuffer1,a
- mov PeriodBufferLo,a
- inc y
- mov a,[CurrentPeriodPointer]+y
- mov TempBuffer2,a
- mov PeriodBufferHi,a
- ;fetch pitch from pitch table. input: period
- mov y,TempBuffer2
- mov a,TempBuffer1
- addw ya,TempBuffer1 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw TempBuffer1,ya ;move adress to pointer
- mov y,#0
- mov a,[TempBuffer1]+y ;get lo pitch byte
- mov PitchBufferLo,a ;save new pitch
- inc y
- mov a,[TempBuffer1]+y
- mov PitchBufferHi,a
- ;fetch pitch end
-
- mov y,#ch_current_pitch_lo ;save new pitch to array
- mov a,PitchBufferLo
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,PitchBufferHi
- mov [CurrentChDataLo]+y,a
-
- mov y,#ch_amiga_period_lo ;save new period to array
- mov a,PeriodBufferLo
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,PeriodBufferHi
- mov [CurrentChDataLo]+y,a
- mov y,#ch_vibrato_tremolo_waveform ;check vibrato waveform
- mov a,[CurrentChDataLo]+y
- cmp a,#$04
- bne VibratoRetrigger
- mov y,#ch_vibrato_position ;reset vibrato position
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- VibratoRetrigger:
- mov y,#ch_vibrato_tremolo_waveform
- mov a,[CurrentChDataLo]+y
- cmp a,#$40
- bne VibratoNoWaveformReset
- mov y,#ch_tremolo_position
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- VibratoNoWaveformReset:
- mov a,CurrentChannel
- or a,#$02
- mov x,a
- mov y,#ch_current_pitch_lo
- mov a,[CurrentChDataLo]+y
- mov $f2,x ;set pitch height(hi), dsp reg $x2
- mov $f3,a
- inc y
- inc x
- mov a,[CurrentChDataLo]+y
-
- mov $f2,x ;set pitch height(lo), dsp reg $x3
- mov $f3,a
- inc x
-
- mov y,#ch_instrument ;set source sample number
- mov a,[CurrentChDataLo]+y
- beq DontUpdateSourceSampleNumber
- mov $f2,x
- mov $f3,a
- inc x
- mov $f2,x ;disable adsr, enable gain
- mov $f3,#$00 ;old #$0c
- inc x
- mov $f2,x ;clear adsr2
- mov $f3,#$00
- inc x
- inc x
- mov y,#ch_current_channelmask
- mov a,[CurrentChDataLo]+y ;trigger note
- or a,KeyOn ;set note in key on var
- mov KeyOn,a
- DontUpdateSourceSampleNumber:
- jmp !GetDataFromPatternCheckEffects
- GetPitchFromBufferAndSet:
- mov a,CurrentChannel
- or a,#$02
- mov x,a
- mov y,#ch_current_pitch_lo
- mov a,[CurrentChDataLo]+y
- mov $f2,x
- mov $f3,a
- inc x
- inc y
- mov a,[CurrentChDataLo]+y
- mov $f2,x
- mov $f3,a
- ret
- CheckForTickBasedEffects:
- ;check if note cutoff is due
- mov y,#ch_effect
- mov a,[CurrentChDataLo]+y
- cmp a,#$ff
- beq GetPitchFromBufferAndSet
- ;check for special effects:
- and a,#$0f
- asl a
- mov x,a ;use effect command as pointer into jump table
- jmp [!TickBasedEffectJumpTable+x]
-
- TickBasedEffectJumpTable:
- .dw TickBasedArpeggio
- .dw TickBasedPortamentoUp
- .dw TickBasedPortamentoDown
- .dw TickBasedTonePortamento
- .dw TickBasedVibrato
- .dw TickBasedVolslidePorta
- .dw VolslideVibrato
- .dw TickBasedTremolo
- .dw TickBasedVoid
- .dw TickBasedVoid
- .dw TickbasedVolslide
- .dw TickBasedVoid
- .dw TickBasedVoid
- .dw TickBasedVoid
- .dw TickBasedExEffects
- .dw TickBasedVoid
- TickBasedVoid:
- ret
-
- TickBasedExEffects:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get ex-effect subtype
- and a,#$f0
- lsr a
- lsr a
- lsr a
- mov x,a ;use effect command as pointer into jump table
- jmp [!TickBasedExEffectJumpTable+x]
- TickBasedExEffectJumpTable:
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExEffectNoteRetrigger
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- .dw TickBasedExEffectNoteCutOff
- .dw TickBasedExEffectNoteDelay
- .dw TickBasedExVoid
- .dw TickBasedExVoid
- TickBasedExVoid:
- ret
- ;check for special effects commands
- GetDataFromPatternCheckEffects:
- mov y,#ch_effect
- mov a,[CurrentChDataLo]+y
- cmp a,#$ff ;no effect present?
- beq GetPitchFromBufferAndSetLong
- and a,#$0f
- asl a
- mov x,a ;use effect command as pointer into jump table
- jmp [!NormalEffectJumpTable+x]
-
- NormalEffectJumpTable:
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw GetPitchFromBufferAndSet
- .dw SetSampleOffset
- .dw GetPitchFromBufferAndSet
- .dw PositionJump
- .dw EffectSetVolume
- .dw PatternBreak
- .dw GetDataFromPatternCheckExEffects
- .dw SetSpeed0x0F
- GetPitchFromBufferAndSetLong:
- jmp !GetPitchFromBufferAndSet
-
- ;these are the special $Ex effects
- GetDataFromPatternCheckExEffects:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$f0
- mov y,a ;save a
- xcn a
- asl a
- mov x,a ;pointer into jump table
- jmp [!ExEffectJumpTable+x]
-
- ExEffectJumpTable:
- .dw ExEffectSpecialReportCmd
- .dw FinePortamentoUp
- .dw FinePortamentoDown
- .dw ExEffectVoid
- .dw SetVibratoWaveform
- .dw Finetune
- .dw PatternLoop
- .dw ExEffectVoid
- .dw ExEffectVoid
- .dw EffectNoteRetrigger
- .dw FineVolSlideUp
- .dw FineVolSlideDown
- .dw EffectNoteCutOff
- .dw EffectNoteDelay
- .dw ExEffectVoid
- .dw ExEffectVoid
-
- ExEffectVoid:
- ret
-
- TickBasedArpeggio:
- mov y,#ch_finetune ;calculate finetune
- mov a,[CurrentChDataLo]+y
- mov y,#$48
- mul ya
- addw ya,PeriodTablePointerLo
- movw CurrentPeriodPointer,ya
-
- mov y,#ch_current_pitch_lo
- mov a,[CurrentChDataLo]+y ;save current pitch to buffer
- mov PitchBufferLo,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov PitchBufferHi,a
- jmp !ArpeggioToneSelector
- TickBasedVolslidePorta:
- call !TonePortamentoContinue
- jmp !TickbasedVolslide
- VolslideVibrato:
- call !ContinueVibrato
- jmp !TickbasedVolslide
- ArpeggioToneSelector:
- mov a,WaitCounter ;get waitcounter
- mov y,#0 ;clear y
- mov x,#3 ;put 3 into x
- div ya,x ;divide waitcounter by three
-
- mov TempBuffer1,y ;put remainder(can take values 0-2) into TempBuffer1
-
- cmp TempBuffer1,#$01
- beq ArpeggioTone1
- cmp TempBuffer1,#$02
- beq ArpeggioTone2
- cmp TempBuffer1,#$00
- beq ArpeggioTone3
-
-
- ret
- ArpeggioTone1:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- xcn a
- and a,#$0f
- bra ArpeggioCommit
- ArpeggioTone2:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- bra ArpeggioCommit
- ArpeggioTone3:
- mov y,#ch_current_pitch_lo ;use current tone as pitch, unchanged
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- bra ArpeggioSetPitch
- ArpeggioCommit:
- asl a
- mov TempBuffer1,a
- mov y,#ch_arpeggio_note_buffer
- mov a,[CurrentChDataLo]+y
- clrc
- adc a,TempBuffer1
- mov y,a
- mov a,[CurrentPeriodPointer]+y ;get current period
- mov ScratchPad1,a
- inc y
- mov a,[CurrentPeriodPointer]+y
- mov ScratchPad2,a
-
- mov y,ScratchPad2
- mov a,ScratchPad1
- addw ya,ScratchPad1 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw ScratchPad1,ya ;move adress to pointer
- mov y,#0
- mov a,[ScratchPad1]+y ;get lo pitch byte
- mov TempBuffer1,a ;save new pitch
- inc y
- mov a,[ScratchPad1]+y
- mov TempBuffer2,a
- ArpeggioSetPitch:
- mov a,CurrentChannel
- or a,#$02
- mov $f2,a
- mov $f3,TempBuffer1
- inc a
- mov $f2,a
- mov $f3,TempBuffer2
- ret
- FinePortamentoUp:
- cmp WaitCounter,#$00
- bne PortamentoExit
- mov PortamentoSpeedMask,#$0f ;portamento up, but only with lower nibble of effect value
- TickBasedPortamentoUp:
- mov a, #(HighestPortaPeriod & $00ff)
- mov y, #(HighestPortaPeriod >> 8)
- movw TempBuffer5,ya ;put highest slideable period into buffer
-
- mov y,#ch_amiga_period_lo ;get current period
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a ;and save it to temp buffer
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get current effect value
- and a,PortamentoSpeedMask ;and with mask depeding on normal or finetune portamento
- mov y,#$00 ;inverse clear y
- movw TempBuffer3,ya ;put ya into tempbuffer3
- movw ya,TempBuffer1 ;get current period
- subw ya,TempBuffer3 ;substract portamento speed
- cmpw ya,TempBuffer5 ;if negative, we've slided too high
- bpl PortaUpNoLimit
- movw ya,TempBuffer5 ;use limit value if we've slided too high
- PortaUpNoLimit:
- movw TempBuffer1,ya ;put new pitch to buffer
- mov y,#ch_amiga_period_lo ;save back current period
- mov a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
-
- mov y,TempBuffer2 ;get current period
- mov a,TempBuffer1
- addw ya,TempBuffer1 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw TempBuffer3,ya ;move adress to pointer
- mov y,#0
- mov a,[TempBuffer3]+y ;get lo pitch byte
- mov TempBuffer1,a ;save new pitch
- inc y
- mov a,[TempBuffer3]+y
- mov TempBuffer2,a
-
-
- mov y,#ch_current_pitch_lo ;save new pitch to current pitch and update pitch register
- mov a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
- mov a,CurrentChannel
- or a,#$02
- mov $f2,a
- mov $f3,TempBuffer1
- inc a
- mov $f2,a
- mov $f3,TempBuffer2
- PortamentoExit:
- mov PortamentoSpeedMask,#$ff
- ret
- FinePortamentoDown:
- cmp WaitCounter,#$00
- bne PortamentoExit
- mov PortamentoSpeedMask,#$0f
- TickBasedPortamentoDown:
- mov a, #(LowestPortaPeriod & $00ff)
- mov y, #(LowestPortaPeriod >> 8)
- movw TempBuffer5,ya ;put lowest slideable period into buffer
-
- mov y,#ch_amiga_period_lo ;get current period
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a ;and save it to temp buffer
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get current effect value
- and a,PortamentoSpeedMask ;and with mask depeding on normal or finetune portamento
- mov y,#$00 ;inverse clear y
- addw ya,TempBuffer1 ;add portamento speed
- cmpw ya,TempBuffer5 ;if positive, we've slided too high
- bmi PortaDownNoLimit
- movw ya,TempBuffer5 ;use limit value if we've slided too high
- PortaDownNoLimit:
- movw TempBuffer1,ya ;put new pitch to buffer
- mov y,#ch_amiga_period_lo ;save back current period
- mov a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
-
- mov y,TempBuffer2 ;get current period
- mov a,TempBuffer1
- addw ya,TempBuffer1 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw TempBuffer3,ya ;move adress to pointer
- mov y,#0
- mov a,[TempBuffer3]+y ;get lo pitch byte
- mov TempBuffer1,a ;save new pitch
- inc y
- mov a,[TempBuffer3]+y
- mov TempBuffer2,a
-
-
-
- mov y,#ch_current_pitch_lo
- mov a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
- mov a,CurrentChannel
- or a,#$02
- mov $f2,a
- mov $f3,TempBuffer1
- inc a
- mov $f2,a
- mov $f3,TempBuffer2
- ret
- TonePortamento:
- mov y,#ch_note ;get note
- mov a,[CurrentChDataLo]+y
- mov y,a ;put period in y
- push y
- mov y,#ch_finetune
- mov a,[CurrentChDataLo]+y ;calculate finetune
- mov y,#$48
- mul ya
- addw ya,PeriodTablePointerLo
- movw CurrentPeriodPointer,ya
-
- pop y ;get corresponding value in 14bit period table
- mov a,[CurrentPeriodPointer]+y ;get current period
- mov PeriodBufferLo,a
- inc y
- mov a,[CurrentPeriodPointer]+y
- mov PeriodBufferHi,a
- mov y,#ch_current_amiga_period_lo ;this is our target period to slide to
- mov a,PeriodBufferLo
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,PeriodBufferHi
- mov [CurrentChDataLo]+y,a
- mov y,#ch_amiga_period_lo ;get current actual period
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
-
-
- mov y,#ch_portamento_slide_dir
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- movw ya,PeriodBufferLo
- cmpw ya,TempBuffer1
- beq TonePortamentoEqual ;check if already at target period
- bmi TonePortamentoExit ;if plus, the target period is higher(tone is lower) than the current period. slide value must be added in that case
- mov y,#ch_portamento_slide_dir ;invert sliding direction
- mov a,#$01
- mov [CurrentChDataLo]+y,a
- TonePortamentoExit:
- ret
- TonePortamentoEqual:
- mov y,#ch_current_amiga_period_lo
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- ret
- TickBasedTonePortamento:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get effect data (tone portamento speed value)
- beq TonePortamentoContinue ;if zero, continue and dont alter period
- mov y,#ch_tone_portamento_speed ;save speed
- mov [CurrentChDataLo]+y,a
- mov y,#ch_effect_data ;clear effect data
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- TonePortamentoContinue:
- mov y,#ch_current_amiga_period_lo ;get target period, put into tempbuffer1
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
-
-
- movw ya,TempBuffer1 ;exit if target period is zero (set before if target period has already been reached
- beq TonePortamentoExit
- mov y,#ch_tone_portamento_speed
- mov a,[CurrentChDataLo]+y ;get current speed value (tone portamento speed)
- mov y,#$00 ;clear y
- movw TempBuffer3,ya ;put slide amount into tempbuffer3
-
- mov y,#ch_portamento_slide_dir
- mov a,[CurrentChDataLo]+y
- bne TonePortaSlideDown ;check whether to slide up or down
- mov y,#ch_amiga_period_lo ;get current period, put into TempBuffer5
- mov a,[CurrentChDataLo]+y
- mov TempBuffer5,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer6,a
-
- movw ya,TempBuffer5 ;get current period
- subw ya,TempBuffer3 ;substract slidespeed
- cmpw ya,TempBuffer1 ;check for overflow
- bpl TonePortaSlideDone
- mov y,#ch_current_amiga_period_lo ;if overflow occured, clear tone porta target period
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- movw ya,TempBuffer1 ;and load target period instead
- bra TonePortaSlideDone
- TonePortaSlideDown:
- mov y,#ch_amiga_period_lo ;get current period, put into TempBuffer5
- mov a,[CurrentChDataLo]+y
- mov TempBuffer5,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov TempBuffer6,a
-
- movw ya,TempBuffer5 ;get current period
- addw ya,TempBuffer3 ;substract slidespeed
- cmpw ya,TempBuffer1 ;check for overflow
- bmi TonePortaSlideDone
- mov y,#ch_current_amiga_period_lo ;if overflow occured, clear tone porta target period
- mov a,#$00
- mov [CurrentChDataLo]+y,a
- inc y
- mov [CurrentChDataLo]+y,a
- movw ya,TempBuffer1 ;and load target period instead
- ; bra TonePortaSlideDone
- TonePortaSlideDone:
- movw TempBuffer1,ya ;save newly calculated period to current period buffer
- mov y,#ch_amiga_period_lo ;save to current period buffer
- mov a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
- ;fetch pitch from pitch table. input: period
- movw ya,TempBuffer1
- addw ya,TempBuffer1 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw TempBuffer1,ya ;move adress to pointer
- mov y,#0
- mov a,[TempBuffer1]+y ;get lo pitch byte
- mov TempBuffer5,a ;save new pitch
- inc y
- mov a,[TempBuffer1]+y
- mov TempBuffer6,a
- mov y,#ch_current_pitch_lo ;save to current pitch buffer
- mov a,TempBuffer5
- mov [CurrentChDataLo]+y,a
- inc y
- mov a,TempBuffer6
- mov [CurrentChDataLo]+y,a
- mov a,CurrentChannel
- or a,#$02
- mov $f2,a ;write to dsp
- mov $f3,TempBuffer5
- inc a
- mov $f2,a
- mov $f3,TempBuffer6
- ret
- TickBasedVibrato:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;if speed & depth are zero, continue vibrato without updating em.
- beq ContinueVibrato
- mov TempBuffer1,a
- mov y,#ch_vibrato_command_buffer ;get vibrato speed & depth buffer
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- and TempBuffer1,#$0f
- beq VibratoSkipDepthUpdate ;dont update depth if its zero
- and TempBuffer2,#$f0 ;update buffer
- or TempBuffer2,TempBuffer1
- VibratoSkipDepthUpdate:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get vibrato speed
- mov TempBuffer1,a
- and TempBuffer1,#$f0
- beq VibratoSkipSpeedUpdate ;dont upgrade speed if its zero
- and TempBuffer2,#$0f ;update buffer
- or TempBuffer2,TempBuffer1
- VibratoSkipSpeedUpdate:
- mov y,#ch_vibrato_command_buffer
- mov a,TempBuffer2 ;save back updated vibrato speed & depth
- mov [CurrentChDataLo]+y,a
- ContinueVibrato:
- mov y,#ch_vibrato_position
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a ;get current vibrato position, this is our pointer into the vibrato table
- lsr TempBuffer2
- lsr TempBuffer2
- and TempBuffer2,#$1f ;divide by 4 and limit
- mov y,#ch_vibrato_tremolo_waveform
- mov a,[CurrentChDataLo]+y
- and a,#$03 ;select current waveform
- mov TempBuffer3,a
- beq VibratoSelectSine
- asl TempBuffer2 ;multiply table pointer with 8
- asl TempBuffer2
- asl TempBuffer2
- cmp a,#$01
- beq VibratoSelectRampDown
- mov TempBuffer3,#$ff ;this is square vibrato
- bra VibratoSelectSet
- VibratoSelectRampDown:
- mov y,#ch_vibrato_position
- mov a,[CurrentChDataLo]+y ;get current vibrato position
- bpl VibratoSet
- mov TempBuffer3,#$ff
- setc
- sbc TempBuffer3,TempBuffer2
- bra VibratoSelectSet
- VibratoSet:
- mov TempBuffer3,TempBuffer2
- bra VibratoSelectSet
- VibratoSelectSine:
- mov x,TempBuffer2
- mov a,!VibratoTable+x ;access vibrato table
- mov TempBuffer3,a
- VibratoSelectSet:
- mov y,#ch_vibrato_command_buffer
- mov a,[CurrentChDataLo]+y
- and a,#$0f ;get current vibrato depth
- mov y,TempBuffer3
- mul ya ;multiply with selected vibrato position
- movw TempBuffer5,ya
- mov y,#$07
- VibratoDivLoop:
- lsr TempBuffer6 ;divide by 128
- ror TempBuffer5
- dbnz y,VibratoDivLoop
-
- mov y,#ch_amiga_period_lo ;get current period
- mov a,[CurrentChDataLo]+y
- mov PitchBufferLo,a
- inc y
- mov a,[CurrentChDataLo]+y
- mov PitchBufferHi,a
- mov y,#ch_vibrato_position
- mov a,[CurrentChDataLo]+y ;get vibrato position
- bmi VibratoPosNegative
- movw ya,PitchBufferLo
- subw ya,TempBuffer5
- bra VibratoUpdatePitch
- VibratoPosNegative:
- movw ya,PitchBufferLo
- addw ya,TempBuffer5
- VibratoUpdatePitch:
- movw PitchBufferLo,ya ;this is our new period
- addw ya,PitchBufferLo ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw ScratchPad1,ya ;move adress to pointer
- mov y,#0
- mov a,[ScratchPad1]+y ;get lo pitch byte
- mov PitchBufferLo,a ;save new pitch
- inc y
- mov a,[ScratchPad1]+y
- mov PitchBufferHi,a
-
- mov a,CurrentChannel ;write pitch to dsp
- or a,#$02
- mov $f2,a
- mov $f3,PitchBufferLo
- inc a
- mov $f2,a
- mov $f3,PitchBufferHi
- mov y,#ch_vibrato_command_buffer
- mov a,[CurrentChDataLo]+y
- lsr a
- lsr a
- and a,#$3c
- mov TempBuffer1,a
- mov y,#ch_vibrato_position
- mov a,[CurrentChDataLo]+y
- clrc
- adc a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- ret
- TickBasedTremolo:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- beq TremoloContinue
- mov TempBuffer1,a
- mov y,#ch_tremolo_command_buffer
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- and TempBuffer1,#$0f
- beq TremoloNoNewSpeed
- and TempBuffer2,#$f0
- or TempBuffer2,TempBuffer1
- TremoloNoNewSpeed:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a
- and TempBuffer1,#$f0
- beq TremoloNoNewDepth
- and TempBuffer2,#$0f
- or TempBuffer2,TempBuffer1
- TremoloNoNewDepth:
- mov y,#ch_tremolo_command_buffer
- mov a,TempBuffer2
- mov [CurrentChDataLo]+y,a
- TremoloContinue:
- mov y,#ch_tremolo_position
- mov a,[CurrentChDataLo]+y
- mov TempBuffer2,a
- lsr TempBuffer2
- lsr TempBuffer2
- and TempBuffer2,#$1f
- mov y,#ch_vibrato_tremolo_waveform
- mov a,[CurrentChDataLo]+y
- mov TempBuffer3,a
- lsr TempBuffer3
- lsr TempBuffer3
- lsr TempBuffer3
- lsr TempBuffer3
- and TempBuffer3,#$03
- beq TremolWavSel
- asl TempBuffer2
- asl TempBuffer2
- asl TempBuffer2
- asl TempBuffer2
- cmp TempBuffer3,#$01
- beq TremolWavSel2
- mov TempBuffer3,#$ff
- bra TremoloCommit
- TremolWavSel2:
- mov y,#ch_vibrato_position
- mov a,[CurrentChDataLo]+y
- bpl TremoloCommit2
- mov TempBuffer3,#$ff
- setc
- sbc TempBuffer3,TempBuffer2
- bra TremoloCommit
- TremoloCommit2:
- mov TempBuffer3,TempBuffer2
- bra TremoloCommit
- TremolWavSel:
- mov x,TempBuffer2
- mov a,!VibratoTable+x ;access table #2
- mov TempBuffer3,a
- TremoloCommit:
- mov y,#ch_tremolo_command_buffer
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov y,TempBuffer3
- mul ya
- movw TempBuffer5,ya
- mov y,#$06
- TremolDivLoop:
- lsr TempBuffer6
- ror TempBuffer5
- dbnz y,TremolDivLoop
-
- mov y,#ch_current_volume
- mov a,[CurrentChDataLo]+y
- mov TempBuffer1,a
- mov y,#ch_tremolo_position
- mov a,[CurrentChDataLo]+y
- bmi TremolPosNeg
- clrc
- adc TempBuffer1,TempBuffer5
- bra TremolPosPos
- TremolPosNeg:
- setc
- sbc TempBuffer1,TempBuffer5
- TremolPosPos:
- bpl TremolPosRes
- mov TempBuffer1,#$00
- TremolPosRes:
- cmp TempBuffer1,#$40
- bmi TremolPosRes2
- mov TempBuffer1,#$40
- TremolPosRes2:
- mov a,CurrentChannel
- or a,#$00
- mov $f2,a
- mov $f3,TempBuffer1
- inc a
- mov $f2,a
- mov $f3,TempBuffer1
- mov y,#ch_tremolo_command_buffer
- mov a,[CurrentChDataLo]+y
- lsr a
- lsr a
- and a,#$3c
- mov TempBuffer1,a
- mov y,#ch_tremolo_position
- mov a,[CurrentChDataLo]+y
- clrc
- adc a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- ret
- TickbasedVolslide:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- xcn a
- and a,#$0f
- beq TickbasedVolSlideDown
- mov TempBuffer1,a
- VolSlideUp:
- mov y,#ch_current_volume
- mov a,[CurrentChDataLo]+y
- adc a,TempBuffer1
- cmp a,#$40
- bmi VolSlideUpNoWaveformReset
- mov a,#$40
- VolSlideUpNoWaveformReset:
- mov [CurrentChDataLo]+y,a
- mov CurrentVolume,a
- call !SetVolumeVibrato
-
- ret
- TickbasedVolSlideDown:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov TempBuffer1,a
- VolSlideDown:
- mov y,#ch_current_volume
- mov a,[CurrentChDataLo]+y
- sbc a,TempBuffer1
- bpl VolSlideDownNoReset
- mov a,#$00
- VolSlideDownNoReset:
- mov [CurrentChDataLo]+y,a
- mov CurrentVolume,a
- call !SetVolumeVibrato
-
- ret
- SetSpeed0x0F:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- mov PatternSpeed,a ;self-modifying code
- dec a
- mov NextRowChFadeOutTime,a
- ret
- SetSampleOffset:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- mov x,a
- mov a,#0
- mov y,#0
- mov TempBuffer3,#$90 ;512/16*9=288, $120
- mov TempBuffer4,#$00
- SetSampleOffsetCalcLoop:
- cmp x,#0
- beq SetSampleOffsetCalcLoopDone
- addw ya,TempBuffer3
- dec x
- bra SetSampleOffsetCalcLoop
- SetSampleOffsetCalcLoopDone:
- movw TempBuffer1,ya
-
- mov y,#ch_instrument
- mov a,[CurrentChDataLo]+y
- asl a
- asl a
- mov x,a
- mov a,!SampleSource+x ;create a new sample (#3f) that plays with the modified start position
- mov TempBuffer5,a
- mov !(SampleSource+(ExtSample*4)),a
- mov a,!(SampleSource+1)+x
- mov TempBuffer6,a
- mov !(SampleSource+1+(ExtSample*4)),a
- mov a,!(SampleSource+2)+x
- mov !(SampleSource+2+(ExtSample*4)),a
- mov a,!(SampleSource+3)+x
- mov !(SampleSource+3+(ExtSample*4)),a
- movw ya,TempBuffer5
- addw ya,TempBuffer1
- movw TempBuffer5,ya
- mov a,TempBuffer5
- mov !(SampleSource+(ExtSample*4)),a
- mov a,TempBuffer6
- mov !(SampleSource+1+(ExtSample*4)),a
- mov a,CurrentChannel
- or a,#$04
- mov $f2,a
- mov $f3,#ExtSample
- ret
- PositionJump:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- mov CurrentPatternNumber,a
- mov x,a
- mov a,!(ModFile+$fa)+x
- asl a
- mov x,a
- mov a,!(ModFile+$17a)+x
- mov y,a
- mov a,!(ModFile+$17b)+x
- addw ya,InitPatternPointerLo
- movw CurrentPatternPointerLo,ya
- pop a ;need to purge the stack a bit first
- pop a ;else, it would overflow slowly when using the pattern break command constantly
- pop a
- pop a
- pop a
- pop a
- jmp !MainLoop
- ;set channel volume:
- EffectSetVolume:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- mov y,#ch_current_volume
- mov [CurrentChDataLo]+y,a
-
- mov CurrentVolume,a
- call !SetVolume
- ret
- PatternBreak:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get break row.
- bne PatternBreakZero ;only breaks to row #0 of next pattern are supported. else dont do anything
- mov PatternBreakFlag,#1 ;set break flag. the actual break gets executed after the current row has been completely processed
- PatternBreakZero:
- ret
- ExEffectSpecialReportCmd:
- inc SpecialReportCmd ;increase special cmd counter.
- ret
-
- SetVibratoWaveform:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov TempBuffer1,a
- mov y,#ch_vibrato_tremolo_waveform ;update vibrato waveform
- mov a,[CurrentChDataLo]+y
- and a,#$f0
- or a,TempBuffer1
- mov [CurrentChDataLo]+y,a
- ret
- Finetune:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov y,#ch_finetune ;whats written to chdata $04 here?
- mov [CurrentChDataLo]+y,a
- ret
- FineVolSlideUp:
- mov a,WaitCounter
- bne FineVolSlideUpCancel
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov TempBuffer1,a
- jmp !VolSlideUp
- FineVolSlideUpCancel:
- ret
- FineVolSlideDown:
- mov a,WaitCounter
- bne FineVolSlideDownCancel
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- mov TempBuffer1,a
- jmp !VolSlideDown
- FineVolSlideDownCancel:
- ret
- InitVariables:
- mov WaitCounter,#$00
- mov a,#$06
- mov PatternSpeed,a ;self-modifying code
- dec a
- mov NextRowChFadeOutTime,a
- mov LoopCounter,#0
- mov CurrentPatternNumber,#$00
- mov PortamentoSpeedMask,#$ff
- mov a,!(ModFile+$f8) ;$13d3
- mov NumberOfPatterns,a
- mov TempBuffer1,#$fc ;initial relative adress of pattern tables
- mov TempBuffer2,#$01
- movw ya,ModFilePointerLo
- movw ModFilePointer2Lo,ya
- addw ya,TempBuffer1
- movw CurrentPatternPointerLo,ya
- movw InitPatternPointerLo,ya
- movw CurrentLoopPointerLo,ya
- mov a,!(ModFile+$fa) ;load initial pattern.
- asl a
- mov x,a
- mov a,!(ModFile+$17a)+x ;get pointer to pattern
- mov y,a
- mov a,!(ModFile+$17b)+x
- addw ya,InitPatternPointerLo
- movw CurrentPatternPointerLo,ya
- mov a,#(PeriodTable & $00ff) ;set pointer to amiga period table
- mov PeriodTablePointerLo,a
- mov a,#(PeriodTable >> 8)
- mov PeriodTablePointerHi,a
- mov a,#(PitchTable & $00ff) ;set pointer to snes pitch table
- mov PitchTablePointerLo,a
- mov a,#(PitchTable >> 8)
- mov PitchTablePointerHi,a
- mov PatternBreakFlag,#0
- mov SpecialReportCmd,#0
- ret
- PortamentoDownLimit:
- .dw $01e3
- ;set reset some dsp registers:
- SetupDspRegsAndTimers:
- mov $f1,#$00 ;stop timers
- mov a,$fd ;clear 4bit counters
- mov a,$fe ;clear 4bit counters
- mov a,$ff ;clear 4bit counters
- mov SongChannelMask,#$0f ;enable all 4 mod channels
- mov ModPlayerTimer0,#$a0
- mov $fa,ModPlayerTimer0 ;20 milliSeconds on timer 0
- mov $fb,#$10 ;2 milliSeconds on timer 1
- nop
- nop
- mov $f1,#$03 ;start timer(s)
- mov a,#$00 ;clear all dsp regs
- mov x,a
- DspRegClearLoop:
- cmp x,#$6c
- bne DspRegClearLoopEchoSkip
- mov $f2,x ;disable echo
- mov $f3,#$20
- inc x
-
- DspRegClearLoopEchoSkip:
- mov $f2,x
- mov $f3,a
- inc x
- bpl DspRegClearLoop
- mov $f2,#$5d ;setup dsp regs
- mov $f3,#(SampleSource >> 8) ;this is the sample info loaction (dir)
- mov $f2,#$6c
- mov $f3,#$20
- mov $f2,#$0c ;set master volume
- mov $f3,MainVolL
- mov $f2,#$1c
- mov $f3,MainVolR
- mov $f2,#$3d
- mov $f3,#$00
- mov $f2,#$7c
- mov $f3,a
- ;setup echo stuff:
- ;set filter:
- mov $f2,#$0f ;fir
- mov $f3,#$30
- mov $f2,#$1f ;fir
- mov $f3,#$00
- mov $f2,#$2f ;fir
- mov $f3,#$00
- mov $f2,#$3f ;fir
- mov $f3,#$00
- mov $f2,#$4f ;fir
- mov $f3,#$00
- mov $f2,#$5f ;fir
- mov $f3,#$00
- mov $f2,#$6f ;fir
- mov $f3,#$20
- mov $f2,#$7f ;fir
- mov $f3,#$30
- ;setup adsr on channels 1-4:
- mov a,CurrentChannel
- push a
- mov CurrentChannel,#$00 ;channel 1
- call !SetupAdsr
- mov CurrentChannel,#$10 ;channel 2
- call !SetupAdsr
- mov CurrentChannel,#$20 ;channel 3
- call !SetupAdsr
- mov CurrentChannel,#$30 ;channel 4
- call !SetupAdsr
- pop a
- ret
-
- SetupAdsr:
- mov a,#$05 ;dsp reg $x5 (adsr1)
- or a,CurrentChannel ;or with channel number
- mov x,a
-
- mov $f2,x ;set adsr 1 (winter gold example: $dc) new value: $cb (slower attack an decay)
- mov $f3,#$0e ;old #$0c
- inc x
- mov $f2,x ;set adsr 2 (winter gold example: $2d) new value: $36 (longer release)
- mov $f3,#$2d ;old #$2d
- inc x
- mov a,x
- and a,#$f0 ;only get channel, not register
- mov x,a
- mov a,#$40
- ret
- SetupSamples:
- mov x,#$00
- mov y,#$00
- SetupSamplesLoop:
- inc y
- mov a,[ModFilePointerLo]+y ;get sample relative adress low
- dec y
- clrc
- adc a,ModFilePointerLo ;add modfile position
- mov !(SampleSource+4)+x,a ;store in dsp sample area
- mov a,[ModFilePointerLo]+y ;get sample relative adress hi
- adc a,ModFilePointerHi ;add modfile position, with carry from previous add
- mov !(SampleSource+5)+x,a ;store in dsp sample area
- inc y
- inc y
- inc y
- inc y
- ;repeat the same with loop adress:
- inc y
- mov a,[ModFilePointerLo]+y ;get sample relative adress low
- dec y
- clrc
- adc a,ModFilePointerLo ;add modfile position
- mov !(SampleSource+6)+x,a ;store in dsp sample area
- mov a,[ModFilePointerLo]+y ;get sample relative adress hi
- adc a,ModFilePointerHi ;add modfile position, with carry from previous add
- mov !(SampleSource+7)+x,a ;store in dsp sample area
- inc y
- inc y
- inc y
- inc y
- inc x
- inc x
- inc x
- inc x
- cmp x,#$7c
- bne SetupSamplesLoop
-
- ret
-
- ;old:
- clrc
- mov a,!(ModFile+1)+x ;get sample location $12dc
- adc a,#(ModFile & $00ff) ;add #$12db
- mov !(SampleSource+4)+y,a ;store in dsp sample area
- mov a,!ModFile+x
- adc a,#(ModFile >> 8)
- mov !(SampleSource+5)+y,a
- inc x
- inc x
- inc x
- inc x
- clrc
- mov a,!(ModFile+1)+x
- adc a,#(ModFile & $00ff)
- mov !(SampleSource+6)+y,a
- mov a,!ModFile+x
- adc a,#(ModFile >> 8)
- mov !(SampleSource+7)+y,a
- inc x
- inc x
- inc x
- inc x
- inc y
- inc y
- inc y
- inc y
- cmp y,#$7c
- bne SetupSamplesLoop
- ret
- ;setup stream sample adress, sample #33
- SetupStreamSampleAdress:
- mov a,#SpcStreamSampleNumber ;get number of sample to use
- asl a ;multiply by 4
- asl a
- mov y,a ;pointer into sample source table
-
- mov a,#(StreamBuffer & $00ff) ;get 1st stream buffer adress
- mov !(SampleSource)+y,a ;store in dsp sample area
- mov !(SampleSource+2)+y,a
- mov a,#(StreamBuffer >> 8)
- mov !(SampleSource+1)+y,a
- mov !(SampleSource+3)+y,a
- ret
-
- KeyOnKeyOff:
- mov y,#0
- mov a,#$5c
- movw $f2,ya
- mov $f2,#$4c
- mov a,KeyOn
- and a,SongChannelMask
- mov $f3,a
- ret
- CutOffChannelGain:
- mov a,#$07 ;select GAIN dsp reg
- or a,CurrentChannel ;
- mov $f2,a ;set gain (winter gold example: $3d)
- mov $f3,#%10011111 ;decrease volume, 8mS ;old #%10111111
- mov y,#ch_current_volume
- mov a,#0 ;clear volume
- mov [CurrentChDataLo]+y,a
- ret ;return
- SetVolumeVibrato:
- ;set channel mod volume
- mov a,#$07 ;select GAIN dsp reg
- or a,CurrentChannel ;
- mov $f2,a ;set gain
- mov a,CurrentVolume
- and a,#$7f ;set direct gain mode
- mov $f3,a
- ;set channel global volume
- mov a,CurrentChannel ;check active channel
- cmp a,#0
- beq SetVolumeLeftCh
- cmp a,#$20
- beq SetVolumeLeftCh
- mov y,MusicVol1
- movw $f2,ya
- inc a
- mov y,MusicVol2
- movw $f2,ya
- ret
- SetVolume:
- ;set channel mod volume
- mov a,#$07 ;select GAIN dsp reg
- or a,CurrentChannel ;
- mov $f2,a ;set gain
- mov y,#ch_current_volume
- mov a,[CurrentChDataLo]+y
- and a,#$7f ;set direct gain mode
- mov $f3,a
- ;set channel global volume
- mov a,CurrentChannel ;check active channel
- cmp a,#0
- beq SetVolumeLeftCh
- cmp a,#$20
- beq SetVolumeLeftCh
- mov y,MusicVol1
- movw $f2,ya
- inc a
- mov y,MusicVol2
- movw $f2,ya
- ret
- SetVolumeLeftCh:
- mov y,MusicVol2
- movw $f2,ya
- inc a
- mov y,MusicVol1
- movw $f2,ya
- ret
-
- mov a,CurrentChannel ;save current volume
- mov $f2,a
- mov a,$f3
- mov TempVol,a
-
- SetVolumeLoop:
- cmp CurrentVolume,TempVol ;check if bigger or smaller
- beq SetVolumeExit
- bmi SetVolumeDec ;branch if old value is bigger than new
- inc TempVol
- mov a,CurrentChannel ;check active channel
- mov y,TempVol
- movw $f2,ya
- inc a
- movw $f2,ya
-
- bra SetVolumeLoop
- SetVolumeDec:
- dec TempVol
- mov a,CurrentChannel ;check active channel
- mov y,TempVol
- movw $f2,ya
- inc a
- movw $f2,ya
- bra SetVolumeLoop
- SetVolumeExit:
- ret
-
- PreTestRow:
- mov y,#$00
- mov NextRowChFadeOuts,#$00
- mov CurrentChannel,#$01
- call !PreTestChannel
- mov CurrentChannel,#$02
- call !PreTestChannel
- mov CurrentChannel,#$04
- call !PreTestChannel
- mov CurrentChannel,#$08
- jmp !PreTestChannel
-
-
- PreTestChannel:
- mov a,[CurrentPatternPointerLo]+y
- cmp a,#$00
- beq PreTestChannelIsEffectOnly
- cmp a,#$ff ;compare if channel entry is $ff(skip)
- beq PreTestChannelIsVoid
-
- inc y ;check if a period is present
- mov a,[CurrentPatternPointerLo]+y
- cmp a,#$ff
- beq PreTestChannelIsEffectOnly2
-
- inc y
- mov a,[CurrentPatternPointerLo]+y
- cmp a,#3 ;check if tone portamento (which doesnt actually play a new note, so the old one must not be muted)
- beq PreTestChannelIsEffectOnly3
- and a,#$0f
- mov TempBuffer1,a
- inc y
- mov a,[CurrentPatternPointerLo]+y
- dec y
- and a,#$f0
- or a,TempBuffer1
- cmp a,#$de ;delay sample effect present? if yes, don't trigger sample
- beq PreTestChannelIsEffectOnly3
-
- mov a,NextRowChFadeOuts
- or a,CurrentChannel ;if theres a note in the next row on this channel, set flag to fade it out before the next row gets processed
- mov NextRowChFadeOuts,a
- bra PreTestChannelIsEffectOnly3
- PreTestChannelIsEffectOnly:
- inc y ;if theres a note, the pattern data entry is 4 bytes long
- PreTestChannelIsEffectOnly2:
- inc y
- PreTestChannelIsEffectOnly3:
- inc y
- PreTestChannelIsVoid:
- inc y
- ret
-
- PatternLoop:
- ;get effect value
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get current effect value
- and a,#$0f ;and $0f
- bne PatternLoopDontSetLoopPoint
- ;effect value is 0, set loop point:
- movw ya,CurrentRowPointerLo
- movw CurrentLoopPointerLo,ya
- ret
- ;effect value is not 0, check if we are in an active loop
- PatternLoopDontSetLoopPoint:
- mov a,LoopCounter ;check if loop is in progress, must be reset by loop jumper after loop repeat has been finished.
- and a,#$20
- bne PatternLoopDontSetLoopPointButLoop
- ;we arent in a loop, set loop count:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get current effect value
- and a,#$0f ;and $0f
- or a,#$30 ;set "in loop"-flag and "do jump"-flag
- mov LoopCounter,a
- ret
- PatternLoopDontSetLoopPointButLoop:
- ;we are in a loop, just jump:
- mov a,LoopCounter
- and a,#$0f
- dec a
- mov LoopCounter,a
- beq PatternLoopFinished
- ;do another loop jump
- or LoopCounter,#$30
-
- PatternLoopFinished:
- ret
- PatternLoopJumper:
- mov a,LoopCounter
- and a,#%00010000
- beq PatternLoopJumperNoJump
- movw ya,CurrentLoopPointerLo
- movw CurrentPatternPointerLo,ya
- mov a,LoopCounter
- and a,#%11101111
- mov LoopCounter,a
- PatternLoopJumperNoJump:
- ret
- EffectNoteRetrigger:
- EffectNoteDelay:
- EffectNoteCutOff:
- mov y,#ch_effect_data
- mov a,[CurrentChDataLo]+y ;get current effect value
- and a,#$0f ;and $0f
- beq EffectNoteCutOffImmediately
- dec a
- EffectNoteCutOffImmediately:
- mov y,#ch_tick_delay
- mov [CurrentChDataLo]+y,a ;write to buffer
- ret
- TickBasedExEffectNoteCutOff:
- mov y,#ch_tick_delay
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- bne CheckForTickBasedEffectsNoteCutOffDec
-
- mov [CurrentChDataLo]+y,a
- call !CutOffChannelGain
-
- mov y,#ch_current_channelmask
- mov a,[CurrentChDataLo]+y ;disable channel in keyon reg
- eor a,#$ff
- mov ScratchPad1,a
- and KeyOn,ScratchPad1
- mov CurrentVolume,#$00
- call !SetVolume
- mov y,#ch_effect_data ;clear effect data so this routine isnt triggered on successive ticks of this frame
- mov a,#0
- mov [CurrentChDataLo]+y,a
-
- ret
- CheckForTickBasedEffectsNoteCutOffDec:
- dec a
- mov [CurrentChDataLo]+y,a
-
- ;CheckForTickBasedEffectsNoNoteCutOff:
- ret
- TickBasedExEffectNoteRetrigger:
- TickBasedExEffectNoteDelay:
- mov y,#ch_tick_delay
- mov a,[CurrentChDataLo]+y
- and a,#$0f
- bne CheckForTickBasedEffectsNoteDelayDec
-
- call !SetNewSample
- mov y,#ch_current_channelmask
- mov a,[CurrentChDataLo]+y ;enable channel in keyon reg
- or a,TickSampleStart
- mov TickSampleStart,a
- mov y,#ch_effect_data ;clear effect data so this routine isnt triggered on successive ticks of this frame
- mov a,#0
- mov [CurrentChDataLo]+y,a
- ret
- CheckForTickBasedEffectsNoteDelayDec:
- dec a
- mov [CurrentChDataLo]+y,a
- ret
- SetEchoAndVolume:
- mov $f2,#$2c ;echo volume l
- mov $f3,#$00 ;0d
- mov $f2,#$3c ;echo volume r
- mov $f3,#$00 ;0d
- mov $f2,#$4d ;echo channel enable
- mov $f3,#$00 ;ff
- ret
- ReceiveSongHandler:
- mov $f2,#$0c
- mov $f3,#$00
- mov $f2,#$1c
- mov $f3,#$00
- mov $f2,#$2c
- mov $f3,#$00
- mov $f2,#$3c
- mov $f3,#$00
- mov $f2,#$6c ;disable echo
- mov $f3,#$20
-
-
- mov a,#SpcCmdUploadSong ;set "upload song command received"-flag so cpu knows we're ready
- mov $f4,a
- mov a,#$00 ;clear remaining ports
- mov $f5,a
- mov $f6,a
- mov $f7,a
- mov SpcDataPointerLo,#(ModFile & $00ff) ;setup mod pointer
- mov SpcDataPointerHi,#(ModFile >> 8)
- mov ModFilePointerLo,#(ModFile & $00ff) ;setup mod pointer
- mov ModFilePointerHi,#(ModFile >> 8)
- mov y,#$00 ;clear mod pointer counter(actually, this counter always stays 0,just needed for indirect write)
- ReceiveSongWaitLoop2: ;wait for first transfer
- cmp $f4,#SpcCmdUploadSongDone
- beq ReceiveSongComplete ;check if upload complete
-
- cmp $f4,#SpcCmdUploadSongT1 ;check if data for transfer 1 is stable and on ports
- bne ReceiveSongWaitLoop2
- mov a,$f5 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov $f4,#SpcCmdUploadSongT1
-
- ReceiveSongWaitLoop3: ;wait for second transfer
- cmp $f4,#SpcCmdUploadSongT2
- bne ReceiveSongWaitLoop3
- mov a,$f5 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov $f4,#SpcCmdUploadSongT2
- bra ReceiveSongWaitLoop2
- ReceiveSongComplete:
- mov a,#$00 ;clear apu ports so that cpu knows were ready
- mov $f4,a
- mov $f5,a
- mov $f6,a
- mov $f7,a
- mov ModTimecode,#0 ;clear Timecode
- mov ModTimecode+1,#0
- mov SongEffectsUploaded,#%00000001 ;set "song uploaded" flag, clear "sample pack uploaded" flag
- ret
- ReceiveSamplePack:
- mov a,#SpcCmdUploadSamplePack ;set "upload song command received"-flag so cpu knows we're ready
- mov $f4,a
- mov a,#$00 ;clear remaining ports
- mov $f5,a
- mov $f6,a
- mov $f7,a
-
- mov $f2,#$5c ;key off all channels
- mov $f3,#%11111111
-
- movw ya,SpcDataPointerLo ;save offset
- movw TempBuffer1,ya
- mov y,#$00 ;clear mod pointer counter(actually, this counter always stays 0,just needed for indirect write)
- ReceiveSamplePackWaitLoop2: ;wait for first transfer
- cmp $f4,#SpcCmdUploadSamplePackDone
- beq ReceiveSamplePackComplete ;check if upload complete
-
- cmp $f4,#SpcCmdUploadSongT1 ;check if data for transfer 1 is stable and on ports
- bne ReceiveSamplePackWaitLoop2
- mov a,$f5 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov $f4,#SpcCmdUploadSongT1
-
- ReceiveSamplePackWaitLoop3: ;wait for second transfer
- cmp $f4,#SpcCmdUploadSongT2
- bne ReceiveSamplePackWaitLoop3
- mov a,$f5 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [SpcDataPointerLo]+y,a
- incw SpcDataPointerLo ;increment counter, word
- mov $f4,#SpcCmdUploadSongT2
- bra ReceiveSamplePackWaitLoop2
- ReceiveSamplePackComplete:
- mov a,#$00 ;clear apu ports so that cpu knows were ready
- mov $f4,a
- mov $f5,a
- mov $f6,a
- mov $f7,a
- movw ya,TempBuffer1 ;restore saved pointer
- movw SpcDataPointerLo,ya
-
- or SongEffectsUploaded,#%00000010 ;set "sample pack uploaded" flag
- call !SetupEffectSamples
- ;return to mainloop:
- jmp !MainLoop
- SetupEffectSamples:
- mov x,#34*4 ;start copying to 34th dsp sample
- mov y,#$00
- mov a,[SpcDataPointerLo]+y ;get number of sample in pack
- and a,#$1f ;maximum number of samples 31
- mov TempBuffer1,a ;this is our number of samples to process
- inc y ;advance to first byte pointer
- SetupEffectSamplesLoop:
- ;sample adress:
- mov a,[SpcDataPointerLo]+y ;get sample relative adress low
- inc y
- clrc
- adc a,SpcDataPointerLo ;add modfile position
- mov !(SampleSource+0)+x,a ;store in dsp sample area
- mov a,[SpcDataPointerLo]+y ;get sample relative adress hi
- adc a,SpcDataPointerHi ;add modfile position, with carry from previous add
- dec y
- mov !(SampleSource+1)+x,a ;store in dsp sample area
- inc y
- inc y
- ;sample loop adress:
- mov a,[SpcDataPointerLo]+y ;get sample relative adress low
- inc y
- clrc
- adc a,SpcDataPointerLo ;add modfile position
- mov !(SampleSource+2)+x,a ;store in dsp sample area
-
-
- mov a,[SpcDataPointerLo]+y ;get sample relative adress hi
- adc a,SpcDataPointerHi ;add modfile position, with carry from previous add
- dec y
- mov !(SampleSource+3)+x,a ;store in dsp sample area
- mov a,y ;increment source pointer by 15 (entry is 16 bytes long)
- clrc
- adc a,#14
- mov y,a
-
- inc x
- inc x
- inc x
- inc x
- dbnz TempBuffer1,SetupEffectSamplesLoop
-
- ret
- PlaySoundEffectAbort:
- jmp !MainLoop
- PlaySoundEffect:
- movw ya,$f4 ;save all 4 ports to variables
- movw TempBuffer1,ya ;tempbuffer1:command,tb2:se number,tb3-4:volume/pitch
- movw ya,$f6
- movw TempBuffer3,ya
-
- mov $f4,#SpcCmdPlaySoundEffect ;echo command received
-
- bbc $ef.1,PlaySoundEffectAbort ;only process song if song has been uploaded before
- mov a,TempBuffer4
- and a,#$80 ;get flip flag
- eor a,SoundEffectFlipFlag
- bne PlaySoundEffectAbort ;only play effect if this flag has changed as expected
-
- eor SoundEffectFlipFlag,#$80 ;toggle flag for next soundeffect
- mov y,#0
- mov a,[SpcDataPointerLo]+y ;get number of samples in pack
- mov TempBuffer5,a
- mov a,TempBuffer2
-
- cmp a,TempBuffer5
- bcs PlaySoundEffectAbort ;return if sound effect to play is bigger than number of samples in pack
- mov a,ActiveSoundEffectCh
- inc a ;goto next channel
- and a,#3 ;maximum number of channels is 3
- mov ActiveSoundEffectCh,a ;save back
- mov x,a
- mov a,!SoundEffectChannelDspRegLUT+x ;get channel value for dsp access
- mov TempBuffer5,a
- mov a,!SoundEffectChannelKofLUT+x ;get channel key off bit
- mov TempBuffer6,a
- mov $f2,#$5c ;key off current channel
- mov $f3,a
-
- ;wait 8ms for key off to finish
- mov a,$fe ;clear 4bit counter
- mov y,#4
- KofWaitLoop2:
- mov a,$fe ;wait for 2mS
- beq KofWaitLoop2
- dbnz y,KofWaitLoop2
- mov x,TempBuffer5 ;get pointer to dsp channel register set
-
- mov a,TempBuffer2 ;get sample number
- asl a ;multiply by 16
- asl a
- asl a
- asl a
- inc a ;increment because first byte in sample pack is number of samples
- mov y,a
-
- inc y
- inc y
- inc y
- inc y
-
- mov a,TempBuffer4 ;get 65816 command volume
- and a,#$7f ;mask off flip flag
- beq PlaySoundEffectDefaultVol
- ;play SE with custom volume
- and a,#%0001111 ;get volume
- mov TempBuffer7,a
- clrc
- asl a
- asl a
- asl a
- and TempBuffer7,#%00001111 ;add lower bits to get maximum range
- or a,TempBuffer7
- mov TempBuffer7,a
- call !SoundEffectCalcPanL
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- call !SoundEffectCalcPanR
- mov $f2,x
- mov $f3,a
- bra PlaySoundEffectCustomVol
- PlaySoundEffectDefaultVol:
- mov a,[SpcDataPointerLo]+y ;get volume l
-
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,[SpcDataPointerLo]+y ;get volume r
-
- mov $f2,x
- mov $f3,a
- PlaySoundEffectCustomVol:
- inc y
- inc x
- mov a,TempBuffer3 ;get 65816 command pitch
- beq PlaySoundEffectDefaultPitch
- ;play custom pitch. same as mod pitch numbers. valid pitch numbers: 0-59
- push y
- ;**************************************************
- asl a ;asl because each period is 2 bytes long
- mov y,a ;get period number
- mov a,[PeriodTablePointerLo]+y ;get current period
- mov TempBuffer7,a
- inc y
- mov a,[PeriodTablePointerLo]+y
- mov TempBuffer8,a
- ;fetch pitch from pitch table. input: period
- mov y,TempBuffer8
- mov a,TempBuffer7
- addw ya,TempBuffer7 ;multiply by 2
- addw ya,PitchTablePointerLo ;add table offset
- movw TempBuffer7,ya ;move adress to pointer
- mov y,#0
- mov a,[TempBuffer7]+y ;get lo pitch byte
- mov PitchBufferLo,a ;save new pitch
- inc y
- mov a,[TempBuffer7]+y
- mov PitchBufferHi,a
- pop y
- mov a,PitchBufferLo ;get pitch lo
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,PitchBufferHi ;get pitch hi
- mov $f2,x
- mov $f3,a
- bra PlaySoundEffectCustomPitch
-
- ;**********************************************+
-
- PlaySoundEffectDefaultPitch:
- mov a,[SpcDataPointerLo]+y ;get pitch lo
-
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,[SpcDataPointerLo]+y ;get pitch hi
-
- mov $f2,x
- mov $f3,a
- PlaySoundEffectCustomPitch:
- inc x
- mov a,TempBuffer2 ;get sound effect to play
- clrc
- adc a,#34 ;add 34 (sound effects start at dsp sample 34)
-
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,[SpcDataPointerLo]+y ;get adsr lo
-
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,[SpcDataPointerLo]+y ;get adsr hi
-
- mov $f2,x
- mov $f3,a
- inc y
- inc x
- mov a,[SpcDataPointerLo]+y ;get gain
-
- mov $f2,x
- mov $f3,a
- mov $f2,#$5c ;reset key off in case it's still active.(shouldn't, though)
- mov $f3,#%00000000
- mov $f2,#$4c ;key on channel
- mov $f3,TempBuffer6
-
- jmp !MainLoop
- ;in: TempBuffer4:volume&pan command
- ; TempBuffer7:total channel volume
- ;out: a,8bit: panned channel volume
- ;uses: TempBuffer8
- SoundEffectCalcPanL:
- mov a,TempBuffer4 ;get pan bits
- xcn a ;swap nibbles
- ;put pan bits into lower 4 bits. we're skipping lsr a, asl a here because the pointers in the LUT are words.
- and a,#%00000111 ;mask off rest
- push x
- asl a
- mov x,a ;use as pointer
- mov a,TempBuffer7
- jmp [!PlaySoundEffectLVolLUT+x]
- PlaySoundEffectLVolLUT:
- .dw PlaySoundEffectVolTBL
- .dw PlaySoundEffectVolTBL+1
- .dw PlaySoundEffectVolTBL+2
- .dw PlaySoundEffectVolTBL+3
- .dw PlaySoundEffectVolTBL+4
- .dw PlaySoundEffectVolTBL+5
- .dw PlaySoundEffectVolTBL+6
- .dw PlaySoundEffectVolTBL+7
- SoundEffectCalcPanR:
- mov a,TempBuffer4 ;get pan bits
- xcn a ;swap nibbles
- ;put pan bits into lower 4 bits. we're skipping lsr a, asl a here because the pointers in the LUT are words.
- and a,#%00000111 ;mask off rest
- push x
- asl a
- mov x,a ;use as pointer
- mov a,TempBuffer7
- jmp [!PlaySoundEffectRVolLUT+x]
- PlaySoundEffectRVolLUT:
- .dw PlaySoundEffectVolTBL+7
- .dw PlaySoundEffectVolTBL+6
- .dw PlaySoundEffectVolTBL+5
- .dw PlaySoundEffectVolTBL+4
- .dw PlaySoundEffectVolTBL+3
- .dw PlaySoundEffectVolTBL+2
- .dw PlaySoundEffectVolTBL+1
- .dw PlaySoundEffectVolTBL
-
- PlaySoundEffectVolTBL:
- lsr a
- lsr a
- lsr a
- lsr a
- lsr a
- lsr a
- lsr a
- nop
- mov TempBuffer8,a ;save
- mov a,TempBuffer7
- setc
- sbc a,TempBuffer8 ;substract calculated pan value
- pop x
- ret
- ReceiveStream:
- mov $f2,#$5c ;key off channels 0-3
- mov $f3,#%00001111
-
- mov StreamState,#0 ;reset transfer state machine
- mov StreamCurrentBuffer,#0 ;reset to first buffer
-
- call !SetupStreamSampleAdress
- movw ya,$f5
- movw TempBuffer1,ya ;get total number of samples to transfer
- mov a,#0
- mov y,a
- movw TempBuffer3,ya ;clear current frame counter
- movw $f5,ya ;tell 65816 current frame to transfer
- mov $f4,#SpcCmdReceiveStream
- ReceiveStreamWaitLoop1:
- cmp $f4,#SpcCmdSubmitStreamNumber
- bne ReceiveStreamWaitLoop1
- ;wait for desired frame
- movw ya,$f5
- cmpw ya,TempBuffer3
- bne ReceiveStreamRequestFrame
- mov a,$f7
- mov StreamVolume,a
- beq ReceiveStreamExit ;exit streaming if volume is 0
- ;enter receive state machine
- mov a,StreamState
- asl a
- mov x,a ;pointer into jump table
- jmp [!StreamJumpTable+x]
-
- ReceiveStreamWaitLoop2:
- cmp $f4,#SpcCmdSubmitStreamNumber ;wait for port0 data to change. Don't know if this works out as desired, but
- beq ReceiveStreamWaitLoop2
-
-
- ReceiveStreamTransferLoop: ;66 cycles per scanline. this loop must be exactly 66 bytes long while looping.
- ;26 cycles ;59 cycles per scanline left for actual transfer
- movw ya,$f4
- push a ;save data on stack cause that's the fastest way possible
- push y
- movw ya,$f6
- push a
- push y
-
- ;waste 33 cyles:
- ;******************************
- mov a,TempBuffer1 ;real snes/bsnes need a total of 33 cycles here
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- mov a,TempBuffer1
- ;7 cycles when looping back
- dbnz TempBuffer5,ReceiveStreamTransferLoop
- mov a,#36
- mov TempBuffer5,a
- mov y,#144-1 ;set counter to last byte in buffer(reverse copy because of stack)
-
- ReceiveStreamSaveLoop:
- pop a ;dummy loop to fix stack
- mov [TempBuffer7]+y,a ;7 -move to buffer
- dec y
- pop a ;dummy loop to fix stack
- mov [TempBuffer7]+y,a ;7 -move to buffer
- dec y
- pop a ;dummy loop to fix stack
- mov [TempBuffer7]+y,a ;7 -move to buffer
- dec y
- pop a ;dummy loop to fix stack
- mov [TempBuffer7]+y,a ;7 -move to buffer
- dec y
- dbnz TempBuffer5,ReceiveStreamSaveLoop
- cmp StreamCurrentBuffer,#SpcStreamLatency
- bne SpcStreamDontSetEndBit
-
- mov y,#144-9 ;set pointer to last samples header
- mov a,[TempBuffer7]+y ;get header byte
- or a,#%00000011 ;set loop & end bits
- mov [TempBuffer7]+y,a ;save back header byte
- SpcStreamDontSetEndBit:
- incw TempBuffer3 ;request next frame
- inc StreamCurrentBuffer
- and StreamCurrentBuffer,#7 ;maximum number of buffers: 8
- StreamTimerWait: ;wait for 16 brr samples to play / ca. 2 frames to pass, then continue downloading stream
- mov a,$fd
- beq StreamTimerWait
- ReceiveStreamRequestFrame:
- movw ya,TempBuffer3
- movw $f5,ya ;tell 65816 which frame to transfer
-
- movw ya,TempBuffer1 ;check if done transfering
- cmpw ya,TempBuffer3
- bne ReceiveStreamWaitLoop1
- ReceiveStreamExit:
- mov $f2,#$5c ;key off channels 0-3
- mov $f3,#%00000001
- mov $f4,#SpcCmdReceiveStreamComplete ;tell 65816 we're done
- ;StreamWaitSampleEnd:
- mov $f1,#$00 ;stop timer
- nop
- nop
- mov $fa,ModPlayerTimer0 ;reset timer, return to modplayer
-
- nop
- nop
- mov $f1,#$03 ;start timer
-
- jmp !MainLoop ;return
- StreamJumpTable:
- .dw InitStream ;fill buffer, then start playing sample
- .dw StreamContinue ;fill buffer according to timer
- StreamContinue:
- ;setup current stream buffer
- mov TempBuffer7,#(StreamBuffer & $00ff) ;pointer to first stream buffer
- mov TempBuffer8,#(StreamBuffer >> 8)
- mov a,StreamCurrentBuffer
- mov y,#144
- mul ya
- addw ya,TempBuffer7
- movw TempBuffer7,ya ;pointer to current stream buffer in TempBuffer7,8
- mov a,#$00
- mov y,StreamVolume ;update volume
- movw $f2,ya
- inc a
- movw $f2,ya
- mov y,#0 ;clear target copy counter
-
- mov a,#36 ;amount of scanlines to copy
- mov TempBuffer5,a
-
- jmp !ReceiveStreamWaitLoop2
- InitStream:
- ;receive stream here:
- ;setup current stream buffer
- mov TempBuffer7,#(StreamBuffer & $00ff) ;pointer to first stream buffer
- mov TempBuffer8,#(StreamBuffer >> 8)
- mov a,StreamCurrentBuffer
- and a,#7 ;maximum number of buffers: 8
- mov y,#144
- mul ya
- addw ya,TempBuffer7
- movw TempBuffer7,ya ;pointer to current stream buffer in TempBuffer7,8
- mov y,#0 ;clear target copy counter
-
- mov a,#36 ;amount of scanlines to copy
- mov TempBuffer5,a
-
- cmp StreamCurrentBuffer,#SpcStreamLatency
- bne SpcStreamDontStartSample
- ;setup sample dsp regs on channel 1:
- ;wide stereo effect
- mov a,#$00
- mov y,StreamVolume ;volume
- movw $f2,ya
- inc a
- movw $f2,ya
- inc a
- mov y,#$00 ;pitch lo
- movw $f2,ya
- inc a
- mov y,#$04 ;pitch hi
- movw $f2,ya
- inc a
- mov y,#SpcStreamSampleNumber ;sample number
- movw $f2,ya
- inc a
- mov y,#0 ;adsr1 (use gain instead)
- movw $f2,ya
- inc a
- movw $f2,ya ;adsr2
- inc a
- mov y,#$7f ;volume
- movw $f2,ya
- mov $f2,#$5c ;reset key off in case it's still active.(shouldn't, though)
- mov $f3,#%00000000
- mov $f2,#$4c ;key on channel 1
- mov $f3,#%00000001
- mov $f1,#$00 ;stop timer
- nop
- nop
- mov $fa,#StreamerTimer0 ;32 milliSeconds on timer 0
- nop
- nop
- mov $f1,#$03 ;start timer
- inc StreamState ;goto next state
- SpcStreamDontStartSample:
- jmp !ReceiveStreamWaitLoop2
- UpdateVolEchoHandler:
- mov ModFilePointerLo,#(MainVolL & $00ff) ;setup mod pointer
- mov ModFilePointerHi,#(MainVolL >> 8)
- mov y,#$00 ;clear mod pointer counter(actually, this counter always stays 0,just needed for indirect write)
- mov $f4,#$01
- UpdateVolEchoWaitLoop1:
- cmp $f4,#$00 ;check if another data download is due
- bne UpdateVolEchoWaitLoop1
- mov a,$f5 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov $f4,#$00
- UpdateVolEchoWaitLoop2:
- cmp $f4,#$01 ;check if another data download is due
- bne UpdateVolEchoWaitLoop2
- mov a,$f5 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov a,$f6 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov a,$f7 ;get byte
- mov [ModFilePointerLo]+y,a
- incw ModFilePointerLo ;increment counter, word
- mov a,#$00 ;clear apu ports so that cpu knows were ready
- mov $f4,a
- mov $f5,a
- mov $f6,a
- mov $f7,a
- UpdateVolEchoVariablesOnly:
- mov $f2,#$6d ;echo start adress
- mov $f3,#EchoStartAdress ;80
- mov $f2,#$7d ;echo delay
- mov $f3,#EchoDelay ;06
- mov $f2,#$0d ;echo feedback
- mov $f3,#$04 ;04
- mov $f2,#$0c
- mov $f3,MainVolL
- mov $f2,#$1c
- mov $f3,MainVolR
- mov $f2,#$2c
- mov $f3,EchoVolL
- mov $f2,#$3c
- mov $f3,EchoVolR
- mov $f2,#$4d
- mov $f3,ChannelEchoEnable
-
- ret
- ;set key on/key off here:
- GetDataFromPatternCheckPatternPosition:
- ;***********************************************
- ;check if pattern break is due
- mov a, PatternBreakFlag ;check if pattern break flag is set
- beq CheckPatternBreakExit
- inc CurrentPatternNumber ;increment current pattern
- mov x,CurrentPatternNumber ;check if we overflow
- cmp x,NumberOfPatterns
- bne PatternBreakNoOverflow
- mov CurrentPatternNumber,#$00 ;reset to pattern #0 if overflow occured
- mov x,CurrentPatternNumber
- PatternBreakNoOverflow:
- mov a,!(ModFile+$fa)+x ;get id number of next pattern
- asl a
- mov x,a
- mov a,!(ModFile+$17a)+x ;get word-pointer to that table
- mov y,a
- mov a,!(ModFile+$17b)+x
- addw ya,InitPatternPointerLo
- movw CurrentPatternPointerLo,ya ;update current pattern pointer
- mov PatternBreakFlag,#0 ;clear pattern break flag and exit
- pop a ;need to purge the stack a bit first
- pop a ;else, it would overflow slowly when using the pattern break command constantly
- pop a
- pop a
- jmp !MainLoop
- CheckPatternBreakExit:
- ;check if at end of current pattern
- mov x,CurrentPatternNumber
- mov a,!(ModFile+$fa)+x ;load pattern number
- inc a
- asl a ;multiply, use as pointer into patterntable pointertable list
- mov x,a
- mov a,!(ModFile+$17a)+x ;$1455+x ;(ModFile+$17a) ;$17a
- mov TempBuffer2,a
- mov a,!(ModFile+$17b)+x ;$1456+x ;17b
- mov TempBuffer1,a
- movw ya,CurrentPatternPointerLo
- subw ya,InitPatternPointerLo
- cmpw ya,TempBuffer1
- bpl CheckPatternPositionPatternEnd
- ret
- CheckPatternPositionPatternEnd:
- inc CurrentPatternNumber ;increment position in current pattern
- mov a,CurrentPatternNumber
- cmp a,NumberOfPatterns ;check if at end of pattern
- beq CheckPatternPositionReset
- mov x,a
- mov a,!(ModFile+$fa)+x
- asl a
- mov x,a
- mov a,!(ModFile+$17a)+x
- mov y,a
- mov a,!(ModFile+$17b)+x
- addw ya,InitPatternPointerLo
- movw CurrentPatternPointerLo,ya
- movw CurrentLoopPointerLo,ya
- ret
- CheckPatternPositionReset: ;wrap to pattern 0
- mov $f6,#$50
- mov CurrentPatternNumber,#$00
- mov x,CurrentPatternNumber
- mov a,!(ModFile+$fa)+x
- asl a
- mov x,a
- mov a,!(ModFile+$17a)+x
- mov y,a
- mov a,!(ModFile+$17b)+x
- addw ya,InitPatternPointerLo
- movw CurrentPatternPointerLo,ya
- ret
-
- ClearAllChannelArray:
- mov a,#(ChannelArray & $ff) ;get pointer to first channel array
- mov y,#(ChannelArray >> 8)
- movw TempBuffer1,ya
- movw Channel1Array,ya
- mov a,#1
- call !ClearChannelArray
-
- movw Channel2Array,ya
- mov a,#2
- call !ClearChannelArray
- movw Channel3Array,ya
- mov a,#4
- call !ClearChannelArray
- movw Channel4Array,ya
- mov a,#8
- call !ClearChannelArray
- ret
-
-
- ClearChannelArray:
- mov y,#ch_current_channelmask ;number of bytes to copy
- mov [TempBuffer1]+y,a ;put channel mask into array pointer + channel mask value
- decw TempBuffer1
- mov a,#0
- ClearChannelArrayLoop:
- mov [TempBuffer1]+y,a ;clear array
- dbnz y,ClearChannelArrayLoop
-
- incw TempBuffer1
- mov a,#ch_current_channelmask+1 ;get amount of bytes per array and add to current adress
- mov y,#0
- addw ya,TempBuffer1
- movw TempBuffer1,ya ;save adress of next array
- ret
- CommandVoid:
- jmp !MainLoop
- SetSongChannelMask:
- mov SongChannelMask,$f5 ;get new channel mask
- mov $f2,#$5c
- mov a,SongChannelMask
- eor a,#$0f ;invert, switch off masked channels immediately
- mov $f3,a ;key off
- mov $f4,#SpcCmdSetSongChMask ;ack
- jmp !MainLoop ;return
- SetSongSpeed:
- mov ModPlayerTimer0,$f5 ;get new speed
-
- mov $f1,#$00
- nop
- nop
- mov $fa,ModPlayerTimer0 ;20 milliSeconds on timer 0
- mov $fb,#$10 ;2 milliSeconds on timer 1
- nop
- nop
- mov $f1,#$03 ;start timer(s)
- mov $f4,#SpcCmdSetSongSpeed ;ack
- jmp !MainLoop ;return
- StopSongStream:
- and SongEffectsUploaded,#%11111110 ;clear "song uploaded" flag
- mov $f2,#$5c ;reset key off in case it's still active.(shouldn't, though)
- mov $f3,#%00001111 ;key off all mod/stream channels
- mov $f4,#SpcCmdStopSong ;ack command
- jmp !MainLoop ;return
- SetReportType:
- mov SpcReportType,$f5 ;get new report type
- mov $f4,#SpcCmdReportType ;ack
- jmp !MainLoop
- SetSongVolume:
- mov MusicVol1,$f5 ;get new volume, mod channel 0,1
- mov MusicVol2,$f6 ;get new volume, mod channel 0,1
- mov $f4,#SpcCmdSetSongVolume ;ack
- jmp !MainLoop
- SendReportData:
- mov a,SpcReportType ;get report type
- and a,#$07
- asl a
- mov x,a ;pointer into jump table
- jmp [!ReportJumpTable+x]
-
- ReportJumpTable:
- .dw ReportVoid
- .dw ReportTimecode
- .dw ReportChannelLevels
- .dw ReportSpecialCmd
- .dw ReportVoid
- .dw ReportVoid
- .dw ReportVoid
- .dw ReportVoid
-
- ReportVoid:
- mov a,#0
- mov $f5,a ;clear report data
- mov $f6,a
- mov $f7,a
- ret
- ReportTimecode:
- mov $f5,#0 ;clear report byte first
- movw ya,ModTimecode
- movw $f6,ya
- mov a,SpcReportType
- or a,#$e0
- mov $f5,a ;return report type
- ret
- ;report current sample levels of all 4 mod channels as 4bit nibbles unsigned.
- ReportChannelLevels:
- mov $f2,#$09
- mov a,$f3 ;get current wave height ch0
- lsr a
- lsr a
- lsr a
- and a,#$0f
- mov TempBuffer1,a
- mov $f2,#$19
- mov a,$f3 ;get current wave height ch1
- asl a
- and a,#$f0
- or a,TempBuffer1
- mov TempBuffer1,a
- mov $f2,#$29
- mov a,$f3 ;get current wave height ch2
- lsr a
- lsr a
- lsr a
- and a,#$0f
- mov TempBuffer1+1,a
- mov $f2,#$39
- mov a,$f3 ;get current wave height ch3
- asl a
- and a,#$f0
- or a,TempBuffer1+1
- mov TempBuffer1+1,a
-
- movw ya,TempBuffer1
-
- mov $f5,#0 ;clear report byte first
- movw $f6,ya ;write data to ports
- mov a,SpcReportType
- or a,#$e0
- mov $f5,a ;return report type
- ret
- ReportSpecialCmd:
- mov $f5,#0 ;clear report byte first
- mov a,SpecialReportCmd
- mov $f6,a
- mov a,SpcReportType
- or a,#$e0
- mov $f5,a ;return report type
- ret
-
-
- SoundEffectChannelDspRegLUT:
- .db $40
- .db $50
- .db $60
- .db $70
- SoundEffectChannelKofLUT:
- .db $10
- .db $20
- .db $40
- .db $80
-
- VibratoTable:
- .incbin "data/apu/vibratotable.tbl"
- PeriodTable:
- .include "data/apu/amigaperiodtable.tbl"
- PitchTable:
- .include "data/apu/pitchtable_new.tbl"
- .incbin "data/apu/pitchtable2.tbl"
- ModFile:
|