Snd_fx.cpp 201 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344
  1. /*
  2. * Snd_fx.cpp
  3. * -----------
  4. * Purpose: Processing of pattern commands, song length calculation...
  5. * Notes : This needs some heavy refactoring.
  6. * I thought of actually adding an effect interface class. Every pattern effect
  7. * could then be moved into its own class that inherits from the effect interface.
  8. * If effect handling differs severly between module formats, every format would have
  9. * its own class for that effect. Then, a call chain of effect classes could be set up
  10. * for each format, since effects cannot be processed in the same order in all formats.
  11. * Authors: Olivier Lapicque
  12. * OpenMPT Devs
  13. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  14. */
  15. #include "stdafx.h"
  16. #include "Sndfile.h"
  17. #include "mod_specifications.h"
  18. #ifdef MODPLUG_TRACKER
  19. #include "../mptrack/Moddoc.h"
  20. #endif // MODPLUG_TRACKER
  21. #include "tuning.h"
  22. #include "Tables.h"
  23. #include "modsmp_ctrl.h" // For updating the loop wraparound data with the invert loop effect
  24. #include "plugins/PlugInterface.h"
  25. #include "OPL.h"
  26. #include "MIDIEvents.h"
  27. OPENMPT_NAMESPACE_BEGIN
  28. // Formats which have 7-bit (0...128) instead of 6-bit (0...64) global volume commands, or which are imported to this range (mostly formats which are converted to IT internally)
  29. #ifdef MODPLUG_TRACKER
  30. static constexpr auto GLOBALVOL_7BIT_FORMATS_EXT = MOD_TYPE_MT2;
  31. #else
  32. static constexpr auto GLOBALVOL_7BIT_FORMATS_EXT = MOD_TYPE_NONE;
  33. #endif // MODPLUG_TRACKER
  34. static constexpr auto GLOBALVOL_7BIT_FORMATS = MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM | MOD_TYPE_PTM | MOD_TYPE_MDL | MOD_TYPE_DTM | GLOBALVOL_7BIT_FORMATS_EXT;
  35. // Compensate frequency slide LUTs depending on whether we are handling periods or frequency - "up" and "down" in function name are seen from frequency perspective.
  36. static uint32 GetLinearSlideDownTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(LinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? LinearSlideDownTable[i] : LinearSlideUpTable[i]; }
  37. static uint32 GetLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(LinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? LinearSlideUpTable[i] : LinearSlideDownTable[i]; }
  38. static uint32 GetFineLinearSlideDownTable(const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideDownTable[i] : FineLinearSlideUpTable[i]; }
  39. static uint32 GetFineLinearSlideUpTable (const CSoundFile *sndFile, uint32 i) { MPT_ASSERT(i < std::size(FineLinearSlideDownTable)); return sndFile->m_playBehaviour[kPeriodsAreHertz] ? FineLinearSlideUpTable[i] : FineLinearSlideDownTable[i]; }
  40. ////////////////////////////////////////////////////////////
  41. // Length
  42. // Memory class for GetLength() code
  43. class GetLengthMemory
  44. {
  45. protected:
  46. const CSoundFile &sndFile;
  47. public:
  48. std::unique_ptr<CSoundFile::PlayState> state;
  49. struct ChnSettings
  50. {
  51. uint32 ticksToRender = 0; // When using sample sync, we still need to render this many ticks
  52. bool incChanged = false; // When using sample sync, note frequency has changed
  53. uint8 vol = 0xFF;
  54. };
  55. std::vector<ChnSettings> chnSettings;
  56. double elapsedTime;
  57. static constexpr uint32 IGNORE_CHANNEL = uint32_max;
  58. GetLengthMemory(const CSoundFile &sf)
  59. : sndFile(sf)
  60. , state(std::make_unique<CSoundFile::PlayState>(sf.m_PlayState))
  61. {
  62. Reset();
  63. }
  64. void Reset()
  65. {
  66. if(state->m_midiMacroEvaluationResults)
  67. state->m_midiMacroEvaluationResults.emplace();
  68. elapsedTime = 0.0;
  69. state->m_lTotalSampleCount = 0;
  70. state->m_nMusicSpeed = sndFile.m_nDefaultSpeed;
  71. state->m_nMusicTempo = sndFile.m_nDefaultTempo;
  72. state->m_nGlobalVolume = sndFile.m_nDefaultGlobalVolume;
  73. chnSettings.assign(sndFile.GetNumChannels(), ChnSettings());
  74. const auto muteFlag = CSoundFile::GetChannelMuteFlag();
  75. for(CHANNELINDEX chn = 0; chn < sndFile.GetNumChannels(); chn++)
  76. {
  77. state->Chn[chn].Reset(ModChannel::resetTotal, sndFile, chn, muteFlag);
  78. state->Chn[chn].nOldGlobalVolSlide = 0;
  79. state->Chn[chn].nOldChnVolSlide = 0;
  80. state->Chn[chn].nNote = state->Chn[chn].nNewNote = state->Chn[chn].nLastNote = NOTE_NONE;
  81. }
  82. }
  83. // Increment playback position of sample and envelopes on a channel
  84. void RenderChannel(CHANNELINDEX channel, uint32 tickDuration, uint32 portaStart = uint32_max)
  85. {
  86. ModChannel &chn = state->Chn[channel];
  87. uint32 numTicks = chnSettings[channel].ticksToRender;
  88. if(numTicks == IGNORE_CHANNEL || numTicks == 0 || (!chn.IsSamplePlaying() && !chnSettings[channel].incChanged) || chn.pModSample == nullptr)
  89. {
  90. return;
  91. }
  92. const SamplePosition loopStart(chn.dwFlags[CHN_LOOP] ? chn.nLoopStart : 0u, 0);
  93. const SamplePosition sampleEnd(chn.dwFlags[CHN_LOOP] ? chn.nLoopEnd : chn.nLength, 0);
  94. const SmpLength loopLength = chn.nLoopEnd - chn.nLoopStart;
  95. const bool itEnvMode = sndFile.m_playBehaviour[kITEnvelopePositionHandling];
  96. const bool updatePitchEnv = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED;
  97. bool stopNote = false;
  98. SamplePosition inc = chn.increment * tickDuration;
  99. if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate();
  100. for(uint32 i = 0; i < numTicks; i++)
  101. {
  102. bool updateInc = (chn.PitchEnv.flags & (ENV_ENABLED | ENV_FILTER)) == ENV_ENABLED;
  103. if(i >= portaStart)
  104. {
  105. chn.isFirstTick = false;
  106. const ModCommand &m = *sndFile.Patterns[state->m_nPattern].GetpModCommand(state->m_nRow, channel);
  107. auto command = m.command;
  108. if(m.volcmd == VOLCMD_TONEPORTAMENTO)
  109. {
  110. const auto [porta, clearEffectCommand] = sndFile.GetVolCmdTonePorta(m, 0);
  111. sndFile.TonePortamento(chn, porta);
  112. if(clearEffectCommand)
  113. command = CMD_NONE;
  114. }
  115. if(command == CMD_TONEPORTAMENTO)
  116. sndFile.TonePortamento(chn, m.param);
  117. else if(command == CMD_TONEPORTAVOL)
  118. sndFile.TonePortamento(chn, 0);
  119. updateInc = true;
  120. }
  121. int32 period = chn.nPeriod;
  122. if(itEnvMode) sndFile.IncrementEnvelopePositions(chn);
  123. if(updatePitchEnv)
  124. {
  125. sndFile.ProcessPitchFilterEnvelope(chn, period);
  126. updateInc = true;
  127. }
  128. if(!itEnvMode) sndFile.IncrementEnvelopePositions(chn);
  129. int vol = 0;
  130. sndFile.ProcessInstrumentFade(chn, vol);
  131. if(chn.dwFlags[CHN_ADLIB])
  132. continue;
  133. if(updateInc || chnSettings[channel].incChanged)
  134. {
  135. if(chn.m_CalculateFreq || chn.m_ReCalculateFreqOnFirstTick)
  136. {
  137. chn.RecalcTuningFreq(1, 0, sndFile);
  138. if(!chn.m_CalculateFreq)
  139. chn.m_ReCalculateFreqOnFirstTick = false;
  140. else
  141. chn.m_CalculateFreq = false;
  142. }
  143. chn.increment = sndFile.GetChannelIncrement(chn, period, 0).first;
  144. chnSettings[channel].incChanged = false;
  145. inc = chn.increment * tickDuration;
  146. if(chn.dwFlags[CHN_PINGPONGFLAG]) inc.Negate();
  147. }
  148. chn.position += inc;
  149. if(chn.position >= sampleEnd || (chn.position < loopStart && inc.IsNegative()))
  150. {
  151. if(!chn.dwFlags[CHN_LOOP])
  152. {
  153. // Past sample end.
  154. stopNote = true;
  155. break;
  156. }
  157. // We exceeded the sample loop, go back to loop start.
  158. if(chn.dwFlags[CHN_PINGPONGLOOP])
  159. {
  160. if(chn.position < loopStart)
  161. {
  162. chn.position = SamplePosition(chn.nLoopStart + chn.nLoopStart, 0) - chn.position;
  163. chn.dwFlags.flip(CHN_PINGPONGFLAG);
  164. inc.Negate();
  165. }
  166. SmpLength posInt = chn.position.GetUInt() - chn.nLoopStart;
  167. SmpLength pingpongLength = loopLength * 2;
  168. if(sndFile.m_playBehaviour[kITPingPongMode]) pingpongLength--;
  169. posInt %= pingpongLength;
  170. bool forward = (posInt < loopLength);
  171. if(forward)
  172. chn.position.SetInt(chn.nLoopStart + posInt);
  173. else
  174. chn.position.SetInt(chn.nLoopEnd - (posInt - loopLength));
  175. if(forward == chn.dwFlags[CHN_PINGPONGFLAG])
  176. {
  177. chn.dwFlags.flip(CHN_PINGPONGFLAG);
  178. inc.Negate();
  179. }
  180. } else
  181. {
  182. SmpLength posInt = chn.position.GetUInt();
  183. if(posInt >= chn.nLoopEnd + loopLength)
  184. {
  185. const SmpLength overshoot = posInt - chn.nLoopEnd;
  186. posInt -= (overshoot / loopLength) * loopLength;
  187. }
  188. while(posInt >= chn.nLoopEnd)
  189. {
  190. posInt -= loopLength;
  191. }
  192. chn.position.SetInt(posInt);
  193. }
  194. }
  195. }
  196. if(stopNote)
  197. {
  198. chn.Stop();
  199. chn.nPortamentoDest = 0;
  200. }
  201. chnSettings[channel].ticksToRender = 0;
  202. }
  203. };
  204. // Get mod length in various cases. Parameters:
  205. // [in] adjustMode: See enmGetLengthResetMode for possible adjust modes.
  206. // [in] target: Time or position target which should be reached, or no target to get length of the first sub song. Use GetLengthTarget::StartPos to also specify a position from where the seeking should begin.
  207. // [out] See definition of type GetLengthType for the returned values.
  208. std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target)
  209. {
  210. std::vector<GetLengthType> results;
  211. GetLengthType retval;
  212. // Are we trying to reach a certain pattern position?
  213. const bool hasSearchTarget = target.mode != GetLengthTarget::NoTarget && target.mode != GetLengthTarget::GetAllSubsongs;
  214. const bool adjustSamplePos = (adjustMode & eAdjustSamplePositions) == eAdjustSamplePositions;
  215. SEQUENCEINDEX sequence = target.sequence;
  216. if(sequence >= Order.GetNumSequences()) sequence = Order.GetCurrentSequenceIndex();
  217. const ModSequence &orderList = Order(sequence);
  218. GetLengthMemory memory(*this);
  219. CSoundFile::PlayState &playState = *memory.state;
  220. // Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time)
  221. RowVisitor visitedRows(*this, sequence);
  222. ROWINDEX allowedPatternLoopComplexity = 32768;
  223. // If sequence starts with some non-existent patterns, find a better start
  224. while(target.startOrder < orderList.size() && !orderList.IsValidPat(target.startOrder))
  225. {
  226. target.startOrder++;
  227. target.startRow = 0;
  228. }
  229. retval.startRow = playState.m_nNextRow = playState.m_nRow = target.startRow;
  230. retval.startOrder = playState.m_nNextOrder = playState.m_nCurrentOrder = target.startOrder;
  231. // Fast LUTs for commands that are too weird / complicated / whatever to emulate in sample position adjust mode.
  232. std::bitset<MAX_EFFECTS> forbiddenCommands;
  233. std::bitset<MAX_VOLCMDS> forbiddenVolCommands;
  234. if(adjustSamplePos)
  235. {
  236. forbiddenCommands.set(CMD_ARPEGGIO); forbiddenCommands.set(CMD_PORTAMENTOUP);
  237. forbiddenCommands.set(CMD_PORTAMENTODOWN); forbiddenCommands.set(CMD_XFINEPORTAUPDOWN);
  238. forbiddenCommands.set(CMD_NOTESLIDEUP); forbiddenCommands.set(CMD_NOTESLIDEUPRETRIG);
  239. forbiddenCommands.set(CMD_NOTESLIDEDOWN); forbiddenCommands.set(CMD_NOTESLIDEDOWNRETRIG);
  240. forbiddenVolCommands.set(VOLCMD_PORTAUP); forbiddenVolCommands.set(VOLCMD_PORTADOWN);
  241. if(target.mode == GetLengthTarget::SeekPosition && target.pos.order < orderList.size())
  242. {
  243. // If we know where to seek, we can directly rule out any channels on which a new note would be triggered right at the start.
  244. const PATTERNINDEX seekPat = orderList[target.pos.order];
  245. if(Patterns.IsValidPat(seekPat) && Patterns[seekPat].IsValidRow(target.pos.row))
  246. {
  247. const ModCommand *m = Patterns[seekPat].GetpModCommand(target.pos.row, 0);
  248. for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, m++)
  249. {
  250. if(m->note == NOTE_NOTECUT || m->note == NOTE_KEYOFF || (m->note == NOTE_FADE && GetNumInstruments())
  251. || (m->IsNote() && !m->IsPortamento()))
  252. {
  253. memory.chnSettings[i].ticksToRender = GetLengthMemory::IGNORE_CHANNEL;
  254. }
  255. }
  256. }
  257. }
  258. }
  259. if(adjustMode & eAdjust)
  260. playState.m_midiMacroEvaluationResults.emplace();
  261. // If samples are being synced, force them to resync if tick duration changes
  262. uint32 oldTickDuration = 0;
  263. bool breakToRow = false;
  264. for (;;)
  265. {
  266. const bool ignoreRow = NextRow(playState, breakToRow).first;
  267. // Time target reached.
  268. if(target.mode == GetLengthTarget::SeekSeconds && memory.elapsedTime >= target.time)
  269. {
  270. retval.targetReached = true;
  271. break;
  272. }
  273. // Check if pattern is valid
  274. playState.m_nPattern = playState.m_nCurrentOrder < orderList.size() ? orderList[playState.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
  275. if(!Patterns.IsValidPat(playState.m_nPattern) && playState.m_nPattern != orderList.GetInvalidPatIndex() && target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order)
  276. {
  277. // Early test: Target is inside +++ or non-existing pattern
  278. retval.targetReached = true;
  279. break;
  280. }
  281. while(playState.m_nPattern >= Patterns.Size())
  282. {
  283. // End of song?
  284. if((playState.m_nPattern == orderList.GetInvalidPatIndex()) || (playState.m_nCurrentOrder >= orderList.size()))
  285. {
  286. if(playState.m_nCurrentOrder == orderList.GetRestartPos())
  287. break;
  288. else
  289. playState.m_nCurrentOrder = orderList.GetRestartPos();
  290. } else
  291. {
  292. playState.m_nCurrentOrder++;
  293. }
  294. playState.m_nPattern = (playState.m_nCurrentOrder < orderList.size()) ? orderList[playState.m_nCurrentOrder] : orderList.GetInvalidPatIndex();
  295. playState.m_nNextOrder = playState.m_nCurrentOrder;
  296. if((!Patterns.IsValidPat(playState.m_nPattern)) && visitedRows.Visit(playState.m_nCurrentOrder, 0, playState.Chn, ignoreRow))
  297. {
  298. if(!hasSearchTarget)
  299. {
  300. retval.lastOrder = playState.m_nCurrentOrder;
  301. retval.lastRow = 0;
  302. }
  303. if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true))
  304. {
  305. // We aren't searching for a specific row, or we couldn't find any more unvisited rows.
  306. break;
  307. } else
  308. {
  309. // We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
  310. retval.duration = memory.elapsedTime;
  311. results.push_back(retval);
  312. retval.startRow = playState.m_nRow;
  313. retval.startOrder = playState.m_nNextOrder;
  314. memory.Reset();
  315. playState.m_nCurrentOrder = playState.m_nNextOrder;
  316. playState.m_nPattern = orderList[playState.m_nCurrentOrder];
  317. playState.m_nNextRow = playState.m_nRow;
  318. break;
  319. }
  320. }
  321. }
  322. if(playState.m_nNextOrder == ORDERINDEX_INVALID)
  323. {
  324. // GetFirstUnvisitedRow failed, so there is nothing more to play
  325. break;
  326. }
  327. // Skip non-existing patterns
  328. if(!Patterns.IsValidPat(playState.m_nPattern))
  329. {
  330. // If there isn't even a tune, we should probably stop here.
  331. if(playState.m_nCurrentOrder == orderList.GetRestartPos())
  332. {
  333. if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true))
  334. {
  335. // We aren't searching for a specific row, or we couldn't find any more unvisited rows.
  336. break;
  337. } else
  338. {
  339. // We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
  340. retval.duration = memory.elapsedTime;
  341. results.push_back(retval);
  342. retval.startRow = playState.m_nRow;
  343. retval.startOrder = playState.m_nNextOrder;
  344. memory.Reset();
  345. playState.m_nNextRow = playState.m_nRow;
  346. continue;
  347. }
  348. }
  349. playState.m_nNextOrder = playState.m_nCurrentOrder + 1;
  350. continue;
  351. }
  352. // Should never happen
  353. if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows())
  354. playState.m_nRow = 0;
  355. // Check whether target was reached.
  356. if(target.mode == GetLengthTarget::SeekPosition && playState.m_nCurrentOrder == target.pos.order && playState.m_nRow == target.pos.row)
  357. {
  358. retval.targetReached = true;
  359. break;
  360. }
  361. // If pattern loops are nested too deeply, they can cause an effectively infinite amount of loop evalations to be generated.
  362. // As we don't want the user to wait forever, we bail out if the pattern loops are too complex.
  363. const bool moduleTooComplex = target.mode != GetLengthTarget::SeekSeconds && visitedRows.ModuleTooComplex(allowedPatternLoopComplexity);
  364. if(moduleTooComplex)
  365. {
  366. memory.elapsedTime = std::numeric_limits<decltype(memory.elapsedTime)>::infinity();
  367. // Decrease allowed complexity with each subsong, as this seems to be a malicious module
  368. if(allowedPatternLoopComplexity > 256)
  369. allowedPatternLoopComplexity /= 2;
  370. visitedRows.ResetComplexity();
  371. }
  372. if(visitedRows.Visit(playState.m_nCurrentOrder, playState.m_nRow, playState.Chn, ignoreRow) || moduleTooComplex)
  373. {
  374. if(!hasSearchTarget)
  375. {
  376. retval.lastOrder = playState.m_nCurrentOrder;
  377. retval.lastRow = playState.m_nRow;
  378. }
  379. if(target.mode == GetLengthTarget::NoTarget || !visitedRows.GetFirstUnvisitedRow(playState.m_nNextOrder, playState.m_nRow, true))
  380. {
  381. // We aren't searching for a specific row, or we couldn't find any more unvisited rows.
  382. break;
  383. } else
  384. {
  385. // We haven't found the target row yet, but we found some other unplayed row... continue searching from here.
  386. retval.duration = memory.elapsedTime;
  387. results.push_back(retval);
  388. retval.startRow = playState.m_nRow;
  389. retval.startOrder = playState.m_nNextOrder;
  390. memory.Reset();
  391. playState.m_nNextRow = playState.m_nRow;
  392. continue;
  393. }
  394. }
  395. retval.endOrder = playState.m_nCurrentOrder;
  396. retval.endRow = playState.m_nRow;
  397. // Update next position
  398. SetupNextRow(playState, false);
  399. // Jumped to invalid pattern row?
  400. if(playState.m_nRow >= Patterns[playState.m_nPattern].GetNumRows())
  401. {
  402. playState.m_nRow = 0;
  403. }
  404. if(ignoreRow)
  405. continue;
  406. // For various effects, we need to know first how many ticks there are in this row.
  407. const ModCommand *p = Patterns[playState.m_nPattern].GetpModCommand(playState.m_nRow, 0);
  408. const bool ignoreMutedChn = m_playBehaviour[kST3NoMutedChannels];
  409. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++, p++)
  410. {
  411. ModChannel &chn = playState.Chn[nChn];
  412. if(p->IsEmpty() || (ignoreMutedChn && ChnSettings[nChn].dwFlags[CHN_MUTE])) // not even effects are processed on muted S3M channels
  413. {
  414. chn.rowCommand.Clear();
  415. continue;
  416. }
  417. if(p->IsPcNote())
  418. {
  419. #ifndef NO_PLUGINS
  420. if(playState.m_midiMacroEvaluationResults && p->instr > 0 && p->instr <= MAX_MIXPLUGINS)
  421. {
  422. playState.m_midiMacroEvaluationResults->pluginParameter[{static_cast<PLUGINDEX>(p->instr - 1), p->GetValueVolCol()}] = p->GetValueEffectCol() / PlugParamValue(ModCommand::maxColumnValue);
  423. }
  424. #endif // NO_PLUGINS
  425. chn.rowCommand.Clear();
  426. continue;
  427. }
  428. chn.rowCommand = *p;
  429. switch(p->command)
  430. {
  431. case CMD_SPEED:
  432. SetSpeed(playState, p->param);
  433. break;
  434. case CMD_TEMPO:
  435. if(m_playBehaviour[kMODVBlankTiming])
  436. {
  437. // ProTracker MODs with VBlank timing: All Fxx parameters set the tick count.
  438. if(p->param != 0) SetSpeed(playState, p->param);
  439. }
  440. break;
  441. case CMD_S3MCMDEX:
  442. if(!chn.rowCommand.param && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
  443. chn.rowCommand.param = chn.nOldCmdEx;
  444. else
  445. chn.nOldCmdEx = static_cast<ModCommand::PARAM>(chn.rowCommand.param);
  446. if((p->param & 0xF0) == 0x60)
  447. {
  448. // Fine Pattern Delay
  449. playState.m_nFrameDelay += (p->param & 0x0F);
  450. } else if((p->param & 0xF0) == 0xE0 && !playState.m_nPatternDelay)
  451. {
  452. // Pattern Delay
  453. if(!(GetType() & MOD_TYPE_S3M) || (p->param & 0x0F) != 0)
  454. {
  455. // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right),
  456. // Scream Tracker 3 simply ignores such commands.
  457. playState.m_nPatternDelay = 1 + (p->param & 0x0F);
  458. }
  459. }
  460. break;
  461. case CMD_MODCMDEX:
  462. if((p->param & 0xF0) == 0xE0)
  463. {
  464. // Pattern Delay
  465. playState.m_nPatternDelay = 1 + (p->param & 0x0F);
  466. }
  467. break;
  468. }
  469. }
  470. const uint32 numTicks = playState.TicksOnRow();
  471. const uint32 nonRowTicks = numTicks - std::max(playState.m_nPatternDelay, uint32(1));
  472. playState.m_patLoopRow = ROWINDEX_INVALID;
  473. playState.m_breakRow = ROWINDEX_INVALID;
  474. playState.m_posJump = ORDERINDEX_INVALID;
  475. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++)
  476. {
  477. ModChannel &chn = playState.Chn[nChn];
  478. if(chn.rowCommand.IsEmpty())
  479. continue;
  480. ModCommand::COMMAND command = chn.rowCommand.command;
  481. ModCommand::PARAM param = chn.rowCommand.param;
  482. ModCommand::NOTE note = chn.rowCommand.note;
  483. if(adjustMode & eAdjust)
  484. {
  485. if(chn.rowCommand.instr)
  486. {
  487. chn.nNewIns = chn.rowCommand.instr;
  488. chn.nLastNote = NOTE_NONE;
  489. memory.chnSettings[nChn].vol = 0xFF;
  490. }
  491. if(chn.rowCommand.IsNote())
  492. {
  493. chn.nLastNote = note;
  494. chn.RestorePanAndFilter();
  495. }
  496. // Update channel panning
  497. if(chn.rowCommand.IsNote() || chn.rowCommand.instr)
  498. {
  499. ModInstrument *pIns;
  500. if(chn.nNewIns > 0 && chn.nNewIns <= GetNumInstruments() && (pIns = Instruments[chn.nNewIns]) != nullptr)
  501. {
  502. if(pIns->dwFlags[INS_SETPANNING])
  503. chn.SetInstrumentPan(pIns->nPan, *this);
  504. }
  505. const SAMPLEINDEX smp = GetSampleIndex(note, chn.nNewIns);
  506. if(smp > 0)
  507. {
  508. if(Samples[smp].uFlags[CHN_PANNING])
  509. chn.SetInstrumentPan(Samples[smp].nPan, *this);
  510. }
  511. }
  512. switch(chn.rowCommand.volcmd)
  513. {
  514. case VOLCMD_VOLUME:
  515. memory.chnSettings[nChn].vol = chn.rowCommand.vol;
  516. break;
  517. case VOLCMD_VOLSLIDEUP:
  518. case VOLCMD_VOLSLIDEDOWN:
  519. if(chn.rowCommand.vol != 0)
  520. chn.nOldVolParam = chn.rowCommand.vol;
  521. break;
  522. case VOLCMD_TONEPORTAMENTO:
  523. if(chn.rowCommand.vol)
  524. {
  525. const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, 0);
  526. chn.portamentoSlide = porta;
  527. if(clearEffectCommand)
  528. command = CMD_NONE;
  529. }
  530. break;
  531. }
  532. }
  533. switch(command)
  534. {
  535. // Position Jump
  536. case CMD_POSITIONJUMP:
  537. PositionJump(playState, nChn);
  538. break;
  539. // Pattern Break
  540. case CMD_PATTERNBREAK:
  541. if(ROWINDEX row = PatternBreak(playState, nChn, param); row != ROWINDEX_INVALID)
  542. playState.m_breakRow = row;
  543. break;
  544. // Set Tempo
  545. case CMD_TEMPO:
  546. if(!m_playBehaviour[kMODVBlankTiming])
  547. {
  548. TEMPO tempo(CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn), 0);
  549. if ((adjustMode & eAdjust) && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
  550. {
  551. if (tempo.GetInt()) chn.nOldTempo = static_cast<uint8>(tempo.GetInt()); else tempo.Set(chn.nOldTempo);
  552. }
  553. if (tempo.GetInt() >= 0x20) playState.m_nMusicTempo = tempo;
  554. else
  555. {
  556. // Tempo Slide
  557. TEMPO tempoDiff((tempo.GetInt() & 0x0F) * nonRowTicks, 0);
  558. if ((tempo.GetInt() & 0xF0) == 0x10)
  559. {
  560. playState.m_nMusicTempo += tempoDiff;
  561. } else
  562. {
  563. if(tempoDiff < playState.m_nMusicTempo)
  564. playState.m_nMusicTempo -= tempoDiff;
  565. else
  566. playState.m_nMusicTempo.Set(0);
  567. }
  568. }
  569. TEMPO tempoMin = GetModSpecifications().GetTempoMin(), tempoMax = GetModSpecifications().GetTempoMax();
  570. if(m_playBehaviour[kTempoClamp]) // clamp tempo correctly in compatible mode
  571. {
  572. tempoMax.Set(255);
  573. }
  574. Limit(playState.m_nMusicTempo, tempoMin, tempoMax);
  575. }
  576. break;
  577. case CMD_S3MCMDEX:
  578. switch(param & 0xF0)
  579. {
  580. case 0x90:
  581. if(param <= 0x91)
  582. chn.dwFlags.set(CHN_SURROUND, param == 0x91);
  583. break;
  584. case 0xA0: // High sample offset
  585. chn.nOldHiOffset = param & 0x0F;
  586. break;
  587. case 0xB0: // Pattern Loop
  588. PatternLoop(playState, chn, param & 0x0F);
  589. break;
  590. case 0xF0: // Active macro
  591. chn.nActiveMacro = param & 0x0F;
  592. break;
  593. }
  594. break;
  595. case CMD_MODCMDEX:
  596. switch(param & 0xF0)
  597. {
  598. case 0x60: // Pattern Loop
  599. PatternLoop(playState, chn, param & 0x0F);
  600. break;
  601. case 0xF0: // Active macro
  602. chn.nActiveMacro = param & 0x0F;
  603. break;
  604. }
  605. break;
  606. case CMD_XFINEPORTAUPDOWN:
  607. // ignore high offset in compatible mode
  608. if(((param & 0xF0) == 0xA0) && !m_playBehaviour[kFT2RestrictXCommand])
  609. chn.nOldHiOffset = param & 0x0F;
  610. break;
  611. }
  612. // The following calculations are not interesting if we just want to get the song length.
  613. if(!(adjustMode & eAdjust))
  614. continue;
  615. switch(command)
  616. {
  617. // Portamento Up/Down
  618. case CMD_PORTAMENTOUP:
  619. if(param)
  620. {
  621. // FT2 compatibility: Separate effect memory for all portamento commands
  622. // Test case: Porta-LinkMem.xm
  623. if(!m_playBehaviour[kFT2PortaUpDownMemory])
  624. chn.nOldPortaDown = param;
  625. chn.nOldPortaUp = param;
  626. }
  627. break;
  628. case CMD_PORTAMENTODOWN:
  629. if(param)
  630. {
  631. // FT2 compatibility: Separate effect memory for all portamento commands
  632. // Test case: Porta-LinkMem.xm
  633. if(!m_playBehaviour[kFT2PortaUpDownMemory])
  634. chn.nOldPortaUp = param;
  635. chn.nOldPortaDown = param;
  636. }
  637. break;
  638. // Tone-Portamento
  639. case CMD_TONEPORTAMENTO:
  640. if (param) chn.portamentoSlide = param;
  641. break;
  642. // Offset
  643. case CMD_OFFSET:
  644. if(param)
  645. chn.oldOffset = param << 8;
  646. break;
  647. // Volume Slide
  648. case CMD_VOLUMESLIDE:
  649. case CMD_TONEPORTAVOL:
  650. if (param) chn.nOldVolumeSlide = param;
  651. break;
  652. // Set Volume
  653. case CMD_VOLUME:
  654. memory.chnSettings[nChn].vol = param;
  655. break;
  656. // Global Volume
  657. case CMD_GLOBALVOLUME:
  658. if(!(GetType() & GLOBALVOL_7BIT_FORMATS) && param < 128) param *= 2;
  659. // IT compatibility 16. ST3 and IT ignore out-of-range values
  660. if(param <= 128)
  661. {
  662. playState.m_nGlobalVolume = param * 2;
  663. } else if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M)))
  664. {
  665. playState.m_nGlobalVolume = 256;
  666. }
  667. break;
  668. // Global Volume Slide
  669. case CMD_GLOBALVOLSLIDE:
  670. if(m_playBehaviour[kPerChannelGlobalVolSlide])
  671. {
  672. // IT compatibility 16. Global volume slide params are stored per channel (FT2/IT)
  673. if (param) chn.nOldGlobalVolSlide = param; else param = chn.nOldGlobalVolSlide;
  674. } else
  675. {
  676. if (param) playState.Chn[0].nOldGlobalVolSlide = param; else param = playState.Chn[0].nOldGlobalVolSlide;
  677. }
  678. if (((param & 0x0F) == 0x0F) && (param & 0xF0))
  679. {
  680. param >>= 4;
  681. if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
  682. playState.m_nGlobalVolume += param << 1;
  683. } else if (((param & 0xF0) == 0xF0) && (param & 0x0F))
  684. {
  685. param = (param & 0x0F) << 1;
  686. if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
  687. playState.m_nGlobalVolume -= param;
  688. } else if (param & 0xF0)
  689. {
  690. param >>= 4;
  691. param <<= 1;
  692. if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
  693. playState.m_nGlobalVolume += param * nonRowTicks;
  694. } else
  695. {
  696. param = (param & 0x0F) << 1;
  697. if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param <<= 1;
  698. playState.m_nGlobalVolume -= param * nonRowTicks;
  699. }
  700. Limit(playState.m_nGlobalVolume, 0, 256);
  701. break;
  702. case CMD_CHANNELVOLUME:
  703. if (param <= 64) chn.nGlobalVol = param;
  704. break;
  705. case CMD_CHANNELVOLSLIDE:
  706. {
  707. if (param) chn.nOldChnVolSlide = param; else param = chn.nOldChnVolSlide;
  708. int32 volume = chn.nGlobalVol;
  709. if((param & 0x0F) == 0x0F && (param & 0xF0))
  710. volume += (param >> 4); // Fine Up
  711. else if((param & 0xF0) == 0xF0 && (param & 0x0F))
  712. volume -= (param & 0x0F); // Fine Down
  713. else if(param & 0x0F) // Down
  714. volume -= (param & 0x0F) * nonRowTicks;
  715. else // Up
  716. volume += ((param & 0xF0) >> 4) * nonRowTicks;
  717. Limit(volume, 0, 64);
  718. chn.nGlobalVol = volume;
  719. }
  720. break;
  721. case CMD_PANNING8:
  722. Panning(chn, param, Pan8bit);
  723. break;
  724. case CMD_MODCMDEX:
  725. if(param < 0x10)
  726. {
  727. // LED filter
  728. for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++)
  729. {
  730. playState.Chn[channel].dwFlags.set(CHN_AMIGAFILTER, !(param & 1));
  731. }
  732. }
  733. [[fallthrough]];
  734. case CMD_S3MCMDEX:
  735. if((param & 0xF0) == 0x80)
  736. {
  737. Panning(chn, (param & 0x0F), Pan4bit);
  738. }
  739. break;
  740. case CMD_VIBRATOVOL:
  741. if (param) chn.nOldVolumeSlide = param;
  742. param = 0;
  743. [[fallthrough]];
  744. case CMD_VIBRATO:
  745. Vibrato(chn, param);
  746. break;
  747. case CMD_FINEVIBRATO:
  748. FineVibrato(chn, param);
  749. break;
  750. case CMD_TREMOLO:
  751. Tremolo(chn, param);
  752. break;
  753. case CMD_PANBRELLO:
  754. Panbrello(chn, param);
  755. break;
  756. case CMD_MIDI:
  757. case CMD_SMOOTHMIDI:
  758. if(param < 0x80)
  759. ProcessMIDIMacro(playState, nChn, false, m_MidiCfg.SFx[chn.nActiveMacro], chn.rowCommand.param, 0);
  760. else
  761. ProcessMIDIMacro(playState, nChn, false, m_MidiCfg.Zxx[param & 0x7F], chn.rowCommand.param, 0);
  762. break;
  763. default:
  764. break;
  765. }
  766. switch(chn.rowCommand.volcmd)
  767. {
  768. case VOLCMD_PANNING:
  769. Panning(chn, chn.rowCommand.vol, Pan6bit);
  770. break;
  771. case VOLCMD_VIBRATOSPEED:
  772. // FT2 does not automatically enable vibrato with the "set vibrato speed" command
  773. if(m_playBehaviour[kFT2VolColVibrato])
  774. chn.nVibratoSpeed = chn.rowCommand.vol & 0x0F;
  775. else
  776. Vibrato(chn, chn.rowCommand.vol << 4);
  777. break;
  778. case VOLCMD_VIBRATODEPTH:
  779. Vibrato(chn, chn.rowCommand.vol);
  780. break;
  781. }
  782. // Process vibrato / tremolo / panbrello
  783. switch(chn.rowCommand.command)
  784. {
  785. case CMD_VIBRATO:
  786. case CMD_FINEVIBRATO:
  787. case CMD_VIBRATOVOL:
  788. if(adjustMode & eAdjust)
  789. {
  790. uint32 vibTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks;
  791. uint32 inc = chn.nVibratoSpeed * vibTicks;
  792. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  793. inc *= 4;
  794. chn.nVibratoPos += static_cast<uint8>(inc);
  795. }
  796. break;
  797. case CMD_TREMOLO:
  798. if(adjustMode & eAdjust)
  799. {
  800. uint32 tremTicks = ((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS]) ? numTicks : nonRowTicks;
  801. uint32 inc = chn.nTremoloSpeed * tremTicks;
  802. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  803. inc *= 4;
  804. chn.nTremoloPos += static_cast<uint8>(inc);
  805. }
  806. break;
  807. case CMD_PANBRELLO:
  808. if(adjustMode & eAdjust)
  809. {
  810. // Panbrello effect is permanent in compatible mode, so actually apply panbrello for the last tick of this row
  811. chn.nPanbrelloPos += static_cast<uint8>(chn.nPanbrelloSpeed * (numTicks - 1));
  812. ProcessPanbrello(chn);
  813. }
  814. break;
  815. }
  816. if(m_playBehaviour[kST3EffectMemory] && param != 0)
  817. {
  818. UpdateS3MEffectMemory(chn, param);
  819. }
  820. }
  821. // Interpret F00 effect in XM files as "stop song"
  822. if(GetType() == MOD_TYPE_XM && playState.m_nMusicSpeed == uint16_max)
  823. {
  824. break;
  825. }
  826. playState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
  827. if(Patterns[playState.m_nPattern].GetOverrideSignature())
  828. {
  829. playState.m_nCurrentRowsPerBeat = Patterns[playState.m_nPattern].GetRowsPerBeat();
  830. }
  831. const uint32 tickDuration = GetTickDuration(playState);
  832. const uint32 rowDuration = tickDuration * numTicks;
  833. memory.elapsedTime += static_cast<double>(rowDuration) / static_cast<double>(m_MixerSettings.gdwMixingFreq);
  834. playState.m_lTotalSampleCount += rowDuration;
  835. if(adjustSamplePos)
  836. {
  837. // Super experimental and dirty sample seeking
  838. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++)
  839. {
  840. if(memory.chnSettings[nChn].ticksToRender == GetLengthMemory::IGNORE_CHANNEL)
  841. continue;
  842. ModChannel &chn = playState.Chn[nChn];
  843. const ModCommand &m = chn.rowCommand;
  844. if(!chn.nPeriod && m.IsEmpty())
  845. continue;
  846. uint32 paramHi = m.param >> 4, paramLo = m.param & 0x0F;
  847. uint32 startTick = 0;
  848. bool porta = m.command == CMD_TONEPORTAMENTO || m.command == CMD_TONEPORTAVOL || m.volcmd == VOLCMD_TONEPORTAMENTO;
  849. bool stopNote = false;
  850. if(m.instr) chn.prevNoteOffset = 0;
  851. if(m.IsNote())
  852. {
  853. if(porta && memory.chnSettings[nChn].incChanged)
  854. {
  855. // If there's a portamento, the current channel increment mustn't be 0 in NoteChange()
  856. chn.increment = GetChannelIncrement(chn, chn.nPeriod, 0).first;
  857. }
  858. int32 setPan = chn.nPan;
  859. chn.nNewNote = chn.nLastNote;
  860. if(chn.nNewIns != 0) InstrumentChange(chn, chn.nNewIns, porta);
  861. NoteChange(chn, m.note, porta);
  862. HandleDigiSamplePlayDirection(playState, nChn);
  863. memory.chnSettings[nChn].incChanged = true;
  864. if((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xD0 && paramLo < numTicks)
  865. {
  866. startTick = paramLo;
  867. } else if(m.command == CMD_DELAYCUT && paramHi < numTicks)
  868. {
  869. startTick = paramHi;
  870. }
  871. if(playState.m_nPatternDelay > 1 && startTick != 0 && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
  872. {
  873. startTick += (playState.m_nMusicSpeed + playState.m_nFrameDelay) * (playState.m_nPatternDelay - 1);
  874. }
  875. if(!porta) memory.chnSettings[nChn].ticksToRender = 0;
  876. // Panning commands have to be re-applied after a note change with potential pan change.
  877. if(m.command == CMD_PANNING8
  878. || ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && paramHi == 0x8)
  879. || m.volcmd == VOLCMD_PANNING)
  880. {
  881. chn.nPan = setPan;
  882. }
  883. }
  884. if(m.IsNote() || m_playBehaviour[kApplyOffsetWithoutNote])
  885. {
  886. if(m.command == CMD_OFFSET)
  887. {
  888. ProcessSampleOffset(chn, nChn, playState);
  889. } else if(m.command == CMD_OFFSETPERCENTAGE)
  890. {
  891. SampleOffset(chn, Util::muldiv_unsigned(chn.nLength, m.param, 256));
  892. } else if(m.command == CMD_REVERSEOFFSET && chn.pModSample != nullptr)
  893. {
  894. memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
  895. ReverseSampleOffset(chn, m.param);
  896. startTick = playState.m_nMusicSpeed - 1;
  897. } else if(m.volcmd == VOLCMD_OFFSET)
  898. {
  899. if(chn.pModSample != nullptr && m.vol <= std::size(chn.pModSample->cues))
  900. {
  901. SmpLength offset;
  902. if(m.vol == 0)
  903. offset = chn.oldOffset;
  904. else
  905. offset = chn.oldOffset = chn.pModSample->cues[m.vol - 1];
  906. SampleOffset(chn, offset);
  907. }
  908. }
  909. }
  910. if(m.note == NOTE_KEYOFF || m.note == NOTE_NOTECUT || (m.note == NOTE_FADE && GetNumInstruments())
  911. || ((m.command == CMD_MODCMDEX || m.command == CMD_S3MCMDEX) && (m.param & 0xF0) == 0xC0 && paramLo < numTicks)
  912. || (m.command == CMD_DELAYCUT && paramLo != 0 && startTick + paramLo < numTicks)
  913. || m.command == CMD_KEYOFF)
  914. {
  915. stopNote = true;
  916. }
  917. if(m.command == CMD_VOLUME)
  918. {
  919. chn.nVolume = m.param * 4;
  920. } else if(m.volcmd == VOLCMD_VOLUME)
  921. {
  922. chn.nVolume = m.vol * 4;
  923. }
  924. if(chn.pModSample && !stopNote)
  925. {
  926. // Check if we don't want to emulate some effect and thus stop processing.
  927. if(m.command < MAX_EFFECTS)
  928. {
  929. if(forbiddenCommands[m.command])
  930. {
  931. stopNote = true;
  932. } else if(m.command == CMD_MODCMDEX)
  933. {
  934. // Special case: Slides using extended commands
  935. switch(m.param & 0xF0)
  936. {
  937. case 0x10:
  938. case 0x20:
  939. stopNote = true;
  940. }
  941. }
  942. }
  943. if(m.volcmd < forbiddenVolCommands.size() && forbiddenVolCommands[m.volcmd])
  944. {
  945. stopNote = true;
  946. }
  947. }
  948. if(stopNote)
  949. {
  950. chn.Stop();
  951. memory.chnSettings[nChn].ticksToRender = 0;
  952. } else
  953. {
  954. if(oldTickDuration != tickDuration && oldTickDuration != 0)
  955. {
  956. memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
  957. }
  958. switch(m.command)
  959. {
  960. case CMD_TONEPORTAVOL:
  961. case CMD_VOLUMESLIDE:
  962. case CMD_VIBRATOVOL:
  963. if(m.param || (GetType() != MOD_TYPE_MOD))
  964. {
  965. for(uint32 i = 0; i < numTicks; i++)
  966. {
  967. chn.isFirstTick = (i == 0);
  968. VolumeSlide(chn, m.param);
  969. }
  970. }
  971. break;
  972. case CMD_MODCMDEX:
  973. if((m.param & 0x0F) || (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)))
  974. {
  975. chn.isFirstTick = true;
  976. switch(m.param & 0xF0)
  977. {
  978. case 0xA0: FineVolumeUp(chn, m.param & 0x0F, false); break;
  979. case 0xB0: FineVolumeDown(chn, m.param & 0x0F, false); break;
  980. }
  981. }
  982. break;
  983. case CMD_S3MCMDEX:
  984. if(m.param == 0x9E)
  985. {
  986. // Play forward
  987. memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
  988. chn.dwFlags.reset(CHN_PINGPONGFLAG);
  989. } else if(m.param == 0x9F)
  990. {
  991. // Reverse
  992. memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
  993. chn.dwFlags.set(CHN_PINGPONGFLAG);
  994. if(!chn.position.GetInt() && chn.nLength && (m.IsNote() || !chn.dwFlags[CHN_LOOP]))
  995. {
  996. chn.position.Set(chn.nLength - 1, SamplePosition::fractMax);
  997. }
  998. } else if((m.param & 0xF0) == 0x70)
  999. {
  1000. if(m.param >= 0x73)
  1001. chn.InstrumentControl(m.param, *this);
  1002. }
  1003. break;
  1004. case CMD_DIGIREVERSESAMPLE:
  1005. DigiBoosterSampleReverse(chn, m.param);
  1006. break;
  1007. case CMD_FINETUNE:
  1008. case CMD_FINETUNE_SMOOTH:
  1009. memory.RenderChannel(nChn, oldTickDuration); // Re-sync what we've got so far
  1010. SetFinetune(nChn, playState, false); // TODO should render each tick individually for CMD_FINETUNE_SMOOTH for higher sync accuracy
  1011. break;
  1012. }
  1013. chn.isFirstTick = true;
  1014. switch(m.volcmd)
  1015. {
  1016. case VOLCMD_FINEVOLUP: FineVolumeUp(chn, m.vol, m_playBehaviour[kITVolColMemory]); break;
  1017. case VOLCMD_FINEVOLDOWN: FineVolumeDown(chn, m.vol, m_playBehaviour[kITVolColMemory]); break;
  1018. case VOLCMD_VOLSLIDEUP:
  1019. case VOLCMD_VOLSLIDEDOWN:
  1020. {
  1021. // IT Compatibility: Volume column volume slides have their own memory
  1022. // Test case: VolColMemory.it
  1023. ModCommand::VOL vol = m.vol;
  1024. if(vol == 0 && m_playBehaviour[kITVolColMemory])
  1025. {
  1026. vol = chn.nOldVolParam;
  1027. if(vol == 0)
  1028. break;
  1029. }
  1030. if(m.volcmd == VOLCMD_VOLSLIDEUP)
  1031. vol <<= 4;
  1032. for(uint32 i = 0; i < numTicks; i++)
  1033. {
  1034. chn.isFirstTick = (i == 0);
  1035. VolumeSlide(chn, vol);
  1036. }
  1037. }
  1038. break;
  1039. case VOLCMD_PLAYCONTROL:
  1040. if(m.vol <= 1)
  1041. chn.isPaused = (m.vol == 0);
  1042. break;
  1043. }
  1044. if(chn.isPaused)
  1045. continue;
  1046. if(porta)
  1047. {
  1048. // Portamento needs immediate syncing, as the pitch changes on each tick
  1049. uint32 portaTick = memory.chnSettings[nChn].ticksToRender + startTick + 1;
  1050. memory.chnSettings[nChn].ticksToRender += numTicks;
  1051. memory.RenderChannel(nChn, tickDuration, portaTick);
  1052. } else
  1053. {
  1054. memory.chnSettings[nChn].ticksToRender += (numTicks - startTick);
  1055. }
  1056. }
  1057. }
  1058. }
  1059. oldTickDuration = tickDuration;
  1060. breakToRow = HandleNextRow(playState, orderList, false);
  1061. }
  1062. // Now advance the sample positions for sample seeking on channels that are still playing
  1063. if(adjustSamplePos)
  1064. {
  1065. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++)
  1066. {
  1067. if(memory.chnSettings[nChn].ticksToRender != GetLengthMemory::IGNORE_CHANNEL)
  1068. {
  1069. memory.RenderChannel(nChn, oldTickDuration);
  1070. }
  1071. }
  1072. }
  1073. if(retval.targetReached)
  1074. {
  1075. retval.lastOrder = playState.m_nCurrentOrder;
  1076. retval.lastRow = playState.m_nRow;
  1077. }
  1078. retval.duration = memory.elapsedTime;
  1079. results.push_back(retval);
  1080. // Store final variables
  1081. if(adjustMode & eAdjust)
  1082. {
  1083. if(retval.targetReached || target.mode == GetLengthTarget::NoTarget)
  1084. {
  1085. const auto midiMacroEvaluationResults = std::move(playState.m_midiMacroEvaluationResults);
  1086. playState.m_midiMacroEvaluationResults.reset();
  1087. // Target found, or there is no target (i.e. play whole song)...
  1088. m_PlayState = std::move(playState);
  1089. m_PlayState.ResetGlobalVolumeRamping();
  1090. m_PlayState.m_nNextRow = m_PlayState.m_nRow;
  1091. m_PlayState.m_nFrameDelay = m_PlayState.m_nPatternDelay = 0;
  1092. m_PlayState.m_nTickCount = TICKS_ROW_FINISHED;
  1093. m_PlayState.m_bPositionChanged = true;
  1094. if(m_opl != nullptr)
  1095. m_opl->Reset();
  1096. for(CHANNELINDEX n = 0; n < GetNumChannels(); n++)
  1097. {
  1098. auto &chn = m_PlayState.Chn[n];
  1099. if(chn.nLastNote != NOTE_NONE)
  1100. {
  1101. chn.nNewNote = chn.nLastNote;
  1102. }
  1103. if(memory.chnSettings[n].vol != 0xFF && !adjustSamplePos)
  1104. {
  1105. chn.nVolume = std::min(memory.chnSettings[n].vol, uint8(64)) * 4;
  1106. }
  1107. if(chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl)
  1108. {
  1109. m_opl->Patch(n, chn.pModSample->adlib);
  1110. m_opl->NoteCut(n);
  1111. }
  1112. chn.pCurrentSample = nullptr;
  1113. }
  1114. #ifndef NO_PLUGINS
  1115. // If there were any PC events or MIDI macros updating plugin parameters, update plugin parameters to their latest value.
  1116. std::bitset<MAX_MIXPLUGINS> plugSetProgram;
  1117. for(const auto &[plugParam, value] : midiMacroEvaluationResults->pluginParameter)
  1118. {
  1119. PLUGINDEX plug = plugParam.first;
  1120. IMixPlugin *plugin = m_MixPlugins[plug].pMixPlugin;
  1121. if(plugin != nullptr)
  1122. {
  1123. if(!plugSetProgram[plug])
  1124. {
  1125. // Used for bridged plugins to avoid sending out individual messages for each parameter.
  1126. plugSetProgram.set(plug);
  1127. plugin->BeginSetProgram();
  1128. }
  1129. plugin->SetParameter(plugParam.second, value);
  1130. }
  1131. }
  1132. if(plugSetProgram.any())
  1133. {
  1134. for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
  1135. {
  1136. if(plugSetProgram[i])
  1137. {
  1138. m_MixPlugins[i].pMixPlugin->EndSetProgram();
  1139. }
  1140. }
  1141. }
  1142. // Do the same for dry/wet ratios
  1143. for(const auto &[plug, dryWetRatio] : midiMacroEvaluationResults->pluginDryWetRatio)
  1144. {
  1145. m_MixPlugins[plug].fDryRatio = dryWetRatio;
  1146. }
  1147. #endif // NO_PLUGINS
  1148. } else if(adjustMode != eAdjustOnSuccess)
  1149. {
  1150. // Target not found (e.g. when jumping to a hidden sub song), reset global variables...
  1151. m_PlayState.m_nMusicSpeed = m_nDefaultSpeed;
  1152. m_PlayState.m_nMusicTempo = m_nDefaultTempo;
  1153. m_PlayState.m_nGlobalVolume = m_nDefaultGlobalVolume;
  1154. }
  1155. // When adjusting the playback status, we will also want to update the visited rows vector according to the current position.
  1156. if(sequence != Order.GetCurrentSequenceIndex())
  1157. {
  1158. Order.SetSequence(sequence);
  1159. }
  1160. }
  1161. if(adjustMode & (eAdjust | eAdjustOnlyVisitedRows))
  1162. m_visitedRows.MoveVisitedRowsFrom(visitedRows);
  1163. return results;
  1164. }
  1165. //////////////////////////////////////////////////////////////////////////////////////////////////
  1166. // Effects
  1167. // Change sample or instrument number.
  1168. void CSoundFile::InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta, bool bUpdVol, bool bResetEnv) const
  1169. {
  1170. const ModInstrument *pIns = instr <= GetNumInstruments() ? Instruments[instr] : nullptr;
  1171. const ModSample *pSmp = &Samples[instr];
  1172. const auto oldInsVol = chn.nInsVol;
  1173. ModCommand::NOTE note = chn.nNewNote;
  1174. if(note == NOTE_NONE && m_playBehaviour[kITInstrWithoutNote]) return;
  1175. if(pIns != nullptr && ModCommand::IsNote(note))
  1176. {
  1177. // Impulse Tracker ignores empty slots.
  1178. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended.
  1179. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it
  1180. if(pIns->Keyboard[note - NOTE_MIN] == 0 && m_playBehaviour[kITEmptyNoteMapSlot] && !pIns->HasValidMIDIChannel())
  1181. {
  1182. chn.pModInstrument = pIns;
  1183. return;
  1184. }
  1185. if(pIns->NoteMap[note - NOTE_MIN] > NOTE_MAX) return;
  1186. uint32 n = pIns->Keyboard[note - NOTE_MIN];
  1187. pSmp = ((n) && (n < MAX_SAMPLES)) ? &Samples[n] : nullptr;
  1188. } else if(GetNumInstruments())
  1189. {
  1190. // No valid instrument, or not a valid note.
  1191. if (note >= NOTE_MIN_SPECIAL) return;
  1192. if(m_playBehaviour[kITEmptyNoteMapSlot] && (pIns == nullptr || !pIns->HasValidMIDIChannel()))
  1193. {
  1194. // Impulse Tracker ignores empty slots.
  1195. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended.
  1196. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it
  1197. chn.pModInstrument = nullptr;
  1198. chn.nNewIns = 0;
  1199. return;
  1200. }
  1201. pSmp = nullptr;
  1202. }
  1203. bool returnAfterVolumeAdjust = false;
  1204. // instrumentChanged is used for IT carry-on env option
  1205. bool instrumentChanged = (pIns != chn.pModInstrument);
  1206. const bool sampleChanged = (chn.pModSample != nullptr) && (pSmp != chn.pModSample);
  1207. const bool newTuning = (GetType() == MOD_TYPE_MPT && pIns && pIns->pTuning);
  1208. if(!bPorta || instrumentChanged || sampleChanged)
  1209. chn.microTuning = 0;
  1210. // Playback behavior change for MPT: With portamento don't change sample if it is in
  1211. // the same instrument as previous sample.
  1212. if(bPorta && newTuning && pIns == chn.pModInstrument && sampleChanged)
  1213. return;
  1214. if(sampleChanged && bPorta)
  1215. {
  1216. // IT compatibility: No sample change (also within multi-sample instruments) during portamento when using Compatible Gxx.
  1217. // Test case: PortaInsNumCompat.it, PortaSampleCompat.it, PortaCutCompat.it
  1218. if(m_playBehaviour[kITPortamentoInstrument] && m_SongFlags[SONG_ITCOMPATGXX] && !chn.increment.IsZero())
  1219. {
  1220. pSmp = chn.pModSample;
  1221. }
  1222. // Special XM hack (also applies to MOD / S3M, except when playing IT-style S3Ms, such as k_vision.s3m)
  1223. // Test case: PortaSmpChange.mod, PortaSmpChange.s3m, PortaSwap.s3m
  1224. if((!instrumentChanged && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)) && pIns)
  1225. || (GetType() == MOD_TYPE_PLM)
  1226. || (GetType() == MOD_TYPE_MOD && chn.IsSamplePlaying())
  1227. || (m_playBehaviour[kST3PortaSampleChange] && chn.IsSamplePlaying()))
  1228. {
  1229. // FT2 doesn't change the sample in this case,
  1230. // but still uses the sample info from the old one (bug?)
  1231. returnAfterVolumeAdjust = true;
  1232. }
  1233. }
  1234. // IT compatibility: A lone instrument number should only reset sample properties to those of the corresponding sample in instrument mode.
  1235. // C#5 01 ... <-- sample 1
  1236. // C-5 .. g02 <-- sample 2
  1237. // ... 01 ... <-- still sample 1, but with properties of sample 2
  1238. // In the above example, no sample change happens on the second row. In the third row, sample 1 keeps playing but with the
  1239. // volume and panning properties of sample 2.
  1240. // Test case: InstrAfterMultisamplePorta.it
  1241. if(m_nInstruments && !instrumentChanged && sampleChanged && chn.pCurrentSample != nullptr && m_playBehaviour[kITMultiSampleInstrumentNumber] && !chn.rowCommand.IsNote())
  1242. {
  1243. returnAfterVolumeAdjust = true;
  1244. }
  1245. // IT Compatibility: Envelope pickup after SCx cut (but don't do this when working with plugins, or else envelope carry stops working)
  1246. // Test case: cut-carry.it
  1247. if(!chn.IsSamplePlaying() && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (!pIns || !pIns->HasValidMIDIChannel()))
  1248. {
  1249. instrumentChanged = true;
  1250. }
  1251. // FT2 compatibility: new instrument + portamento = ignore new instrument number, but reload old instrument settings (the world of XM is upside down...)
  1252. // And this does *not* happen if volume column portamento is used together with note delay... (handled in ProcessEffects(), where all the other note delay stuff is.)
  1253. // Test case: porta-delay.xm, SamplePortaInInstrument.xm
  1254. if((instrumentChanged || sampleChanged) && bPorta && m_playBehaviour[kFT2PortaIgnoreInstr] && (chn.pModInstrument != nullptr || chn.pModSample != nullptr))
  1255. {
  1256. pIns = chn.pModInstrument;
  1257. pSmp = chn.pModSample;
  1258. instrumentChanged = false;
  1259. } else
  1260. {
  1261. chn.pModInstrument = pIns;
  1262. }
  1263. // Update Volume
  1264. if (bUpdVol && (!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M)) || ((pSmp != nullptr && pSmp->HasSampleData()) || chn.HasMIDIOutput())))
  1265. {
  1266. if(pSmp)
  1267. {
  1268. if(!pSmp->uFlags[SMP_NODEFAULTVOLUME])
  1269. chn.nVolume = pSmp->nVolume;
  1270. } else if(pIns && pIns->nMixPlug)
  1271. {
  1272. chn.nVolume = chn.GetVSTVolume();
  1273. } else
  1274. {
  1275. chn.nVolume = 0;
  1276. }
  1277. }
  1278. if(returnAfterVolumeAdjust && sampleChanged && pSmp != nullptr)
  1279. {
  1280. // ProTracker applies new instrument's finetune but keeps the old sample playing.
  1281. // Test case: PortaSwapPT.mod
  1282. if(m_playBehaviour[kMODSampleSwap])
  1283. chn.nFineTune = pSmp->nFineTune;
  1284. // ST3 does it similarly for middle-C speed.
  1285. // Test case: PortaSwap.s3m, SampleSwap.s3m
  1286. if(GetType() == MOD_TYPE_S3M && pSmp->HasSampleData())
  1287. chn.nC5Speed = pSmp->nC5Speed;
  1288. }
  1289. if(returnAfterVolumeAdjust) return;
  1290. // Instrument adjust
  1291. chn.nNewIns = 0;
  1292. // IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes s7xinsnum.it).
  1293. if (pIns && ((!m_playBehaviour[kITNNAReset] && pSmp) || pIns->nMixPlug || instrumentChanged))
  1294. chn.nNNA = pIns->nNNA;
  1295. // Update volume
  1296. chn.UpdateInstrumentVolume(pSmp, pIns);
  1297. // Update panning
  1298. // FT2 compatibility: Only reset panning on instrument numbers, not notes (bUpdVol condition)
  1299. // Test case: PanMemory.xm
  1300. // IT compatibility: Sample and instrument panning is only applied on note change, not instrument change
  1301. // Test case: PanReset.it
  1302. if((bUpdVol || !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))) && !m_playBehaviour[kITPanningReset])
  1303. {
  1304. ApplyInstrumentPanning(chn, pIns, pSmp);
  1305. }
  1306. // Reset envelopes
  1307. if(bResetEnv)
  1308. {
  1309. // Blurb by Storlek (from the SchismTracker code):
  1310. // Conditions experimentally determined to cause envelope reset in Impulse Tracker:
  1311. // - no note currently playing (of course)
  1312. // - note given, no portamento
  1313. // - instrument number given, portamento, compat gxx enabled
  1314. // - instrument number given, no portamento, after keyoff, old effects enabled
  1315. // If someone can enlighten me to what the logic really is here, I'd appreciate it.
  1316. // Seems like it's just a total mess though, probably to get XMs to play right.
  1317. bool reset, resetAlways;
  1318. // IT Compatibility: Envelope reset
  1319. // Test case: EnvReset.it
  1320. if(m_playBehaviour[kITEnvelopeReset])
  1321. {
  1322. const bool insNumber = (instr != 0);
  1323. reset = (!chn.nLength
  1324. || (insNumber && bPorta && m_SongFlags[SONG_ITCOMPATGXX])
  1325. || (insNumber && !bPorta && chn.dwFlags[CHN_NOTEFADE | CHN_KEYOFF] && m_SongFlags[SONG_ITOLDEFFECTS]));
  1326. // NOTE: IT2.14 with SB/GUS/etc. output is different. We are going after IT's WAV writer here.
  1327. // For SB/GUS/etc. emulation, envelope carry should only apply when the NNA isn't set to "Note Cut".
  1328. // Test case: CarryNNA.it
  1329. resetAlways = (!chn.nFadeOutVol || instrumentChanged || chn.dwFlags[CHN_KEYOFF]);
  1330. } else
  1331. {
  1332. reset = (!bPorta || !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) || m_SongFlags[SONG_ITCOMPATGXX]
  1333. || !chn.nLength || (chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol));
  1334. resetAlways = !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) || instrumentChanged || pIns == nullptr || chn.dwFlags[CHN_KEYOFF | CHN_NOTEFADE];
  1335. }
  1336. if(reset)
  1337. {
  1338. chn.dwFlags.set(CHN_FASTVOLRAMP);
  1339. if(pIns != nullptr)
  1340. {
  1341. if(resetAlways)
  1342. {
  1343. chn.ResetEnvelopes();
  1344. } else
  1345. {
  1346. if(!pIns->VolEnv.dwFlags[ENV_CARRY]) chn.VolEnv.Reset();
  1347. if(!pIns->PanEnv.dwFlags[ENV_CARRY]) chn.PanEnv.Reset();
  1348. if(!pIns->PitchEnv.dwFlags[ENV_CARRY]) chn.PitchEnv.Reset();
  1349. }
  1350. }
  1351. // IT Compatibility: Autovibrato reset
  1352. if(!m_playBehaviour[kITVibratoTremoloPanbrello])
  1353. {
  1354. chn.nAutoVibDepth = 0;
  1355. chn.nAutoVibPos = 0;
  1356. }
  1357. } else if(pIns != nullptr && !pIns->VolEnv.dwFlags[ENV_ENABLED])
  1358. {
  1359. if(m_playBehaviour[kITPortamentoInstrument])
  1360. {
  1361. chn.VolEnv.Reset();
  1362. } else
  1363. {
  1364. chn.ResetEnvelopes();
  1365. }
  1366. }
  1367. }
  1368. // Invalid sample ?
  1369. if(pSmp == nullptr && (pIns == nullptr || !pIns->HasValidMIDIChannel()))
  1370. {
  1371. chn.pModSample = nullptr;
  1372. chn.nInsVol = 0;
  1373. return;
  1374. }
  1375. // Tone-Portamento doesn't reset the pingpong direction flag
  1376. if(bPorta && pSmp == chn.pModSample && pSmp != nullptr)
  1377. {
  1378. // If channel length is 0, we cut a previous sample using SCx. In that case, we have to update sample length, loop points, etc...
  1379. if(GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT) && chn.nLength != 0)
  1380. return;
  1381. // FT2 compatibility: Do not reset key-off status on portamento without instrument number
  1382. // Test case: Off-Porta.xm
  1383. if(GetType() != MOD_TYPE_XM || !m_playBehaviour[kITFT2DontResetNoteOffOnPorta] || chn.rowCommand.instr != 0)
  1384. chn.dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE);
  1385. chn.dwFlags = (chn.dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG));
  1386. } else //if(!instrumentChanged || chn.rowCommand.instr != 0 || !IsCompatibleMode(TRK_FASTTRACKER2)) // SampleChange.xm?
  1387. {
  1388. chn.dwFlags.reset(CHN_KEYOFF | CHN_NOTEFADE);
  1389. // IT compatibility: Don't change bidi loop direction when no sample nor instrument is changed.
  1390. if((m_playBehaviour[kITPingPongNoReset] || !(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) && pSmp == chn.pModSample && !instrumentChanged)
  1391. chn.dwFlags = (chn.dwFlags & (CHN_CHANNELFLAGS | CHN_PINGPONGFLAG));
  1392. else
  1393. chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS);
  1394. if(pIns)
  1395. {
  1396. // Copy envelope flags (we actually only need the "enabled" and "pitch" flag)
  1397. chn.VolEnv.flags = pIns->VolEnv.dwFlags;
  1398. chn.PanEnv.flags = pIns->PanEnv.dwFlags;
  1399. chn.PitchEnv.flags = pIns->PitchEnv.dwFlags;
  1400. // A cutoff frequency of 0 should not be reset just because the filter envelope is enabled.
  1401. // Test case: FilterEnvReset.it
  1402. if((pIns->PitchEnv.dwFlags & (ENV_ENABLED | ENV_FILTER)) == (ENV_ENABLED | ENV_FILTER) && !m_playBehaviour[kITFilterBehaviour])
  1403. {
  1404. if(!chn.nCutOff) chn.nCutOff = 0x7F;
  1405. }
  1406. if(pIns->IsCutoffEnabled()) chn.nCutOff = pIns->GetCutoff();
  1407. if(pIns->IsResonanceEnabled()) chn.nResonance = pIns->GetResonance();
  1408. }
  1409. }
  1410. if(pSmp == nullptr)
  1411. {
  1412. chn.pModSample = nullptr;
  1413. chn.nLength = 0;
  1414. return;
  1415. }
  1416. if(bPorta && chn.nLength == 0 && (m_playBehaviour[kFT2PortaNoNote] || m_playBehaviour[kITPortaNoNote]))
  1417. {
  1418. // IT/FT2 compatibility: If the note just stopped on the previous tick, prevent it from restarting.
  1419. // Test cases: PortaJustStoppedNote.xm, PortaJustStoppedNote.it
  1420. chn.increment.Set(0);
  1421. }
  1422. // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
  1423. // If the instrument changes, keep playing the previous sample, but load the new instrument's envelopes.
  1424. // Test case: ResetEnvNoteOffOldFx.it
  1425. if(chn.rowCommand.note == NOTE_KEYOFF && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && sampleChanged)
  1426. {
  1427. if(chn.pModSample)
  1428. {
  1429. chn.dwFlags |= (chn.pModSample->uFlags & CHN_SAMPLEFLAGS);
  1430. }
  1431. chn.nInsVol = oldInsVol;
  1432. chn.nVolume = pSmp->nVolume;
  1433. if(pSmp->uFlags[CHN_PANNING]) chn.SetInstrumentPan(pSmp->nPan, *this);
  1434. return;
  1435. }
  1436. chn.pModSample = pSmp;
  1437. chn.nLength = pSmp->nLength;
  1438. chn.nLoopStart = pSmp->nLoopStart;
  1439. chn.nLoopEnd = pSmp->nLoopEnd;
  1440. // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end)
  1441. if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) chn.nLoopEnd = pSmp->nLength;
  1442. chn.dwFlags |= (pSmp->uFlags & CHN_SAMPLEFLAGS);
  1443. // IT Compatibility: Autovibrato reset
  1444. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  1445. {
  1446. chn.nAutoVibDepth = 0;
  1447. chn.nAutoVibPos = 0;
  1448. }
  1449. if(newTuning)
  1450. {
  1451. chn.nC5Speed = pSmp->nC5Speed;
  1452. chn.m_CalculateFreq = true;
  1453. chn.nFineTune = 0;
  1454. } else if(!bPorta || sampleChanged || !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM)))
  1455. {
  1456. // Don't reset finetune changed by "set finetune" command.
  1457. // Test case: finetune.xm, finetune.mod
  1458. // But *do* change the finetune if we switch to a different sample, to fix
  1459. // Miranda`s axe by Jamson (jam007.xm).
  1460. chn.nC5Speed = pSmp->nC5Speed;
  1461. chn.nFineTune = pSmp->nFineTune;
  1462. }
  1463. chn.nTranspose = UseFinetuneAndTranspose() ? pSmp->RelativeTone : 0;
  1464. // FT2 compatibility: Don't reset portamento target with new instrument numbers.
  1465. // Test case: Porta-Pickup.xm
  1466. // ProTracker does the same.
  1467. // Test case: PortaTarget.mod
  1468. if(!m_playBehaviour[kFT2PortaTargetNoReset] && GetType() != MOD_TYPE_MOD)
  1469. {
  1470. chn.nPortamentoDest = 0;
  1471. }
  1472. chn.m_PortamentoFineSteps = 0;
  1473. if(chn.dwFlags[CHN_SUSTAINLOOP])
  1474. {
  1475. chn.nLoopStart = pSmp->nSustainStart;
  1476. chn.nLoopEnd = pSmp->nSustainEnd;
  1477. if(chn.dwFlags[CHN_PINGPONGSUSTAIN]) chn.dwFlags.set(CHN_PINGPONGLOOP);
  1478. chn.dwFlags.set(CHN_LOOP);
  1479. }
  1480. if(chn.dwFlags[CHN_LOOP] && chn.nLoopEnd < chn.nLength) chn.nLength = chn.nLoopEnd;
  1481. // Fix sample position on instrument change. This is needed for IT "on the fly" sample change.
  1482. // XXX is this actually called? In ProcessEffects(), a note-on effect is emulated if there's an on the fly sample change!
  1483. if(chn.position.GetUInt() >= chn.nLength)
  1484. {
  1485. if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)))
  1486. {
  1487. chn.position.Set(0);
  1488. }
  1489. }
  1490. }
  1491. void CSoundFile::NoteChange(ModChannel &chn, int note, bool bPorta, bool bResetEnv, bool bManual, CHANNELINDEX channelHint) const
  1492. {
  1493. if(note < NOTE_MIN)
  1494. return;
  1495. const int origNote = note;
  1496. const ModSample *pSmp = chn.pModSample;
  1497. const ModInstrument *pIns = chn.pModInstrument;
  1498. const bool newTuning = (GetType() == MOD_TYPE_MPT && pIns != nullptr && pIns->pTuning);
  1499. // save the note that's actually used, as it's necessary to properly calculate PPS and stuff
  1500. const int realnote = note;
  1501. if((pIns) && (note - NOTE_MIN < (int)std::size(pIns->Keyboard)))
  1502. {
  1503. uint32 n = pIns->Keyboard[note - NOTE_MIN];
  1504. if((n) && (n < MAX_SAMPLES))
  1505. {
  1506. pSmp = &Samples[n];
  1507. } else if(m_playBehaviour[kITEmptyNoteMapSlot] && !chn.HasMIDIOutput())
  1508. {
  1509. // Impulse Tracker ignores empty slots.
  1510. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended.
  1511. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it
  1512. return;
  1513. }
  1514. note = pIns->NoteMap[note - NOTE_MIN];
  1515. }
  1516. // Key Off
  1517. if(note > NOTE_MAX)
  1518. {
  1519. // Key Off (+ Invalid Note for XM - TODO is this correct?)
  1520. if(note == NOTE_KEYOFF || !(GetType() & (MOD_TYPE_IT|MOD_TYPE_MPT)))
  1521. {
  1522. KeyOff(chn);
  1523. // IT compatibility: Note-off + instrument releases sample sustain but does not release envelopes or fade the instrument
  1524. // Test case: noteoff3.it, ResetEnvNoteOffOldFx2.it
  1525. if(!bPorta && m_playBehaviour[kITInstrWithNoteOffOldEffects] && m_SongFlags[SONG_ITOLDEFFECTS] && chn.rowCommand.instr)
  1526. chn.dwFlags.reset(CHN_NOTEFADE | CHN_KEYOFF);
  1527. } else // Invalid Note -> Note Fade
  1528. {
  1529. if(/*note == NOTE_FADE && */ GetNumInstruments())
  1530. chn.dwFlags.set(CHN_NOTEFADE);
  1531. }
  1532. // Note Cut
  1533. if (note == NOTE_NOTECUT)
  1534. {
  1535. if(chn.dwFlags[CHN_ADLIB] && GetType() == MOD_TYPE_S3M)
  1536. {
  1537. // OPL voices are not cut but enter the release portion of their envelope
  1538. // In S3M we can still modify the volume after note-off, in legacy MPTM mode we can't
  1539. chn.dwFlags.set(CHN_KEYOFF);
  1540. } else
  1541. {
  1542. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  1543. // IT compatibility: Stopping sample playback by setting sample increment to 0 rather than volume
  1544. // Test case: NoteOffInstr.it
  1545. if ((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) || (m_nInstruments != 0 && !m_playBehaviour[kITInstrWithNoteOff])) chn.nVolume = 0;
  1546. if (m_playBehaviour[kITInstrWithNoteOff]) chn.increment.Set(0);
  1547. chn.nFadeOutVol = 0;
  1548. }
  1549. }
  1550. // IT compatibility tentative fix: Clear channel note memory (TRANCE_N.IT by A3F).
  1551. if(m_playBehaviour[kITClearOldNoteAfterCut])
  1552. {
  1553. chn.nNote = chn.nNewNote = NOTE_NONE;
  1554. }
  1555. return;
  1556. }
  1557. if(newTuning)
  1558. {
  1559. if(!bPorta || chn.nNote == NOTE_NONE)
  1560. chn.nPortamentoDest = 0;
  1561. else
  1562. {
  1563. chn.nPortamentoDest = pIns->pTuning->GetStepDistance(chn.nNote, chn.m_PortamentoFineSteps, static_cast<Tuning::NOTEINDEXTYPE>(note), 0);
  1564. //Here chn.nPortamentoDest means 'steps to slide'.
  1565. chn.m_PortamentoFineSteps = -chn.nPortamentoDest;
  1566. }
  1567. }
  1568. if(!bPorta && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MED | MOD_TYPE_MT2)))
  1569. {
  1570. if(pSmp)
  1571. {
  1572. chn.nTranspose = pSmp->RelativeTone;
  1573. chn.nFineTune = pSmp->nFineTune;
  1574. }
  1575. }
  1576. // IT Compatibility: Update multisample instruments frequency even if instrument is not specified (fixes the guitars in spx-shuttledeparture.it)
  1577. // Test case: freqreset-noins.it
  1578. if(!bPorta && pSmp && m_playBehaviour[kITMultiSampleBehaviour])
  1579. chn.nC5Speed = pSmp->nC5Speed;
  1580. if(bPorta && !chn.IsSamplePlaying())
  1581. {
  1582. if(m_playBehaviour[kFT2PortaNoNote])
  1583. {
  1584. // FT2 Compatibility: Ignore notes with portamento if there was no note playing.
  1585. // Test case: 3xx-no-old-samp.xm
  1586. chn.nPeriod = 0;
  1587. return;
  1588. } else if(m_playBehaviour[kITPortaNoNote])
  1589. {
  1590. // IT Compatibility: Ignore portamento command if no note was playing (e.g. if a previous note has faded out).
  1591. // Test case: Fade-Porta.it
  1592. bPorta = false;
  1593. }
  1594. }
  1595. if(UseFinetuneAndTranspose())
  1596. {
  1597. note += chn.nTranspose;
  1598. // RealNote = PatternNote + RelativeTone; (0..118, 0 = C-0, 118 = A#9)
  1599. Limit(note, NOTE_MIN + 11, NOTE_MIN + 130); // 119 possible notes
  1600. } else
  1601. {
  1602. Limit(note, NOTE_MIN, NOTE_MAX);
  1603. }
  1604. if(m_playBehaviour[kITRealNoteMapping])
  1605. {
  1606. // need to memorize the original note for various effects (e.g. PPS)
  1607. chn.nNote = static_cast<ModCommand::NOTE>(Clamp(realnote, NOTE_MIN, NOTE_MAX));
  1608. } else
  1609. {
  1610. chn.nNote = static_cast<ModCommand::NOTE>(note);
  1611. }
  1612. chn.m_CalculateFreq = true;
  1613. chn.isPaused = false;
  1614. if ((!bPorta) || (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT)))
  1615. chn.nNewIns = 0;
  1616. uint32 period = GetPeriodFromNote(note, chn.nFineTune, chn.nC5Speed);
  1617. chn.nPanbrelloOffset = 0;
  1618. // IT compatibility: Sample and instrument panning is only applied on note change, not instrument change
  1619. // Test case: PanReset.it
  1620. if(m_playBehaviour[kITPanningReset])
  1621. ApplyInstrumentPanning(chn, pIns, pSmp);
  1622. // IT compatibility: Pitch/Pan Separation can be overriden by panning commands, and shouldn't be affected by note-off commands
  1623. // Test case: PitchPanReset.it
  1624. if(m_playBehaviour[kITPitchPanSeparation] && pIns && pIns->nPPS)
  1625. {
  1626. if(!chn.nRestorePanOnNewNote)
  1627. chn.nRestorePanOnNewNote = static_cast<uint16>(chn.nPan + 1);
  1628. ProcessPitchPanSeparation(chn.nPan, origNote, *pIns);
  1629. }
  1630. if(bResetEnv && !bPorta)
  1631. {
  1632. chn.nVolSwing = chn.nPanSwing = 0;
  1633. chn.nResSwing = chn.nCutSwing = 0;
  1634. if(pIns)
  1635. {
  1636. // IT Compatiblity: NNA is reset on every note change, not every instrument change (fixes spx-farspacedance.it).
  1637. if(m_playBehaviour[kITNNAReset]) chn.nNNA = pIns->nNNA;
  1638. if(!pIns->VolEnv.dwFlags[ENV_CARRY]) chn.VolEnv.Reset();
  1639. if(!pIns->PanEnv.dwFlags[ENV_CARRY]) chn.PanEnv.Reset();
  1640. if(!pIns->PitchEnv.dwFlags[ENV_CARRY]) chn.PitchEnv.Reset();
  1641. // Volume Swing
  1642. if(pIns->nVolSwing)
  1643. {
  1644. chn.nVolSwing = static_cast<int16>(((mpt::random<int8>(AccessPRNG()) * pIns->nVolSwing) / 64 + 1) * (m_playBehaviour[kITSwingBehaviour] ? chn.nInsVol : ((chn.nVolume + 1) / 2)) / 199);
  1645. }
  1646. // Pan Swing
  1647. if(pIns->nPanSwing)
  1648. {
  1649. chn.nPanSwing = static_cast<int16>(((mpt::random<int8>(AccessPRNG()) * pIns->nPanSwing * 4) / 128));
  1650. if(!m_playBehaviour[kITSwingBehaviour] && chn.nRestorePanOnNewNote == 0)
  1651. {
  1652. chn.nRestorePanOnNewNote = static_cast<uint16>(chn.nPan + 1);
  1653. }
  1654. }
  1655. // Cutoff Swing
  1656. if(pIns->nCutSwing)
  1657. {
  1658. int32 d = ((int32)pIns->nCutSwing * (int32)(static_cast<int32>(mpt::random<int8>(AccessPRNG())) + 1)) / 128;
  1659. chn.nCutSwing = static_cast<int16>((d * chn.nCutOff + 1) / 128);
  1660. chn.nRestoreCutoffOnNewNote = chn.nCutOff + 1;
  1661. }
  1662. // Resonance Swing
  1663. if(pIns->nResSwing)
  1664. {
  1665. int32 d = ((int32)pIns->nResSwing * (int32)(static_cast<int32>(mpt::random<int8>(AccessPRNG())) + 1)) / 128;
  1666. chn.nResSwing = static_cast<int16>((d * chn.nResonance + 1) / 128);
  1667. chn.nRestoreResonanceOnNewNote = chn.nResonance + 1;
  1668. }
  1669. }
  1670. }
  1671. if(!pSmp) return;
  1672. if(period)
  1673. {
  1674. if((!bPorta) || (!chn.nPeriod)) chn.nPeriod = period;
  1675. if(!newTuning)
  1676. {
  1677. // FT2 compatibility: Don't reset portamento target with new notes.
  1678. // Test case: Porta-Pickup.xm
  1679. // ProTracker does the same.
  1680. // Test case: PortaTarget.mod
  1681. // IT compatibility: Portamento target is completely cleared with new notes.
  1682. // Test case: PortaReset.it
  1683. if(bPorta || !(m_playBehaviour[kFT2PortaTargetNoReset] || m_playBehaviour[kITClearPortaTarget] || GetType() == MOD_TYPE_MOD))
  1684. {
  1685. chn.nPortamentoDest = period;
  1686. chn.portaTargetReached = false;
  1687. }
  1688. }
  1689. if(!bPorta || (!chn.nLength && !(GetType() & MOD_TYPE_S3M)))
  1690. {
  1691. chn.pModSample = pSmp;
  1692. chn.nLength = pSmp->nLength;
  1693. chn.nLoopEnd = pSmp->nLength;
  1694. chn.nLoopStart = 0;
  1695. chn.position.Set(0);
  1696. if((m_SongFlags[SONG_PT_MODE] || m_playBehaviour[kST3OffsetWithoutInstrument]) && !chn.rowCommand.instr)
  1697. {
  1698. chn.position.SetInt(std::min(chn.prevNoteOffset, chn.nLength - SmpLength(1)));
  1699. } else
  1700. {
  1701. chn.prevNoteOffset = 0;
  1702. }
  1703. chn.dwFlags = (chn.dwFlags & CHN_CHANNELFLAGS) | (pSmp->uFlags & CHN_SAMPLEFLAGS);
  1704. chn.dwFlags.reset(CHN_PORTAMENTO);
  1705. if(chn.dwFlags[CHN_SUSTAINLOOP])
  1706. {
  1707. chn.nLoopStart = pSmp->nSustainStart;
  1708. chn.nLoopEnd = pSmp->nSustainEnd;
  1709. chn.dwFlags.set(CHN_PINGPONGLOOP, chn.dwFlags[CHN_PINGPONGSUSTAIN]);
  1710. chn.dwFlags.set(CHN_LOOP);
  1711. if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd;
  1712. } else if(chn.dwFlags[CHN_LOOP])
  1713. {
  1714. chn.nLoopStart = pSmp->nLoopStart;
  1715. chn.nLoopEnd = pSmp->nLoopEnd;
  1716. if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd;
  1717. }
  1718. // ProTracker "oneshot" loops (if loop start is 0, play the whole sample once and then repeat until loop end)
  1719. if(m_playBehaviour[kMODOneShotLoops] && chn.nLoopStart == 0) chn.nLoopEnd = chn.nLength = pSmp->nLength;
  1720. if(chn.dwFlags[CHN_REVERSE] && chn.nLength > 0)
  1721. {
  1722. chn.dwFlags.set(CHN_PINGPONGFLAG);
  1723. chn.position.SetInt(chn.nLength - 1);
  1724. }
  1725. // Handle "retrigger" waveform type
  1726. if(chn.nVibratoType < 4)
  1727. {
  1728. // IT Compatibilty: Slightly different waveform offsets (why does MPT have two different offsets here with IT old effects enabled and disabled?)
  1729. if(!m_playBehaviour[kITVibratoTremoloPanbrello] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && !m_SongFlags[SONG_ITOLDEFFECTS])
  1730. chn.nVibratoPos = 0x10;
  1731. else if(GetType() == MOD_TYPE_MTM)
  1732. chn.nVibratoPos = 0x20;
  1733. else if(!(GetType() & (MOD_TYPE_DIGI | MOD_TYPE_DBM)))
  1734. chn.nVibratoPos = 0;
  1735. }
  1736. // IT Compatibility: No "retrigger" waveform here
  1737. if(!m_playBehaviour[kITVibratoTremoloPanbrello] && chn.nTremoloType < 4)
  1738. {
  1739. chn.nTremoloPos = 0;
  1740. }
  1741. }
  1742. if(chn.position.GetUInt() >= chn.nLength) chn.position.SetInt(chn.nLoopStart);
  1743. } else
  1744. {
  1745. bPorta = false;
  1746. }
  1747. if (!bPorta
  1748. || (!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)))
  1749. || (chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol)
  1750. || (m_SongFlags[SONG_ITCOMPATGXX] && chn.rowCommand.instr != 0))
  1751. {
  1752. if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_DBM)) && chn.dwFlags[CHN_NOTEFADE] && !chn.nFadeOutVol)
  1753. {
  1754. chn.ResetEnvelopes();
  1755. // IT Compatibility: Autovibrato reset
  1756. if(!m_playBehaviour[kITVibratoTremoloPanbrello])
  1757. {
  1758. chn.nAutoVibDepth = 0;
  1759. chn.nAutoVibPos = 0;
  1760. }
  1761. chn.dwFlags.reset(CHN_NOTEFADE);
  1762. chn.nFadeOutVol = 65536;
  1763. }
  1764. if ((!bPorta) || (!m_SongFlags[SONG_ITCOMPATGXX]) || (chn.rowCommand.instr))
  1765. {
  1766. if ((!(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) || (chn.rowCommand.instr))
  1767. {
  1768. chn.dwFlags.reset(CHN_NOTEFADE);
  1769. chn.nFadeOutVol = 65536;
  1770. }
  1771. }
  1772. }
  1773. // IT compatibility: Don't reset key-off flag on porta notes unless Compat Gxx is enabled.
  1774. // Test case: Off-Porta.it, Off-Porta-CompatGxx.it, Off-Porta.xm
  1775. if(m_playBehaviour[kITFT2DontResetNoteOffOnPorta] && bPorta && (!m_SongFlags[SONG_ITCOMPATGXX] || chn.rowCommand.instr == 0))
  1776. chn.dwFlags.reset(CHN_EXTRALOUD);
  1777. else
  1778. chn.dwFlags.reset(CHN_EXTRALOUD | CHN_KEYOFF);
  1779. // Enable Ramping
  1780. if(!bPorta)
  1781. {
  1782. chn.nLeftVU = chn.nRightVU = 0xFF;
  1783. chn.dwFlags.reset(CHN_FILTER);
  1784. chn.dwFlags.set(CHN_FASTVOLRAMP);
  1785. // IT compatibility 15. Retrigger is reset in RetrigNote (Tremor doesn't store anything here, so we just don't reset this as well)
  1786. if(!m_playBehaviour[kITRetrigger] && !m_playBehaviour[kITTremor])
  1787. {
  1788. // FT2 compatibility: Retrigger is reset in RetrigNote, tremor in ProcessEffects
  1789. if(!m_playBehaviour[kFT2Retrigger] && !m_playBehaviour[kFT2Tremor])
  1790. {
  1791. chn.nRetrigCount = 0;
  1792. chn.nTremorCount = 0;
  1793. }
  1794. }
  1795. if(bResetEnv)
  1796. {
  1797. chn.nAutoVibDepth = 0;
  1798. chn.nAutoVibPos = 0;
  1799. }
  1800. chn.rightVol = chn.leftVol = 0;
  1801. bool useFilter = !m_SongFlags[SONG_MPTFILTERMODE];
  1802. // Setup Initial Filter for this note
  1803. if(pIns)
  1804. {
  1805. if(pIns->IsResonanceEnabled())
  1806. {
  1807. chn.nResonance = pIns->GetResonance();
  1808. useFilter = true;
  1809. }
  1810. if(pIns->IsCutoffEnabled())
  1811. {
  1812. chn.nCutOff = pIns->GetCutoff();
  1813. useFilter = true;
  1814. }
  1815. if(useFilter && (pIns->filterMode != FilterMode::Unchanged))
  1816. {
  1817. chn.nFilterMode = pIns->filterMode;
  1818. }
  1819. } else
  1820. {
  1821. chn.nVolSwing = chn.nPanSwing = 0;
  1822. chn.nCutSwing = chn.nResSwing = 0;
  1823. }
  1824. if((chn.nCutOff < 0x7F || m_playBehaviour[kITFilterBehaviour]) && useFilter)
  1825. {
  1826. int cutoff = SetupChannelFilter(chn, true);
  1827. if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl && channelHint != CHANNELINDEX_INVALID)
  1828. m_opl->Volume(channelHint, chn.nCutOff / 2u, true);
  1829. }
  1830. if(chn.dwFlags[CHN_ADLIB] && m_opl && channelHint != CHANNELINDEX_INVALID)
  1831. {
  1832. // Test case: AdlibZeroVolumeNote.s3m
  1833. if(m_playBehaviour[kOPLNoteOffOnNoteChange])
  1834. m_opl->NoteOff(channelHint);
  1835. else if(m_playBehaviour[kOPLNoteStopWith0Hz])
  1836. m_opl->Frequency(channelHint, 0, true, false);
  1837. }
  1838. }
  1839. // Special case for MPT
  1840. if (bManual) chn.dwFlags.reset(CHN_MUTE);
  1841. if((chn.dwFlags[CHN_MUTE] && (m_MixerSettings.MixerFlags & SNDMIX_MUTECHNMODE))
  1842. || (chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_MUTE] && !bManual)
  1843. || (chn.pModInstrument != nullptr && chn.pModInstrument->dwFlags[INS_MUTE] && !bManual))
  1844. {
  1845. if (!bManual) chn.nPeriod = 0;
  1846. }
  1847. // Reset the Amiga resampler for this channel
  1848. if(!bPorta)
  1849. {
  1850. chn.paulaState.Reset();
  1851. }
  1852. }
  1853. // Apply sample or instrument panning
  1854. void CSoundFile::ApplyInstrumentPanning(ModChannel &chn, const ModInstrument *instr, const ModSample *smp) const
  1855. {
  1856. int32 newPan = int32_min;
  1857. // Default instrument panning
  1858. if(instr != nullptr && instr->dwFlags[INS_SETPANNING])
  1859. newPan = instr->nPan;
  1860. // Default sample panning
  1861. if(smp != nullptr && smp->uFlags[CHN_PANNING])
  1862. newPan = smp->nPan;
  1863. if(newPan != int32_min)
  1864. {
  1865. chn.SetInstrumentPan(newPan, *this);
  1866. // IT compatibility: Sample and instrument panning overrides channel surround status.
  1867. // Test case: SmpInsPanSurround.it
  1868. if(m_playBehaviour[kPanOverride] && !m_SongFlags[SONG_SURROUNDPAN])
  1869. {
  1870. chn.dwFlags.reset(CHN_SURROUND);
  1871. }
  1872. }
  1873. }
  1874. CHANNELINDEX CSoundFile::GetNNAChannel(CHANNELINDEX nChn) const
  1875. {
  1876. // Check for empty channel
  1877. for(CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++)
  1878. {
  1879. const ModChannel &c = m_PlayState.Chn[i];
  1880. // No sample and no plugin playing
  1881. if(!c.nLength && !c.HasMIDIOutput())
  1882. return i;
  1883. // Plugin channel with already released note
  1884. if(!c.nLength && c.dwFlags[CHN_KEYOFF | CHN_NOTEFADE])
  1885. return i;
  1886. // Stopped OPL channel
  1887. if(c.dwFlags[CHN_ADLIB] && (!m_opl || !m_opl->IsActive(i)))
  1888. return i;
  1889. }
  1890. uint32 vol = 0x800000;
  1891. if(nChn < MAX_CHANNELS)
  1892. {
  1893. const ModChannel &srcChn = m_PlayState.Chn[nChn];
  1894. if(!srcChn.nFadeOutVol && srcChn.nLength)
  1895. return CHANNELINDEX_INVALID;
  1896. vol = (srcChn.nRealVolume << 9) | srcChn.nVolume;
  1897. }
  1898. // All channels are used: check for lowest volume
  1899. CHANNELINDEX result = CHANNELINDEX_INVALID;
  1900. uint32 envpos = 0;
  1901. for(CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++)
  1902. {
  1903. const ModChannel &c = m_PlayState.Chn[i];
  1904. if(c.nLength && !c.nFadeOutVol)
  1905. return i;
  1906. // Use a combination of real volume [14 bit] (which includes volume envelopes, but also potentially global volume) and note volume [9 bit].
  1907. // Rationale: We need volume envelopes in case e.g. all NNA channels are playing at full volume but are looping on a 0-volume envelope node.
  1908. // But if global volume is not applied to master and the global volume temporarily drops to 0, we would kill arbitrary channels. Hence, add the note volume as well.
  1909. uint32 v = (c.nRealVolume << 9) | c.nVolume;
  1910. if(c.dwFlags[CHN_LOOP])
  1911. v /= 2;
  1912. if((v < vol) || ((v == vol) && (c.VolEnv.nEnvPosition > envpos)))
  1913. {
  1914. envpos = c.VolEnv.nEnvPosition;
  1915. vol = v;
  1916. result = i;
  1917. }
  1918. }
  1919. return result;
  1920. }
  1921. CHANNELINDEX CSoundFile::CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, bool forceCut)
  1922. {
  1923. ModChannel &srcChn = m_PlayState.Chn[nChn];
  1924. const ModInstrument *pIns = nullptr;
  1925. if(!ModCommand::IsNote(static_cast<ModCommand::NOTE>(note)))
  1926. return CHANNELINDEX_INVALID;
  1927. // Always NNA cut - using
  1928. if((!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_MT2)) || !m_nInstruments || forceCut) && !srcChn.HasMIDIOutput())
  1929. {
  1930. if(!srcChn.nLength || srcChn.dwFlags[CHN_MUTE] || !(srcChn.rightVol | srcChn.leftVol))
  1931. return CHANNELINDEX_INVALID;
  1932. if(srcChn.dwFlags[CHN_ADLIB] && m_opl)
  1933. {
  1934. m_opl->NoteCut(nChn, false);
  1935. return CHANNELINDEX_INVALID;
  1936. }
  1937. const CHANNELINDEX nnaChn = GetNNAChannel(nChn);
  1938. if(nnaChn == CHANNELINDEX_INVALID)
  1939. return CHANNELINDEX_INVALID;
  1940. ModChannel &chn = m_PlayState.Chn[nnaChn];
  1941. // Copy Channel
  1942. chn = srcChn;
  1943. chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_MUTE | CHN_PORTAMENTO);
  1944. chn.nPanbrelloOffset = 0;
  1945. chn.nMasterChn = nChn + 1;
  1946. chn.nCommand = CMD_NONE;
  1947. chn.rowCommand.Clear();
  1948. // Cut the note
  1949. chn.nFadeOutVol = 0;
  1950. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  1951. // Stop this channel
  1952. srcChn.nLength = 0;
  1953. srcChn.position.Set(0);
  1954. srcChn.nROfs = srcChn.nLOfs = 0;
  1955. srcChn.rightVol = srcChn.leftVol = 0;
  1956. return nnaChn;
  1957. }
  1958. if(instr > GetNumInstruments())
  1959. instr = 0;
  1960. const ModSample *pSample = srcChn.pModSample;
  1961. // If no instrument is given, assume previous instrument to still be valid.
  1962. // Test case: DNA-NoInstr.it
  1963. pIns = instr > 0 ? Instruments[instr] : srcChn.pModInstrument;
  1964. auto dnaNote = note;
  1965. if(pIns != nullptr)
  1966. {
  1967. auto smp = pIns->Keyboard[note - NOTE_MIN];
  1968. // IT compatibility: DCT = note uses pattern notes for comparison
  1969. // Note: This is not applied in case kITRealNoteMapping is not set to keep playback of legacy modules simple (chn.nNote is translated note in that case)
  1970. // Test case: dct_smp_note_test.it
  1971. if(!m_playBehaviour[kITDCTBehaviour] || !m_playBehaviour[kITRealNoteMapping])
  1972. dnaNote = pIns->NoteMap[note - NOTE_MIN];
  1973. if(smp > 0 && smp < MAX_SAMPLES)
  1974. {
  1975. pSample = &Samples[smp];
  1976. } else if(m_playBehaviour[kITEmptyNoteMapSlot] && !pIns->HasValidMIDIChannel())
  1977. {
  1978. // Impulse Tracker ignores empty slots.
  1979. // We won't ignore them if a plugin is assigned to this slot, so that VSTis still work as intended.
  1980. // Test case: emptyslot.it, PortaInsNum.it, gxsmp.it, gxsmp2.it
  1981. return CHANNELINDEX_INVALID;
  1982. }
  1983. }
  1984. if(srcChn.dwFlags[CHN_MUTE])
  1985. return CHANNELINDEX_INVALID;
  1986. for(CHANNELINDEX i = nChn; i < MAX_CHANNELS; i++)
  1987. {
  1988. // Only apply to background channels, or the same pattern channel
  1989. if(i < m_nChannels && i != nChn)
  1990. continue;
  1991. ModChannel &chn = m_PlayState.Chn[i];
  1992. bool applyDNAtoPlug = false;
  1993. if((chn.nMasterChn == nChn + 1 || i == nChn) && chn.pModInstrument != nullptr)
  1994. {
  1995. bool applyDNA = false;
  1996. // Duplicate Check Type
  1997. switch(chn.pModInstrument->nDCT)
  1998. {
  1999. case DuplicateCheckType::None:
  2000. break;
  2001. // Note
  2002. case DuplicateCheckType::Note:
  2003. if(dnaNote != NOTE_NONE && chn.nNote == dnaNote && pIns == chn.pModInstrument)
  2004. applyDNA = true;
  2005. if(pIns && pIns->nMixPlug)
  2006. applyDNAtoPlug = true;
  2007. break;
  2008. // Sample
  2009. case DuplicateCheckType::Sample:
  2010. // IT compatibility: DCT = sample only applies to same instrument
  2011. // Test case: dct_smp_note_test.it
  2012. if(pSample != nullptr && pSample == chn.pModSample && (pIns == chn.pModInstrument || !m_playBehaviour[kITDCTBehaviour]))
  2013. applyDNA = true;
  2014. break;
  2015. // Instrument
  2016. case DuplicateCheckType::Instrument:
  2017. if(pIns == chn.pModInstrument)
  2018. applyDNA = true;
  2019. if(pIns && pIns->nMixPlug)
  2020. applyDNAtoPlug = true;
  2021. break;
  2022. // Plugin
  2023. case DuplicateCheckType::Plugin:
  2024. if(pIns && (pIns->nMixPlug) && (pIns->nMixPlug == chn.pModInstrument->nMixPlug))
  2025. {
  2026. applyDNAtoPlug = true;
  2027. applyDNA = true;
  2028. }
  2029. break;
  2030. }
  2031. // Duplicate Note Action
  2032. if(applyDNA)
  2033. {
  2034. #ifndef NO_PLUGINS
  2035. if(applyDNAtoPlug && chn.nNote != NOTE_NONE)
  2036. {
  2037. switch(chn.pModInstrument->nDNA)
  2038. {
  2039. case DuplicateNoteAction::NoteCut:
  2040. case DuplicateNoteAction::NoteOff:
  2041. case DuplicateNoteAction::NoteFade:
  2042. // Switch off duplicated note played on this plugin
  2043. if(const auto oldNote = chn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]); oldNote != NOTE_NONE)
  2044. {
  2045. SendMIDINote(i, oldNote + NOTE_MAX_SPECIAL, 0);
  2046. chn.nArpeggioLastNote = NOTE_NONE;
  2047. chn.nNote = NOTE_NONE;
  2048. }
  2049. break;
  2050. }
  2051. }
  2052. #endif // NO_PLUGINS
  2053. switch(chn.pModInstrument->nDNA)
  2054. {
  2055. // Cut
  2056. case DuplicateNoteAction::NoteCut:
  2057. KeyOff(chn);
  2058. chn.nVolume = 0;
  2059. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2060. m_opl->NoteCut(i);
  2061. break;
  2062. // Note Off
  2063. case DuplicateNoteAction::NoteOff:
  2064. KeyOff(chn);
  2065. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2066. m_opl->NoteOff(i);
  2067. break;
  2068. // Note Fade
  2069. case DuplicateNoteAction::NoteFade:
  2070. chn.dwFlags.set(CHN_NOTEFADE);
  2071. if(chn.dwFlags[CHN_ADLIB] && m_opl && !m_playBehaviour[kOPLwithNNA])
  2072. m_opl->NoteOff(i);
  2073. break;
  2074. }
  2075. if(!chn.nVolume)
  2076. {
  2077. chn.nFadeOutVol = 0;
  2078. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  2079. }
  2080. }
  2081. }
  2082. }
  2083. // Do we need to apply New/Duplicate Note Action to a VSTi?
  2084. bool applyNNAtoPlug = false;
  2085. #ifndef NO_PLUGINS
  2086. IMixPlugin *pPlugin = nullptr;
  2087. if(srcChn.HasMIDIOutput() && ModCommand::IsNote(srcChn.nNote)) // instro sends to a midi chan
  2088. {
  2089. PLUGINDEX plugin = GetBestPlugin(m_PlayState, nChn, PrioritiseInstrument, RespectMutes);
  2090. if(plugin > 0 && plugin <= MAX_MIXPLUGINS)
  2091. {
  2092. pPlugin = m_MixPlugins[plugin - 1].pMixPlugin;
  2093. if(pPlugin)
  2094. {
  2095. // apply NNA to this plugin iff it is currently playing a note on this tracker channel
  2096. // (and if it is playing a note, we know that would be the last note played on this chan).
  2097. const auto oldNote = srcChn.GetPluginNote(m_playBehaviour[kITRealNoteMapping]);
  2098. applyNNAtoPlug = (oldNote != NOTE_NONE) && pPlugin->IsNotePlaying(oldNote, nChn);
  2099. }
  2100. }
  2101. }
  2102. #endif // NO_PLUGINS
  2103. // New Note Action
  2104. if(!srcChn.IsSamplePlaying() && !applyNNAtoPlug)
  2105. return CHANNELINDEX_INVALID;
  2106. #ifndef NO_PLUGINS
  2107. if(applyNNAtoPlug && pPlugin)
  2108. {
  2109. switch(srcChn.nNNA)
  2110. {
  2111. case NewNoteAction::NoteOff:
  2112. case NewNoteAction::NoteCut:
  2113. case NewNoteAction::NoteFade:
  2114. // Switch off note played on this plugin, on this tracker channel and midi channel
  2115. SendMIDINote(nChn, NOTE_KEYOFF, 0);
  2116. srcChn.nArpeggioLastNote = NOTE_NONE;
  2117. break;
  2118. case NewNoteAction::Continue:
  2119. break;
  2120. }
  2121. }
  2122. #endif // NO_PLUGINS
  2123. CHANNELINDEX nnaChn = GetNNAChannel(nChn);
  2124. if(nnaChn == CHANNELINDEX_INVALID)
  2125. return CHANNELINDEX_INVALID;
  2126. ModChannel &chn = m_PlayState.Chn[nnaChn];
  2127. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2128. m_opl->NoteCut(nnaChn);
  2129. // Copy Channel
  2130. chn = srcChn;
  2131. chn.dwFlags.reset(CHN_VIBRATO | CHN_TREMOLO | CHN_PORTAMENTO);
  2132. chn.nPanbrelloOffset = 0;
  2133. chn.nMasterChn = nChn < GetNumChannels() ? nChn + 1 : 0;
  2134. chn.nCommand = CMD_NONE;
  2135. // Key Off the note
  2136. switch(srcChn.nNNA)
  2137. {
  2138. case NewNoteAction::NoteOff:
  2139. KeyOff(chn);
  2140. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2141. {
  2142. m_opl->NoteOff(nChn);
  2143. if(m_playBehaviour[kOPLwithNNA])
  2144. m_opl->MoveChannel(nChn, nnaChn);
  2145. }
  2146. break;
  2147. case NewNoteAction::NoteCut:
  2148. chn.nFadeOutVol = 0;
  2149. chn.dwFlags.set(CHN_NOTEFADE);
  2150. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2151. m_opl->NoteCut(nChn);
  2152. break;
  2153. case NewNoteAction::NoteFade:
  2154. chn.dwFlags.set(CHN_NOTEFADE);
  2155. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2156. {
  2157. if(m_playBehaviour[kOPLwithNNA])
  2158. m_opl->MoveChannel(nChn, nnaChn);
  2159. else
  2160. m_opl->NoteOff(nChn);
  2161. }
  2162. break;
  2163. case NewNoteAction::Continue:
  2164. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  2165. m_opl->MoveChannel(nChn, nnaChn);
  2166. break;
  2167. }
  2168. if(!chn.nVolume)
  2169. {
  2170. chn.nFadeOutVol = 0;
  2171. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  2172. }
  2173. // Stop this channel
  2174. srcChn.nLength = 0;
  2175. srcChn.position.Set(0);
  2176. srcChn.nROfs = srcChn.nLOfs = 0;
  2177. return nnaChn;
  2178. }
  2179. bool CSoundFile::ProcessEffects()
  2180. {
  2181. m_PlayState.m_breakRow = ROWINDEX_INVALID; // Is changed if a break to row command is encountered
  2182. m_PlayState.m_patLoopRow = ROWINDEX_INVALID; // Is changed if a pattern loop jump-back is executed
  2183. m_PlayState.m_posJump = ORDERINDEX_INVALID;
  2184. for(CHANNELINDEX nChn = 0; nChn < GetNumChannels(); nChn++)
  2185. {
  2186. ModChannel &chn = m_PlayState.Chn[nChn];
  2187. const uint32 tickCount = m_PlayState.m_nTickCount % (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay);
  2188. uint32 instr = chn.rowCommand.instr;
  2189. ModCommand::VOLCMD volcmd = chn.rowCommand.volcmd;
  2190. uint32 vol = chn.rowCommand.vol;
  2191. ModCommand::COMMAND cmd = chn.rowCommand.command;
  2192. uint32 param = chn.rowCommand.param;
  2193. bool bPorta = chn.rowCommand.IsPortamento();
  2194. uint32 nStartTick = 0;
  2195. chn.isFirstTick = m_SongFlags[SONG_FIRSTTICK];
  2196. // Process parameter control note.
  2197. if(chn.rowCommand.note == NOTE_PC)
  2198. {
  2199. #ifndef NO_PLUGINS
  2200. const PLUGINDEX plug = chn.rowCommand.instr;
  2201. const PlugParamIndex plugparam = chn.rowCommand.GetValueVolCol();
  2202. const PlugParamValue value = chn.rowCommand.GetValueEffectCol() / PlugParamValue(ModCommand::maxColumnValue);
  2203. if(plug > 0 && plug <= MAX_MIXPLUGINS && m_MixPlugins[plug - 1].pMixPlugin)
  2204. m_MixPlugins[plug-1].pMixPlugin->SetParameter(plugparam, value);
  2205. #endif // NO_PLUGINS
  2206. }
  2207. // Process continuous parameter control note.
  2208. // Row data is cleared after first tick so on following
  2209. // ticks using channels m_nPlugParamValueStep to identify
  2210. // the need for parameter control. The condition cmd == 0
  2211. // is to make sure that m_nPlugParamValueStep != 0 because
  2212. // of NOTE_PCS, not because of macro.
  2213. if(chn.rowCommand.note == NOTE_PCS || (cmd == CMD_NONE && chn.m_plugParamValueStep != 0))
  2214. {
  2215. #ifndef NO_PLUGINS
  2216. const bool isFirstTick = m_SongFlags[SONG_FIRSTTICK];
  2217. if(isFirstTick)
  2218. chn.m_RowPlug = chn.rowCommand.instr;
  2219. const PLUGINDEX plugin = chn.m_RowPlug;
  2220. const bool hasValidPlug = (plugin > 0 && plugin <= MAX_MIXPLUGINS && m_MixPlugins[plugin - 1].pMixPlugin);
  2221. if(hasValidPlug)
  2222. {
  2223. if(isFirstTick)
  2224. chn.m_RowPlugParam = ModCommand::GetValueVolCol(chn.rowCommand.volcmd, chn.rowCommand.vol);
  2225. const PlugParamIndex plugparam = chn.m_RowPlugParam;
  2226. if(isFirstTick)
  2227. {
  2228. PlugParamValue targetvalue = ModCommand::GetValueEffectCol(chn.rowCommand.command, chn.rowCommand.param) / PlugParamValue(ModCommand::maxColumnValue);
  2229. chn.m_plugParamTargetValue = targetvalue;
  2230. chn.m_plugParamValueStep = (targetvalue - m_MixPlugins[plugin - 1].pMixPlugin->GetParameter(plugparam)) / PlugParamValue(m_PlayState.TicksOnRow());
  2231. }
  2232. if(m_PlayState.m_nTickCount + 1 == m_PlayState.TicksOnRow())
  2233. { // On last tick, set parameter exactly to target value.
  2234. m_MixPlugins[plugin - 1].pMixPlugin->SetParameter(plugparam, chn.m_plugParamTargetValue);
  2235. }
  2236. else
  2237. m_MixPlugins[plugin - 1].pMixPlugin->ModifyParameter(plugparam, chn.m_plugParamValueStep);
  2238. }
  2239. #endif // NO_PLUGINS
  2240. }
  2241. // Apart from changing parameters, parameter control notes are intended to be 'invisible'.
  2242. // To achieve this, clearing the note data so that rest of the process sees the row as empty row.
  2243. if(ModCommand::IsPcNote(chn.rowCommand.note))
  2244. {
  2245. chn.ClearRowCmd();
  2246. instr = 0;
  2247. volcmd = VOLCMD_NONE;
  2248. vol = 0;
  2249. cmd = CMD_NONE;
  2250. param = 0;
  2251. bPorta = false;
  2252. }
  2253. // Process Invert Loop (MOD Effect, called every row if it's active)
  2254. if(!m_SongFlags[SONG_FIRSTTICK])
  2255. {
  2256. InvertLoop(m_PlayState.Chn[nChn]);
  2257. } else
  2258. {
  2259. if(instr) m_PlayState.Chn[nChn].nEFxOffset = 0;
  2260. }
  2261. // Process special effects (note delay, pattern delay, pattern loop)
  2262. if (cmd == CMD_DELAYCUT)
  2263. {
  2264. //:xy --> note delay until tick x, note cut at tick x+y
  2265. nStartTick = (param & 0xF0) >> 4;
  2266. const uint32 cutAtTick = nStartTick + (param & 0x0F);
  2267. NoteCut(nChn, cutAtTick, m_playBehaviour[kITSCxStopsSample]);
  2268. } else if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
  2269. {
  2270. if ((!param) && (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT)))
  2271. param = chn.nOldCmdEx;
  2272. else
  2273. chn.nOldCmdEx = static_cast<ModCommand::PARAM>(param);
  2274. // Note Delay ?
  2275. if ((param & 0xF0) == 0xD0)
  2276. {
  2277. nStartTick = param & 0x0F;
  2278. if(nStartTick == 0)
  2279. {
  2280. //IT compatibility 22. SD0 == SD1
  2281. if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
  2282. nStartTick = 1;
  2283. //ST3 ignores notes with SD0 completely
  2284. else if(GetType() == MOD_TYPE_S3M)
  2285. continue;
  2286. } else if(nStartTick >= (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay) && m_playBehaviour[kITOutOfRangeDelay])
  2287. {
  2288. // IT compatibility 08. Handling of out-of-range delay command.
  2289. // Additional test case: tickdelay.it
  2290. if(instr)
  2291. {
  2292. chn.nNewIns = static_cast<ModCommand::INSTR>(instr);
  2293. }
  2294. continue;
  2295. }
  2296. } else if(m_SongFlags[SONG_FIRSTTICK])
  2297. {
  2298. // Pattern Loop ?
  2299. if((param & 0xF0) == 0xE0)
  2300. {
  2301. // Pattern Delay
  2302. // In Scream Tracker 3 / Impulse Tracker, only the first delay command on this row is considered.
  2303. // Test cases: PatternDelays.it, PatternDelays.s3m, PatternDelays.xm
  2304. // XXX In Scream Tracker 3, the "left" channels are evaluated before the "right" channels, which is not emulated here!
  2305. if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)) || !m_PlayState.m_nPatternDelay)
  2306. {
  2307. if(!(GetType() & (MOD_TYPE_S3M)) || (param & 0x0F) != 0)
  2308. {
  2309. // While Impulse Tracker *does* count S60 as a valid row delay (and thus ignores any other row delay commands on the right),
  2310. // Scream Tracker 3 simply ignores such commands.
  2311. m_PlayState.m_nPatternDelay = 1 + (param & 0x0F);
  2312. }
  2313. }
  2314. }
  2315. }
  2316. }
  2317. if(GetType() == MOD_TYPE_MTM && cmd == CMD_MODCMDEX && (param & 0xF0) == 0xD0)
  2318. {
  2319. // Apparently, retrigger and note delay have the same behaviour in MultiTracker:
  2320. // They both restart the note at tick x, and if there is a note on the same row,
  2321. // this note is started on the first tick.
  2322. nStartTick = 0;
  2323. param = 0x90 | (param & 0x0F);
  2324. }
  2325. if(nStartTick != 0 && chn.rowCommand.note == NOTE_KEYOFF && chn.rowCommand.volcmd == VOLCMD_PANNING && m_playBehaviour[kFT2PanWithDelayedNoteOff])
  2326. {
  2327. // FT2 compatibility: If there's a delayed note off, panning commands are ignored. WTF!
  2328. // Test case: PanOff.xm
  2329. chn.rowCommand.volcmd = VOLCMD_NONE;
  2330. }
  2331. bool triggerNote = (m_PlayState.m_nTickCount == nStartTick); // Can be delayed by a note delay effect
  2332. if(m_playBehaviour[kFT2OutOfRangeDelay] && nStartTick >= m_PlayState.m_nMusicSpeed)
  2333. {
  2334. // FT2 compatibility: Note delays greater than the song speed should be ignored.
  2335. // However, EEx pattern delay is *not* considered at all.
  2336. // Test case: DelayCombination.xm, PortaDelay.xm
  2337. triggerNote = false;
  2338. } else if(m_playBehaviour[kRowDelayWithNoteDelay] && nStartTick > 0 && tickCount == nStartTick)
  2339. {
  2340. // IT compatibility: Delayed notes (using SDx) that are on the same row as a Row Delay effect are retriggered.
  2341. // ProTracker / Scream Tracker 3 / FastTracker 2 do the same.
  2342. // Test case: PatternDelay-NoteDelay.it, PatternDelay-NoteDelay.xm, PatternDelaysRetrig.mod
  2343. triggerNote = true;
  2344. }
  2345. // IT compatibility: Tick-0 vs non-tick-0 effect distinction is always based on tick delay.
  2346. // Test case: SlideDelay.it
  2347. if(m_playBehaviour[kITFirstTickHandling])
  2348. {
  2349. chn.isFirstTick = tickCount == nStartTick;
  2350. }
  2351. chn.triggerNote = triggerNote;
  2352. // FT2 compatibility: Note + portamento + note delay = no portamento
  2353. // Test case: PortaDelay.xm
  2354. if(m_playBehaviour[kFT2PortaDelay] && nStartTick != 0)
  2355. {
  2356. bPorta = false;
  2357. }
  2358. if(m_SongFlags[SONG_PT_MODE] && instr && !m_PlayState.m_nTickCount)
  2359. {
  2360. // Instrument number resets the stacked ProTracker offset.
  2361. // Test case: ptoffset.mod
  2362. chn.prevNoteOffset = 0;
  2363. // ProTracker compatibility: Sample properties are always loaded on the first tick, even when there is a note delay.
  2364. // Test case: InstrDelay.mod
  2365. if(!triggerNote && chn.IsSamplePlaying())
  2366. {
  2367. chn.nNewIns = static_cast<ModCommand::INSTR>(instr);
  2368. if(instr <= GetNumSamples())
  2369. {
  2370. chn.nVolume = Samples[instr].nVolume;
  2371. chn.nFineTune = Samples[instr].nFineTune;
  2372. }
  2373. }
  2374. }
  2375. // Handles note/instrument/volume changes
  2376. if(triggerNote)
  2377. {
  2378. ModCommand::NOTE note = chn.rowCommand.note;
  2379. if(instr) chn.nNewIns = static_cast<ModCommand::INSTR>(instr);
  2380. if(ModCommand::IsNote(note) && m_playBehaviour[kFT2Transpose])
  2381. {
  2382. // Notes that exceed FT2's limit are completely ignored.
  2383. // Test case: NoteLimit.xm
  2384. int transpose = chn.nTranspose;
  2385. if(instr && !bPorta)
  2386. {
  2387. // Refresh transpose
  2388. // Test case: NoteLimit2.xm
  2389. const SAMPLEINDEX sample = GetSampleIndex(note, instr);
  2390. if(sample > 0)
  2391. transpose = GetSample(sample).RelativeTone;
  2392. }
  2393. const int computedNote = note + transpose;
  2394. if((computedNote < NOTE_MIN + 11 || computedNote > NOTE_MIN + 130))
  2395. {
  2396. note = NOTE_NONE;
  2397. }
  2398. } else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_J2B)) && GetNumInstruments() != 0 && ModCommand::IsNoteOrEmpty(static_cast<ModCommand::NOTE>(note)))
  2399. {
  2400. // IT compatibility: Invalid instrument numbers do nothing, but they are remembered for upcoming notes and do not trigger a note in that case.
  2401. // Test case: InstrumentNumberChange.it
  2402. INSTRUMENTINDEX instrToCheck = static_cast<INSTRUMENTINDEX>((instr != 0) ? instr : chn.nOldIns);
  2403. if(instrToCheck != 0 && (instrToCheck > GetNumInstruments() || Instruments[instrToCheck] == nullptr))
  2404. {
  2405. note = NOTE_NONE;
  2406. instr = 0;
  2407. }
  2408. }
  2409. // XM: FT2 ignores a note next to a K00 effect, and a fade-out seems to be done when no volume envelope is present (not exactly the Kxx behaviour)
  2410. if(cmd == CMD_KEYOFF && param == 0 && m_playBehaviour[kFT2KeyOff])
  2411. {
  2412. note = NOTE_NONE;
  2413. instr = 0;
  2414. }
  2415. bool retrigEnv = note == NOTE_NONE && instr != 0;
  2416. // Apparently, any note number in a pattern causes instruments to recall their original volume settings - no matter if there's a Note Off next to it or whatever.
  2417. // Test cases: keyoff+instr.xm, delay.xm
  2418. bool reloadSampleSettings = (m_playBehaviour[kFT2ReloadSampleSettings] && instr != 0);
  2419. // ProTracker Compatibility: If a sample was stopped before, lone instrument numbers can retrigger it
  2420. // Test case: PTSwapEmpty.mod, PTInstrVolume.mod, SampleSwap.s3m
  2421. bool keepInstr = (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
  2422. || m_playBehaviour[kST3SampleSwap]
  2423. || (m_playBehaviour[kMODSampleSwap] && !chn.IsSamplePlaying() && (chn.pModSample == nullptr || !chn.pModSample->HasSampleData()));
  2424. // Now it's time for some FT2 crap...
  2425. if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
  2426. {
  2427. // XM: Key-Off + Sample == Note Cut (BUT: Only if no instr number or volume effect is present!)
  2428. // Test case: NoteOffVolume.xm
  2429. if(note == NOTE_KEYOFF
  2430. && ((!instr && volcmd != VOLCMD_VOLUME && cmd != CMD_VOLUME) || !m_playBehaviour[kFT2KeyOff])
  2431. && (chn.pModInstrument == nullptr || !chn.pModInstrument->VolEnv.dwFlags[ENV_ENABLED]))
  2432. {
  2433. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2434. chn.nVolume = 0;
  2435. note = NOTE_NONE;
  2436. instr = 0;
  2437. retrigEnv = false;
  2438. // FT2 Compatbility: Start fading the note for notes with no delay. Only relevant when a volume command is encountered after the note-off.
  2439. // Test case: NoteOffFadeNoEnv.xm
  2440. if(m_SongFlags[SONG_FIRSTTICK] && m_playBehaviour[kFT2NoteOffFlags])
  2441. chn.dwFlags.set(CHN_NOTEFADE);
  2442. } else if(m_playBehaviour[kFT2RetrigWithNoteDelay] && !m_SongFlags[SONG_FIRSTTICK])
  2443. {
  2444. // FT2 Compatibility: Some special hacks for rogue note delays... (EDx with x > 0)
  2445. // Apparently anything that is next to a note delay behaves totally unpredictable in FT2. Swedish tracker logic. :)
  2446. retrigEnv = true;
  2447. // Portamento + Note Delay = No Portamento
  2448. // Test case: porta-delay.xm
  2449. bPorta = false;
  2450. if(note == NOTE_NONE)
  2451. {
  2452. // If there's a note delay but no real note, retrig the last note.
  2453. // Test case: delay2.xm, delay3.xm
  2454. note = static_cast<ModCommand::NOTE>(chn.nNote - chn.nTranspose);
  2455. } else if(note >= NOTE_MIN_SPECIAL)
  2456. {
  2457. // Gah! Even Note Off + Note Delay will cause envelopes to *retrigger*! How stupid is that?
  2458. // ... Well, and that is actually all it does if there's an envelope. No fade out, no nothing. *sigh*
  2459. // Test case: OffDelay.xm
  2460. note = NOTE_NONE;
  2461. keepInstr = false;
  2462. reloadSampleSettings = true;
  2463. } else if(instr || !m_playBehaviour[kFT2NoteDelayWithoutInstr])
  2464. {
  2465. // Normal note (only if there is an instrument, test case: DelayVolume.xm)
  2466. keepInstr = true;
  2467. reloadSampleSettings = true;
  2468. }
  2469. }
  2470. }
  2471. if((retrigEnv && !m_playBehaviour[kFT2ReloadSampleSettings]) || reloadSampleSettings)
  2472. {
  2473. const ModSample *oldSample = nullptr;
  2474. // Reset default volume when retriggering envelopes
  2475. if(GetNumInstruments())
  2476. {
  2477. oldSample = chn.pModSample;
  2478. } else if (instr <= GetNumSamples())
  2479. {
  2480. // Case: Only samples are used; no instruments.
  2481. oldSample = &Samples[instr];
  2482. }
  2483. if(oldSample != nullptr)
  2484. {
  2485. if(!oldSample->uFlags[SMP_NODEFAULTVOLUME] && (GetType() != MOD_TYPE_S3M || oldSample->HasSampleData()))
  2486. chn.nVolume = oldSample->nVolume;
  2487. if(reloadSampleSettings)
  2488. {
  2489. // Also reload panning
  2490. chn.SetInstrumentPan(oldSample->nPan, *this);
  2491. }
  2492. }
  2493. }
  2494. // FT2 compatibility: Instrument number disables tremor effect
  2495. // Test case: TremorInstr.xm, TremoRecover.xm
  2496. if(m_playBehaviour[kFT2Tremor] && instr != 0)
  2497. {
  2498. chn.nTremorCount = 0x20;
  2499. }
  2500. // IT compatibility: Envelope retriggering with instrument number based on Old Effects and Compatible Gxx flags:
  2501. // OldFX CompatGxx Env Behaviour
  2502. // ----- --------- -------------
  2503. // off off never reset
  2504. // on off reset on instrument without portamento
  2505. // off on reset on instrument with portamento
  2506. // on on always reset
  2507. // Test case: ins-xx.it, ins-ox.it, ins-oc.it, ins-xc.it, ResetEnvNoteOffOldFx.it, ResetEnvNoteOffOldFx2.it, noteoff3.it
  2508. if(GetNumInstruments() && m_playBehaviour[kITInstrWithNoteOffOldEffects]
  2509. && instr && !ModCommand::IsNote(note))
  2510. {
  2511. if((bPorta && m_SongFlags[SONG_ITCOMPATGXX])
  2512. || (!bPorta && m_SongFlags[SONG_ITOLDEFFECTS]))
  2513. {
  2514. chn.ResetEnvelopes();
  2515. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2516. chn.nFadeOutVol = 65536;
  2517. }
  2518. }
  2519. if(retrigEnv) //Case: instrument with no note data.
  2520. {
  2521. //IT compatibility: Instrument with no note.
  2522. if(m_playBehaviour[kITInstrWithoutNote] || GetType() == MOD_TYPE_PLM)
  2523. {
  2524. // IT compatibility: Completely retrigger note after sample end to also reset portamento.
  2525. // Test case: PortaResetAfterRetrigger.it
  2526. bool triggerAfterSmpEnd = m_playBehaviour[kITMultiSampleInstrumentNumber] && !chn.IsSamplePlaying();
  2527. if(GetNumInstruments())
  2528. {
  2529. // Instrument mode
  2530. if(instr <= GetNumInstruments() && (chn.pModInstrument != Instruments[instr] || triggerAfterSmpEnd))
  2531. note = chn.nNote;
  2532. } else
  2533. {
  2534. // Sample mode
  2535. if(instr < MAX_SAMPLES && (chn.pModSample != &Samples[instr] || triggerAfterSmpEnd))
  2536. note = chn.nNote;
  2537. }
  2538. }
  2539. if(GetNumInstruments() && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED)))
  2540. {
  2541. chn.ResetEnvelopes();
  2542. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2543. chn.dwFlags.reset(CHN_NOTEFADE);
  2544. chn.nAutoVibDepth = 0;
  2545. chn.nAutoVibPos = 0;
  2546. chn.nFadeOutVol = 65536;
  2547. // FT2 Compatbility: Reset key-off status with instrument number
  2548. // Test case: NoteOffInstrChange.xm
  2549. if(m_playBehaviour[kFT2NoteOffFlags])
  2550. chn.dwFlags.reset(CHN_KEYOFF);
  2551. }
  2552. if (!keepInstr) instr = 0;
  2553. }
  2554. // Note Cut/Off/Fade => ignore instrument
  2555. if (note >= NOTE_MIN_SPECIAL)
  2556. {
  2557. // IT compatibility: Default volume of sample is recalled if instrument number is next to a note-off.
  2558. // Test case: NoteOffInstr.it, noteoff2.it
  2559. if(m_playBehaviour[kITInstrWithNoteOff] && instr)
  2560. {
  2561. const SAMPLEINDEX smp = GetSampleIndex(chn.nLastNote, instr);
  2562. if(smp > 0 && !Samples[smp].uFlags[SMP_NODEFAULTVOLUME])
  2563. chn.nVolume = Samples[smp].nVolume;
  2564. }
  2565. // IT compatibility: Note-off with instrument number + Old Effects retriggers envelopes.
  2566. // Test case: ResetEnvNoteOffOldFx.it
  2567. if(!m_playBehaviour[kITInstrWithNoteOffOldEffects] || !m_SongFlags[SONG_ITOLDEFFECTS])
  2568. instr = 0;
  2569. }
  2570. if(ModCommand::IsNote(note))
  2571. {
  2572. chn.nNewNote = chn.nLastNote = note;
  2573. // New Note Action ?
  2574. if(!bPorta)
  2575. {
  2576. CheckNNA(nChn, instr, note, false);
  2577. }
  2578. chn.RestorePanAndFilter();
  2579. }
  2580. // Instrument Change ?
  2581. if(instr)
  2582. {
  2583. const ModSample *oldSample = chn.pModSample;
  2584. //const ModInstrument *oldInstrument = chn.pModInstrument;
  2585. InstrumentChange(chn, instr, bPorta, true);
  2586. if(chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl)
  2587. {
  2588. m_opl->Patch(nChn, chn.pModSample->adlib);
  2589. }
  2590. // IT compatibility: Keep new instrument number for next instrument-less note even if sample playback is stopped
  2591. // Test case: StoppedInstrSwap.it
  2592. if(GetType() == MOD_TYPE_MOD)
  2593. {
  2594. // Test case: PortaSwapPT.mod
  2595. if(!bPorta || !m_playBehaviour[kMODSampleSwap]) chn.nNewIns = 0;
  2596. } else
  2597. {
  2598. if(!m_playBehaviour[kITInstrWithNoteOff] || ModCommand::IsNote(note)) chn.nNewIns = 0;
  2599. }
  2600. if(m_playBehaviour[kITPortamentoSwapResetsPos])
  2601. {
  2602. // Test cases: PortaInsNum.it, PortaSample.it
  2603. if(ModCommand::IsNote(note) && oldSample != chn.pModSample)
  2604. {
  2605. //const bool newInstrument = oldInstrument != chn.pModInstrument && chn.pModInstrument->Keyboard[chn.nNewNote - NOTE_MIN] != 0;
  2606. chn.position.Set(0);
  2607. }
  2608. } else if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && oldSample != chn.pModSample && ModCommand::IsNote(note))
  2609. {
  2610. // Special IT case: portamento+note causes sample change -> ignore portamento
  2611. bPorta = false;
  2612. } else if(m_playBehaviour[kST3SampleSwap] && oldSample != chn.pModSample && (bPorta || !ModCommand::IsNote(note)) && chn.position.GetUInt() > chn.nLength)
  2613. {
  2614. // ST3 with SoundBlaster does sample swapping and continues playing the new sample where the old sample was stopped.
  2615. // If the new sample is shorter than that, it is stopped, even if it could be looped.
  2616. // This also applies to portamento between different samples.
  2617. // Test case: SampleSwap.s3m
  2618. chn.nLength = 0;
  2619. } else if(m_playBehaviour[kMODSampleSwap] && !chn.IsSamplePlaying())
  2620. {
  2621. // If channel was paused and is resurrected by a lone instrument number, reset the sample position.
  2622. // Test case: PTSwapEmpty.mod
  2623. chn.position.Set(0);
  2624. }
  2625. }
  2626. // New Note ?
  2627. if (note != NOTE_NONE)
  2628. {
  2629. const bool instrChange = (!instr) && (chn.nNewIns) && ModCommand::IsNote(note);
  2630. if(instrChange)
  2631. {
  2632. InstrumentChange(chn, chn.nNewIns, bPorta, chn.pModSample == nullptr && chn.pModInstrument == nullptr, !(GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)));
  2633. chn.nNewIns = 0;
  2634. }
  2635. if(chn.pModSample != nullptr && chn.pModSample->uFlags[CHN_ADLIB] && m_opl && (instrChange || !m_opl->IsActive(nChn)))
  2636. {
  2637. m_opl->Patch(nChn, chn.pModSample->adlib);
  2638. }
  2639. NoteChange(chn, note, bPorta, !(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)), false, nChn);
  2640. HandleDigiSamplePlayDirection(m_PlayState, nChn);
  2641. if ((bPorta) && (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2)) && (instr))
  2642. {
  2643. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2644. chn.ResetEnvelopes();
  2645. chn.nAutoVibDepth = 0;
  2646. chn.nAutoVibPos = 0;
  2647. }
  2648. if(chn.dwFlags[CHN_ADLIB] && m_opl
  2649. && ((note == NOTE_NOTECUT || note == NOTE_KEYOFF) || (note == NOTE_FADE && !m_playBehaviour[kOPLFlexibleNoteOff])))
  2650. {
  2651. if(m_playBehaviour[kOPLNoteStopWith0Hz])
  2652. m_opl->Frequency(nChn, 0, true, false);
  2653. m_opl->NoteOff(nChn);
  2654. }
  2655. }
  2656. // Tick-0 only volume commands
  2657. if (volcmd == VOLCMD_VOLUME)
  2658. {
  2659. if (vol > 64) vol = 64;
  2660. chn.nVolume = vol << 2;
  2661. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2662. } else
  2663. if (volcmd == VOLCMD_PANNING)
  2664. {
  2665. Panning(chn, vol, Pan6bit);
  2666. }
  2667. #ifndef NO_PLUGINS
  2668. if (m_nInstruments) ProcessMidiOut(nChn);
  2669. #endif // NO_PLUGINS
  2670. }
  2671. if(m_playBehaviour[kST3NoMutedChannels] && ChnSettings[nChn].dwFlags[CHN_MUTE]) // not even effects are processed on muted S3M channels
  2672. continue;
  2673. // Volume Column Effect (except volume & panning)
  2674. /* A few notes, paraphrased from ITTECH.TXT by Storlek (creator of schismtracker):
  2675. Ex/Fx/Gx are shared with Exx/Fxx/Gxx; Ex/Fx are 4x the 'normal' slide value
  2676. Gx is linked with Ex/Fx if Compat Gxx is off, just like Gxx is with Exx/Fxx
  2677. Gx values: 1, 4, 8, 16, 32, 64, 96, 128, 255
  2678. Ax/Bx/Cx/Dx values are used directly (i.e. D9 == D09), and are NOT shared with Dxx
  2679. (value is stored into nOldVolParam and used by A0/B0/C0/D0)
  2680. Hx uses the same value as Hxx and Uxx, and affects the *depth*
  2681. so... hxx = (hx | (oldhxx & 0xf0)) ???
  2682. TODO is this done correctly?
  2683. */
  2684. bool doVolumeColumn = m_PlayState.m_nTickCount >= nStartTick;
  2685. // FT2 compatibility: If there's a note delay, volume column effects are NOT executed
  2686. // on the first tick and, if there's an instrument number, on the delayed tick.
  2687. // Test case: VolColDelay.xm, PortaDelay.xm
  2688. if(m_playBehaviour[kFT2VolColDelay] && nStartTick != 0)
  2689. {
  2690. doVolumeColumn = m_PlayState.m_nTickCount != 0 && (m_PlayState.m_nTickCount != nStartTick || (chn.rowCommand.instr == 0 && volcmd != VOLCMD_TONEPORTAMENTO));
  2691. }
  2692. if(volcmd > VOLCMD_PANNING && doVolumeColumn)
  2693. {
  2694. if(volcmd == VOLCMD_TONEPORTAMENTO)
  2695. {
  2696. const auto [porta, clearEffectCommand] = GetVolCmdTonePorta(chn.rowCommand, nStartTick);
  2697. if(clearEffectCommand)
  2698. cmd = CMD_NONE;
  2699. TonePortamento(chn, porta);
  2700. } else
  2701. {
  2702. // FT2 Compatibility: FT2 ignores some volume commands with parameter = 0.
  2703. if(m_playBehaviour[kFT2VolColMemory] && vol == 0)
  2704. {
  2705. switch(volcmd)
  2706. {
  2707. case VOLCMD_VOLUME:
  2708. case VOLCMD_PANNING:
  2709. case VOLCMD_VIBRATODEPTH:
  2710. break;
  2711. case VOLCMD_PANSLIDELEFT:
  2712. // FT2 Compatibility: Pan slide left with zero parameter causes panning to be set to full left on every non-row tick.
  2713. // Test case: PanSlideZero.xm
  2714. if(!m_SongFlags[SONG_FIRSTTICK])
  2715. {
  2716. chn.nPan = 0;
  2717. }
  2718. [[fallthrough]];
  2719. default:
  2720. // no memory here.
  2721. volcmd = VOLCMD_NONE;
  2722. }
  2723. } else if(!m_playBehaviour[kITVolColMemory])
  2724. {
  2725. // IT Compatibility: Effects in the volume column don't have an unified memory.
  2726. // Test case: VolColMemory.it
  2727. if(vol) chn.nOldVolParam = static_cast<ModCommand::PARAM>(vol); else vol = chn.nOldVolParam;
  2728. }
  2729. switch(volcmd)
  2730. {
  2731. case VOLCMD_VOLSLIDEUP:
  2732. case VOLCMD_VOLSLIDEDOWN:
  2733. // IT Compatibility: Volume column volume slides have their own memory
  2734. // Test case: VolColMemory.it
  2735. if(vol == 0 && m_playBehaviour[kITVolColMemory])
  2736. {
  2737. vol = chn.nOldVolParam;
  2738. if(vol == 0)
  2739. break;
  2740. } else
  2741. {
  2742. chn.nOldVolParam = static_cast<ModCommand::PARAM>(vol);
  2743. }
  2744. VolumeSlide(chn, static_cast<ModCommand::PARAM>(volcmd == VOLCMD_VOLSLIDEUP ? (vol << 4) : vol));
  2745. break;
  2746. case VOLCMD_FINEVOLUP:
  2747. // IT Compatibility: Fine volume slides in the volume column are only executed on the first tick, not on multiples of the first tick in case of pattern delay
  2748. // Test case: FineVolColSlide.it
  2749. if(m_PlayState.m_nTickCount == nStartTick || !m_playBehaviour[kITVolColMemory])
  2750. {
  2751. // IT Compatibility: Volume column volume slides have their own memory
  2752. // Test case: VolColMemory.it
  2753. FineVolumeUp(chn, static_cast<ModCommand::PARAM>(vol), m_playBehaviour[kITVolColMemory]);
  2754. }
  2755. break;
  2756. case VOLCMD_FINEVOLDOWN:
  2757. // IT Compatibility: Fine volume slides in the volume column are only executed on the first tick, not on multiples of the first tick in case of pattern delay
  2758. // Test case: FineVolColSlide.it
  2759. if(m_PlayState.m_nTickCount == nStartTick || !m_playBehaviour[kITVolColMemory])
  2760. {
  2761. // IT Compatibility: Volume column volume slides have their own memory
  2762. // Test case: VolColMemory.it
  2763. FineVolumeDown(chn, static_cast<ModCommand::PARAM>(vol), m_playBehaviour[kITVolColMemory]);
  2764. }
  2765. break;
  2766. case VOLCMD_VIBRATOSPEED:
  2767. // FT2 does not automatically enable vibrato with the "set vibrato speed" command
  2768. if(m_playBehaviour[kFT2VolColVibrato])
  2769. chn.nVibratoSpeed = vol & 0x0F;
  2770. else
  2771. Vibrato(chn, vol << 4);
  2772. break;
  2773. case VOLCMD_VIBRATODEPTH:
  2774. Vibrato(chn, vol);
  2775. break;
  2776. case VOLCMD_PANSLIDELEFT:
  2777. PanningSlide(chn, static_cast<ModCommand::PARAM>(vol), !m_playBehaviour[kFT2VolColMemory]);
  2778. break;
  2779. case VOLCMD_PANSLIDERIGHT:
  2780. PanningSlide(chn, static_cast<ModCommand::PARAM>(vol << 4), !m_playBehaviour[kFT2VolColMemory]);
  2781. break;
  2782. case VOLCMD_PORTAUP:
  2783. // IT compatibility (one of the first testcases - link effect memory)
  2784. PortamentoUp(nChn, static_cast<ModCommand::PARAM>(vol << 2), m_playBehaviour[kITVolColFinePortamento]);
  2785. break;
  2786. case VOLCMD_PORTADOWN:
  2787. // IT compatibility (one of the first testcases - link effect memory)
  2788. PortamentoDown(nChn, static_cast<ModCommand::PARAM>(vol << 2), m_playBehaviour[kITVolColFinePortamento]);
  2789. break;
  2790. case VOLCMD_OFFSET:
  2791. if(triggerNote && chn.pModSample && vol <= std::size(chn.pModSample->cues))
  2792. {
  2793. SmpLength offset;
  2794. if(vol == 0)
  2795. offset = chn.oldOffset;
  2796. else
  2797. offset = chn.oldOffset = chn.pModSample->cues[vol - 1];
  2798. SampleOffset(chn, offset);
  2799. }
  2800. break;
  2801. case VOLCMD_PLAYCONTROL:
  2802. if(vol <= 1)
  2803. chn.isPaused = (vol == 0);
  2804. break;
  2805. }
  2806. }
  2807. }
  2808. // Effects
  2809. if(cmd != CMD_NONE) switch (cmd)
  2810. {
  2811. // Set Volume
  2812. case CMD_VOLUME:
  2813. if(m_SongFlags[SONG_FIRSTTICK])
  2814. {
  2815. chn.nVolume = (param < 64) ? param * 4 : 256;
  2816. chn.dwFlags.set(CHN_FASTVOLRAMP);
  2817. }
  2818. break;
  2819. // Portamento Up
  2820. case CMD_PORTAMENTOUP:
  2821. if ((!param) && (GetType() & MOD_TYPE_MOD)) break;
  2822. PortamentoUp(nChn, static_cast<ModCommand::PARAM>(param));
  2823. break;
  2824. // Portamento Down
  2825. case CMD_PORTAMENTODOWN:
  2826. if ((!param) && (GetType() & MOD_TYPE_MOD)) break;
  2827. PortamentoDown(nChn, static_cast<ModCommand::PARAM>(param));
  2828. break;
  2829. // Volume Slide
  2830. case CMD_VOLUMESLIDE:
  2831. if (param || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast<ModCommand::PARAM>(param));
  2832. break;
  2833. // Tone-Portamento
  2834. case CMD_TONEPORTAMENTO:
  2835. TonePortamento(chn, static_cast<uint16>(param));
  2836. break;
  2837. // Tone-Portamento + Volume Slide
  2838. case CMD_TONEPORTAVOL:
  2839. if ((param) || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast<ModCommand::PARAM>(param));
  2840. TonePortamento(chn, 0);
  2841. break;
  2842. // Vibrato
  2843. case CMD_VIBRATO:
  2844. Vibrato(chn, param);
  2845. break;
  2846. // Vibrato + Volume Slide
  2847. case CMD_VIBRATOVOL:
  2848. if ((param) || (GetType() != MOD_TYPE_MOD)) VolumeSlide(chn, static_cast<ModCommand::PARAM>(param));
  2849. Vibrato(chn, 0);
  2850. break;
  2851. // Set Speed
  2852. case CMD_SPEED:
  2853. if(m_SongFlags[SONG_FIRSTTICK])
  2854. SetSpeed(m_PlayState, param);
  2855. break;
  2856. // Set Tempo
  2857. case CMD_TEMPO:
  2858. if(m_playBehaviour[kMODVBlankTiming])
  2859. {
  2860. // ProTracker MODs with VBlank timing: All Fxx parameters set the tick count.
  2861. if(m_SongFlags[SONG_FIRSTTICK] && param != 0) SetSpeed(m_PlayState, param);
  2862. break;
  2863. }
  2864. {
  2865. param = CalculateXParam(m_PlayState.m_nPattern, m_PlayState.m_nRow, nChn);
  2866. if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))
  2867. {
  2868. if (param) chn.nOldTempo = static_cast<ModCommand::PARAM>(param); else param = chn.nOldTempo;
  2869. }
  2870. TEMPO t(param, 0);
  2871. LimitMax(t, GetModSpecifications().GetTempoMax());
  2872. SetTempo(t);
  2873. }
  2874. break;
  2875. // Set Offset
  2876. case CMD_OFFSET:
  2877. if(triggerNote)
  2878. {
  2879. // FT2 compatibility: Portamento + Offset = Ignore offset
  2880. // Test case: porta-offset.xm
  2881. if(bPorta && GetType() == MOD_TYPE_XM)
  2882. break;
  2883. ProcessSampleOffset(chn, nChn, m_PlayState);
  2884. }
  2885. break;
  2886. // Disorder Tracker 2 percentage offset
  2887. case CMD_OFFSETPERCENTAGE:
  2888. if(triggerNote)
  2889. {
  2890. SampleOffset(chn, Util::muldiv_unsigned(chn.nLength, param, 256));
  2891. }
  2892. break;
  2893. // Arpeggio
  2894. case CMD_ARPEGGIO:
  2895. // IT compatibility 01. Don't ignore Arpeggio if no note is playing (also valid for ST3)
  2896. if(m_PlayState.m_nTickCount) break;
  2897. if((!chn.nPeriod || !chn.nNote)
  2898. && (chn.pModInstrument == nullptr || !chn.pModInstrument->HasValidMIDIChannel()) // Plugin arpeggio
  2899. && !m_playBehaviour[kITArpeggio] && (GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))) break;
  2900. if (!param && (GetType() & (MOD_TYPE_XM | MOD_TYPE_MOD))) break; // Only important when editing MOD/XM files (000 effects are removed when loading files where this means "no effect")
  2901. chn.nCommand = CMD_ARPEGGIO;
  2902. if (param) chn.nArpeggio = static_cast<ModCommand::PARAM>(param);
  2903. break;
  2904. // Retrig
  2905. case CMD_RETRIG:
  2906. if (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))
  2907. {
  2908. if (!(param & 0xF0)) param |= chn.nRetrigParam & 0xF0;
  2909. if (!(param & 0x0F)) param |= chn.nRetrigParam & 0x0F;
  2910. param |= 0x100; // increment retrig count on first row
  2911. }
  2912. // IT compatibility 15. Retrigger
  2913. if(m_playBehaviour[kITRetrigger])
  2914. {
  2915. if (param) chn.nRetrigParam = static_cast<uint8>(param & 0xFF);
  2916. RetrigNote(nChn, chn.nRetrigParam, (volcmd == VOLCMD_OFFSET) ? vol + 1 : 0);
  2917. } else
  2918. {
  2919. // XM Retrig
  2920. if (param) chn.nRetrigParam = static_cast<uint8>(param & 0xFF); else param = chn.nRetrigParam;
  2921. RetrigNote(nChn, param, (volcmd == VOLCMD_OFFSET) ? vol + 1 : 0);
  2922. }
  2923. break;
  2924. // Tremor
  2925. case CMD_TREMOR:
  2926. if(!m_SongFlags[SONG_FIRSTTICK])
  2927. {
  2928. break;
  2929. }
  2930. // IT compatibility 12. / 13. Tremor (using modified DUMB's Tremor logic here because of old effects - http://dumb.sf.net/)
  2931. if(m_playBehaviour[kITTremor])
  2932. {
  2933. if(param && !m_SongFlags[SONG_ITOLDEFFECTS])
  2934. {
  2935. // Old effects have different length interpretation (+1 for both on and off)
  2936. if(param & 0xF0)
  2937. param -= 0x10;
  2938. if(param & 0x0F)
  2939. param -= 0x01;
  2940. chn.nTremorParam = static_cast<ModCommand::PARAM>(param);
  2941. }
  2942. chn.nTremorCount |= 0x80; // set on/off flag
  2943. } else if(m_playBehaviour[kFT2Tremor])
  2944. {
  2945. // XM Tremor. Logic is being processed in sndmix.cpp
  2946. chn.nTremorCount |= 0x80; // set on/off flag
  2947. }
  2948. chn.nCommand = CMD_TREMOR;
  2949. if(param)
  2950. chn.nTremorParam = static_cast<ModCommand::PARAM>(param);
  2951. break;
  2952. // Set Global Volume
  2953. case CMD_GLOBALVOLUME:
  2954. // IT compatibility: Only apply global volume on first tick (and multiples)
  2955. // Test case: GlobalVolFirstTick.it
  2956. if(!m_SongFlags[SONG_FIRSTTICK])
  2957. break;
  2958. // ST3 applies global volume on tick 1 and does other weird things, but we won't emulate this for now.
  2959. // if(((GetType() & MOD_TYPE_S3M) && m_nTickCount != 1)
  2960. // || (!(GetType() & MOD_TYPE_S3M) && !m_SongFlags[SONG_FIRSTTICK]))
  2961. // {
  2962. // break;
  2963. // }
  2964. // FT2 compatibility: On channels that are "left" of the global volume command, the new global volume is not applied
  2965. // until the second tick of the row. Since we apply global volume on the mix buffer rather than note volumes, this
  2966. // cannot be fixed for now.
  2967. // Test case: GlobalVolume.xm
  2968. // if(IsCompatibleMode(TRK_FASTTRACKER2) && m_SongFlags[SONG_FIRSTTICK] && m_nMusicSpeed > 1)
  2969. // {
  2970. // break;
  2971. // }
  2972. if (!(GetType() & GLOBALVOL_7BIT_FORMATS)) param *= 2;
  2973. // IT compatibility 16. ST3 and IT ignore out-of-range values.
  2974. // Test case: globalvol-invalid.it
  2975. if(param <= 128)
  2976. {
  2977. m_PlayState.m_nGlobalVolume = param * 2;
  2978. } else if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_S3M)))
  2979. {
  2980. m_PlayState.m_nGlobalVolume = 256;
  2981. }
  2982. break;
  2983. // Global Volume Slide
  2984. case CMD_GLOBALVOLSLIDE:
  2985. //IT compatibility 16. Saving last global volume slide param per channel (FT2/IT)
  2986. if(m_playBehaviour[kPerChannelGlobalVolSlide])
  2987. GlobalVolSlide(static_cast<ModCommand::PARAM>(param), chn.nOldGlobalVolSlide);
  2988. else
  2989. GlobalVolSlide(static_cast<ModCommand::PARAM>(param), m_PlayState.Chn[0].nOldGlobalVolSlide);
  2990. break;
  2991. // Set 8-bit Panning
  2992. case CMD_PANNING8:
  2993. if(m_SongFlags[SONG_FIRSTTICK])
  2994. {
  2995. Panning(chn, param, Pan8bit);
  2996. }
  2997. break;
  2998. // Panning Slide
  2999. case CMD_PANNINGSLIDE:
  3000. PanningSlide(chn, static_cast<ModCommand::PARAM>(param));
  3001. break;
  3002. // Tremolo
  3003. case CMD_TREMOLO:
  3004. Tremolo(chn, param);
  3005. break;
  3006. // Fine Vibrato
  3007. case CMD_FINEVIBRATO:
  3008. FineVibrato(chn, param);
  3009. break;
  3010. // MOD/XM Exx Extended Commands
  3011. case CMD_MODCMDEX:
  3012. ExtendedMODCommands(nChn, static_cast<ModCommand::PARAM>(param));
  3013. break;
  3014. // S3M/IT Sxx Extended Commands
  3015. case CMD_S3MCMDEX:
  3016. ExtendedS3MCommands(nChn, static_cast<ModCommand::PARAM>(param));
  3017. break;
  3018. // Key Off
  3019. case CMD_KEYOFF:
  3020. // This is how Key Off is supposed to sound... (in FT2 at least)
  3021. if(m_playBehaviour[kFT2KeyOff])
  3022. {
  3023. if (m_PlayState.m_nTickCount == param)
  3024. {
  3025. // XM: Key-Off + Sample == Note Cut
  3026. if(chn.pModInstrument == nullptr || !chn.pModInstrument->VolEnv.dwFlags[ENV_ENABLED])
  3027. {
  3028. if(param == 0 && (chn.rowCommand.instr || chn.rowCommand.volcmd != VOLCMD_NONE)) // FT2 is weird....
  3029. {
  3030. chn.dwFlags.set(CHN_NOTEFADE);
  3031. }
  3032. else
  3033. {
  3034. chn.dwFlags.set(CHN_FASTVOLRAMP);
  3035. chn.nVolume = 0;
  3036. }
  3037. }
  3038. KeyOff(chn);
  3039. }
  3040. }
  3041. // This is how it's NOT supposed to sound...
  3042. else
  3043. {
  3044. if(m_SongFlags[SONG_FIRSTTICK])
  3045. KeyOff(chn);
  3046. }
  3047. break;
  3048. // Extra-fine porta up/down
  3049. case CMD_XFINEPORTAUPDOWN:
  3050. switch(param & 0xF0)
  3051. {
  3052. case 0x10: ExtraFinePortamentoUp(chn, param & 0x0F); break;
  3053. case 0x20: ExtraFinePortamentoDown(chn, param & 0x0F); break;
  3054. // ModPlug XM Extensions (ignore in compatible mode)
  3055. case 0x50:
  3056. case 0x60:
  3057. case 0x70:
  3058. case 0x90:
  3059. case 0xA0:
  3060. if(!m_playBehaviour[kFT2RestrictXCommand]) ExtendedS3MCommands(nChn, static_cast<ModCommand::PARAM>(param));
  3061. break;
  3062. }
  3063. break;
  3064. case CMD_FINETUNE:
  3065. case CMD_FINETUNE_SMOOTH:
  3066. if(m_SongFlags[SONG_FIRSTTICK] || cmd == CMD_FINETUNE_SMOOTH)
  3067. {
  3068. SetFinetune(nChn, m_PlayState, cmd == CMD_FINETUNE_SMOOTH);
  3069. #ifndef NO_PLUGINS
  3070. if(IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]); plugin != nullptr)
  3071. plugin->MidiPitchBendRaw(chn.GetMIDIPitchBend(), nChn);
  3072. #endif // NO_PLUGINS
  3073. }
  3074. break;
  3075. // Set Channel Global Volume
  3076. case CMD_CHANNELVOLUME:
  3077. if(!m_SongFlags[SONG_FIRSTTICK]) break;
  3078. if (param <= 64)
  3079. {
  3080. chn.nGlobalVol = param;
  3081. chn.dwFlags.set(CHN_FASTVOLRAMP);
  3082. }
  3083. break;
  3084. // Channel volume slide
  3085. case CMD_CHANNELVOLSLIDE:
  3086. ChannelVolSlide(chn, static_cast<ModCommand::PARAM>(param));
  3087. break;
  3088. // Panbrello (IT)
  3089. case CMD_PANBRELLO:
  3090. Panbrello(chn, param);
  3091. break;
  3092. // Set Envelope Position
  3093. case CMD_SETENVPOSITION:
  3094. if(m_SongFlags[SONG_FIRSTTICK])
  3095. {
  3096. chn.VolEnv.nEnvPosition = param;
  3097. // FT2 compatibility: FT2 only sets the position of the panning envelope if the volume envelope's sustain flag is set
  3098. // Test case: SetEnvPos.xm
  3099. if(!m_playBehaviour[kFT2SetPanEnvPos] || chn.VolEnv.flags[ENV_SUSTAIN])
  3100. {
  3101. chn.PanEnv.nEnvPosition = param;
  3102. chn.PitchEnv.nEnvPosition = param;
  3103. }
  3104. }
  3105. break;
  3106. // Position Jump
  3107. case CMD_POSITIONJUMP:
  3108. PositionJump(m_PlayState, nChn);
  3109. break;
  3110. // Pattern Break
  3111. case CMD_PATTERNBREAK:
  3112. if(ROWINDEX row = PatternBreak(m_PlayState, nChn, static_cast<ModCommand::PARAM>(param)); row != ROWINDEX_INVALID)
  3113. {
  3114. m_PlayState.m_breakRow = row;
  3115. if(m_SongFlags[SONG_PATTERNLOOP])
  3116. {
  3117. //If song is set to loop and a pattern break occurs we should stay on the same pattern.
  3118. //Use nPosJump to force playback to "jump to this pattern" rather than move to next, as by default.
  3119. m_PlayState.m_posJump = m_PlayState.m_nCurrentOrder;
  3120. }
  3121. }
  3122. break;
  3123. // IMF / PTM Note Slides
  3124. case CMD_NOTESLIDEUP:
  3125. case CMD_NOTESLIDEDOWN:
  3126. case CMD_NOTESLIDEUPRETRIG:
  3127. case CMD_NOTESLIDEDOWNRETRIG:
  3128. // Note that this command seems to be a bit buggy in Polytracker... Luckily, no tune seems to seriously use this
  3129. // (Vic uses it e.g. in Spaceman or Perfect Reason to slide effect samples, noone will notice the difference :)
  3130. NoteSlide(chn, param, cmd == CMD_NOTESLIDEUP || cmd == CMD_NOTESLIDEUPRETRIG, cmd == CMD_NOTESLIDEUPRETRIG || cmd == CMD_NOTESLIDEDOWNRETRIG);
  3131. break;
  3132. // PTM Reverse sample + offset (executed on every tick)
  3133. case CMD_REVERSEOFFSET:
  3134. ReverseSampleOffset(chn, static_cast<ModCommand::PARAM>(param));
  3135. break;
  3136. #ifndef NO_PLUGINS
  3137. // DBM: Toggle DSP Echo
  3138. case CMD_DBMECHO:
  3139. if(m_PlayState.m_nTickCount == 0)
  3140. {
  3141. uint32 echoType = (param >> 4), enable = (param & 0x0F);
  3142. if(echoType > 2 || enable > 1)
  3143. {
  3144. break;
  3145. }
  3146. CHANNELINDEX firstChn = nChn, lastChn = nChn;
  3147. if(echoType == 1)
  3148. {
  3149. firstChn = 0;
  3150. lastChn = m_nChannels - 1;
  3151. }
  3152. for(CHANNELINDEX c = firstChn; c <= lastChn; c++)
  3153. {
  3154. ChnSettings[c].dwFlags.set(CHN_NOFX, enable == 1);
  3155. m_PlayState.Chn[c].dwFlags.set(CHN_NOFX, enable == 1);
  3156. }
  3157. }
  3158. break;
  3159. #endif // NO_PLUGINS
  3160. // Digi Booster sample reverse
  3161. case CMD_DIGIREVERSESAMPLE:
  3162. DigiBoosterSampleReverse(chn, static_cast<ModCommand::PARAM>(param));
  3163. break;
  3164. }
  3165. if(m_playBehaviour[kST3EffectMemory] && param != 0)
  3166. {
  3167. UpdateS3MEffectMemory(chn, static_cast<ModCommand::PARAM>(param));
  3168. }
  3169. if(chn.rowCommand.instr)
  3170. {
  3171. // Not necessarily consistent with actually playing instrument for IT compatibility
  3172. chn.nOldIns = chn.rowCommand.instr;
  3173. }
  3174. } // for(...) end
  3175. // Navigation Effects
  3176. if(m_SongFlags[SONG_FIRSTTICK])
  3177. {
  3178. if(HandleNextRow(m_PlayState, Order(), true))
  3179. m_SongFlags.set(SONG_BREAKTOROW);
  3180. }
  3181. return true;
  3182. }
  3183. bool CSoundFile::HandleNextRow(PlayState &state, const ModSequence &order, bool honorPatternLoop) const
  3184. {
  3185. const bool doPatternLoop = (state.m_patLoopRow != ROWINDEX_INVALID);
  3186. const bool doBreakRow = (state.m_breakRow != ROWINDEX_INVALID);
  3187. const bool doPosJump = (state.m_posJump != ORDERINDEX_INVALID);
  3188. bool breakToRow = false;
  3189. // Pattern Break / Position Jump only if no loop running
  3190. // Exception: FastTracker 2 in all cases, Impulse Tracker in case of position jump
  3191. // Test case for FT2 exception: PatLoop-Jumps.xm, PatLoop-Various.xm
  3192. // Test case for IT: exception: LoopBreak.it, sbx-priority.it
  3193. if((doBreakRow || doPosJump)
  3194. && (!doPatternLoop
  3195. || m_playBehaviour[kFT2PatternLoopWithJumps]
  3196. || (m_playBehaviour[kITPatternLoopWithJumps] && doPosJump)
  3197. || (m_playBehaviour[kITPatternLoopWithJumpsOld] && doPosJump)))
  3198. {
  3199. if(!doPosJump)
  3200. state.m_posJump = state.m_nCurrentOrder + 1;
  3201. if(!doBreakRow)
  3202. state.m_breakRow = 0;
  3203. breakToRow = true;
  3204. if(state.m_posJump >= order.size())
  3205. state.m_posJump = order.GetRestartPos();
  3206. // IT / FT2 compatibility: don't reset loop count on pattern break.
  3207. // Test case: gm-trippy01.it, PatLoop-Break.xm, PatLoop-Weird.xm, PatLoop-Break.mod
  3208. if(state.m_posJump != state.m_nCurrentOrder
  3209. && !m_playBehaviour[kITPatternLoopBreak] && !m_playBehaviour[kFT2PatternLoopWithJumps] && GetType() != MOD_TYPE_MOD)
  3210. {
  3211. for(CHANNELINDEX i = 0; i < GetNumChannels(); i++)
  3212. {
  3213. state.Chn[i].nPatternLoopCount = 0;
  3214. }
  3215. }
  3216. state.m_nNextRow = state.m_breakRow;
  3217. if(!honorPatternLoop || !m_SongFlags[SONG_PATTERNLOOP])
  3218. state.m_nNextOrder = state.m_posJump;
  3219. } else if(doPatternLoop)
  3220. {
  3221. // Pattern Loop
  3222. state.m_nNextOrder = state.m_nCurrentOrder;
  3223. state.m_nNextRow = state.m_patLoopRow;
  3224. // FT2 skips the first row of the pattern loop if there's a pattern delay, ProTracker sometimes does it too (didn't quite figure it out yet).
  3225. // But IT and ST3 don't do this.
  3226. // Test cases: PatLoopWithDelay.it, PatLoopWithDelay.s3m
  3227. if(state.m_nPatternDelay
  3228. && (GetType() != MOD_TYPE_IT || !m_playBehaviour[kITPatternLoopWithJumps])
  3229. && GetType() != MOD_TYPE_S3M)
  3230. {
  3231. state.m_nNextRow++;
  3232. }
  3233. // IT Compatibility: If the restart row is past the end of the current pattern
  3234. // (e.g. when continued from a previous pattern without explicit SB0 effect), continue the next pattern.
  3235. // Test case: LoopStartAfterPatternEnd.it
  3236. if(state.m_patLoopRow >= Patterns[state.m_nPattern].GetNumRows())
  3237. {
  3238. state.m_nNextOrder++;
  3239. state.m_nNextRow = 0;
  3240. }
  3241. }
  3242. return breakToRow;
  3243. }
  3244. ////////////////////////////////////////////////////////////
  3245. // Channels effects
  3246. // Update the effect memory of all S3M effects that use the last non-zero effect parameter as memory (Dxy, Exx, Fxx, Ixy, Jxy, Kxy, Lxy, Qxy, Rxy, Sxy)
  3247. // Test case: ParamMemory.s3m
  3248. void CSoundFile::UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param) const
  3249. {
  3250. chn.nOldVolumeSlide = param; // Dxy / Kxy / Lxy
  3251. chn.nOldPortaUp = param; // Exx / Fxx
  3252. chn.nOldPortaDown = param; // Exx / Fxx
  3253. chn.nTremorParam = param; // Ixy
  3254. chn.nArpeggio = param; // Jxy
  3255. chn.nRetrigParam = param; // Qxy
  3256. chn.nTremoloDepth = (param & 0x0F) << 2; // Rxy
  3257. chn.nTremoloSpeed = (param >> 4) & 0x0F; // Rxy
  3258. chn.nOldCmdEx = param; // Sxy
  3259. }
  3260. // Calculate full parameter for effects that support parameter extension at the given pattern location.
  3261. // maxCommands sets the maximum number of XParam commands to look at for this effect
  3262. // extendedRows returns how many extended rows are used (i.e. a value of 0 means the command is not extended).
  3263. uint32 CSoundFile::CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX chn, uint32 *extendedRows) const
  3264. {
  3265. if(extendedRows != nullptr)
  3266. *extendedRows = 0;
  3267. if(!Patterns.IsValidPat(pat))
  3268. {
  3269. #ifdef MPT_BUILD_FUZZER
  3270. // Ending up in this situation implies a logic error
  3271. std::abort();
  3272. #else
  3273. return 0;
  3274. #endif
  3275. }
  3276. ROWINDEX maxCommands = 4;
  3277. const ModCommand *m = Patterns[pat].GetpModCommand(row, chn);
  3278. const auto startCmd = m->command;
  3279. uint32 val = m->param;
  3280. switch(m->command)
  3281. {
  3282. case CMD_OFFSET:
  3283. // 24 bit command
  3284. maxCommands = 2;
  3285. break;
  3286. case CMD_TEMPO:
  3287. case CMD_PATTERNBREAK:
  3288. case CMD_POSITIONJUMP:
  3289. case CMD_FINETUNE:
  3290. case CMD_FINETUNE_SMOOTH:
  3291. // 16 bit command
  3292. maxCommands = 1;
  3293. break;
  3294. default:
  3295. return val;
  3296. }
  3297. const bool xmTempoFix = m->command == CMD_TEMPO && GetType() == MOD_TYPE_XM;
  3298. ROWINDEX numRows = std::min(Patterns[pat].GetNumRows() - row - 1, maxCommands);
  3299. uint32 extRows = 0;
  3300. while(numRows > 0)
  3301. {
  3302. m += Patterns[pat].GetNumChannels();
  3303. if(m->command != CMD_XPARAM)
  3304. break;
  3305. if(xmTempoFix && val < 256)
  3306. {
  3307. // With XM, 0x20 is the lowest tempo. Anything below changes ticks per row.
  3308. val -= 0x20;
  3309. }
  3310. val = (val << 8) | m->param;
  3311. numRows--;
  3312. extRows++;
  3313. }
  3314. // Always return a full-precision value for finetune
  3315. if((startCmd == CMD_FINETUNE || startCmd == CMD_FINETUNE_SMOOTH) && !extRows)
  3316. val <<= 8;
  3317. if(extendedRows != nullptr)
  3318. *extendedRows = extRows;
  3319. return val;
  3320. }
  3321. void CSoundFile::PositionJump(PlayState &state, CHANNELINDEX chn) const
  3322. {
  3323. state.m_nextPatStartRow = 0; // FT2 E60 bug
  3324. state.m_posJump = static_cast<ORDERINDEX>(CalculateXParam(state.m_nPattern, state.m_nRow, chn));
  3325. // see https://forum.openmpt.org/index.php?topic=2769.0 - FastTracker resets Dxx if Bxx is called _after_ Dxx
  3326. // Test case: PatternJump.mod
  3327. if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM)) && state.m_breakRow != ROWINDEX_INVALID)
  3328. {
  3329. state.m_breakRow = 0;
  3330. }
  3331. }
  3332. ROWINDEX CSoundFile::PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const
  3333. {
  3334. if(param >= 64 && (GetType() & MOD_TYPE_S3M))
  3335. {
  3336. // ST3 ignores invalid pattern breaks.
  3337. return ROWINDEX_INVALID;
  3338. }
  3339. state.m_nextPatStartRow = 0; // FT2 E60 bug
  3340. return static_cast<ROWINDEX>(CalculateXParam(state.m_nPattern, state.m_nRow, chn));
  3341. }
  3342. void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular)
  3343. {
  3344. ModChannel &chn = m_PlayState.Chn[nChn];
  3345. if(param)
  3346. {
  3347. // FT2 compatibility: Separate effect memory for all portamento commands
  3348. // Test case: Porta-LinkMem.xm
  3349. if(!m_playBehaviour[kFT2PortaUpDownMemory])
  3350. chn.nOldPortaDown = param;
  3351. chn.nOldPortaUp = param;
  3352. } else
  3353. {
  3354. param = chn.nOldPortaUp;
  3355. }
  3356. const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM));
  3357. // Process MIDI pitch bend for instrument plugins
  3358. MidiPortamento(nChn, param, doFineSlides);
  3359. if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning)
  3360. {
  3361. // Portamento for instruments with custom tuning
  3362. if(param >= 0xF0 && !doFinePortamentoAsRegular)
  3363. PortamentoFineMPT(chn, param - 0xF0);
  3364. else if(param >= 0xE0 && !doFinePortamentoAsRegular)
  3365. PortamentoExtraFineMPT(chn, param - 0xE0);
  3366. else
  3367. PortamentoMPT(chn, param);
  3368. return;
  3369. } else if(GetType() == MOD_TYPE_PLM)
  3370. {
  3371. // A normal portamento up or down makes a follow-up tone portamento go the same direction.
  3372. chn.nPortamentoDest = 1;
  3373. }
  3374. if (doFineSlides && param >= 0xE0)
  3375. {
  3376. if (param & 0x0F)
  3377. {
  3378. if ((param & 0xF0) == 0xF0)
  3379. {
  3380. FinePortamentoUp(chn, param & 0x0F);
  3381. return;
  3382. } else if ((param & 0xF0) == 0xE0 && GetType() != MOD_TYPE_DBM)
  3383. {
  3384. ExtraFinePortamentoUp(chn, param & 0x0F);
  3385. return;
  3386. }
  3387. }
  3388. if(GetType() != MOD_TYPE_DBM)
  3389. {
  3390. // DBM only has fine slides, no extra-fine slides.
  3391. return;
  3392. }
  3393. }
  3394. // Regular Slide
  3395. if(!chn.isFirstTick
  3396. || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
  3397. || (GetType() & (MOD_TYPE_669 | MOD_TYPE_OKT))
  3398. || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]))
  3399. {
  3400. DoFreqSlide(chn, chn.nPeriod, param * 4);
  3401. }
  3402. }
  3403. void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular)
  3404. {
  3405. ModChannel &chn = m_PlayState.Chn[nChn];
  3406. if(param)
  3407. {
  3408. // FT2 compatibility: Separate effect memory for all portamento commands
  3409. // Test case: Porta-LinkMem.xm
  3410. if(!m_playBehaviour[kFT2PortaUpDownMemory])
  3411. chn.nOldPortaUp = param;
  3412. chn.nOldPortaDown = param;
  3413. } else
  3414. {
  3415. param = chn.nOldPortaDown;
  3416. }
  3417. const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM));
  3418. // Process MIDI pitch bend for instrument plugins
  3419. MidiPortamento(nChn, -static_cast<int>(param), doFineSlides);
  3420. if(GetType() == MOD_TYPE_MPT && chn.pModInstrument && chn.pModInstrument->pTuning)
  3421. {
  3422. // Portamento for instruments with custom tuning
  3423. if(param >= 0xF0 && !doFinePortamentoAsRegular)
  3424. PortamentoFineMPT(chn, -static_cast<int>(param - 0xF0));
  3425. else if(param >= 0xE0 && !doFinePortamentoAsRegular)
  3426. PortamentoExtraFineMPT(chn, -static_cast<int>(param - 0xE0));
  3427. else
  3428. PortamentoMPT(chn, -static_cast<int>(param));
  3429. return;
  3430. } else if(GetType() == MOD_TYPE_PLM)
  3431. {
  3432. // A normal portamento up or down makes a follow-up tone portamento go the same direction.
  3433. chn.nPortamentoDest = 65535;
  3434. }
  3435. if(doFineSlides && param >= 0xE0)
  3436. {
  3437. if (param & 0x0F)
  3438. {
  3439. if ((param & 0xF0) == 0xF0)
  3440. {
  3441. FinePortamentoDown(chn, param & 0x0F);
  3442. return;
  3443. } else if ((param & 0xF0) == 0xE0 && GetType() != MOD_TYPE_DBM)
  3444. {
  3445. ExtraFinePortamentoDown(chn, param & 0x0F);
  3446. return;
  3447. }
  3448. }
  3449. if(GetType() != MOD_TYPE_DBM)
  3450. {
  3451. // DBM only has fine slides, no extra-fine slides.
  3452. return;
  3453. }
  3454. }
  3455. if(!chn.isFirstTick
  3456. || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
  3457. || (GetType() & (MOD_TYPE_669 | MOD_TYPE_OKT))
  3458. || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]))
  3459. {
  3460. DoFreqSlide(chn, chn.nPeriod, param * -4);
  3461. }
  3462. }
  3463. // Send portamento commands to plugins
  3464. void CSoundFile::MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides)
  3465. {
  3466. int actualParam = std::abs(param);
  3467. int pitchBend = 0;
  3468. // Old MIDI Pitch Bends:
  3469. // - Applied on every tick
  3470. // - No fine pitch slides (they are interpreted as normal slides)
  3471. // New MIDI Pitch Bends:
  3472. // - Behaviour identical to sample pitch bends if the instrument's PWD parameter corresponds to the actual VSTi setting.
  3473. if(doFineSlides && actualParam >= 0xE0 && !m_playBehaviour[kOldMIDIPitchBends])
  3474. {
  3475. if(m_PlayState.Chn[nChn].isFirstTick)
  3476. {
  3477. // Extra fine slide...
  3478. pitchBend = (actualParam & 0x0F) * mpt::signum(param);
  3479. if(actualParam >= 0xF0)
  3480. {
  3481. // ... or just a fine slide!
  3482. pitchBend *= 4;
  3483. }
  3484. }
  3485. } else if(!m_PlayState.Chn[nChn].isFirstTick || m_playBehaviour[kOldMIDIPitchBends])
  3486. {
  3487. // Regular slide
  3488. pitchBend = param * 4;
  3489. }
  3490. if(pitchBend)
  3491. {
  3492. #ifndef NO_PLUGINS
  3493. IMixPlugin *plugin = GetChannelInstrumentPlugin(m_PlayState.Chn[nChn]);
  3494. if(plugin != nullptr)
  3495. {
  3496. int8 pwd = 13; // Early OpenMPT legacy... Actually it's not *exactly* 13, but close enough...
  3497. if(m_PlayState.Chn[nChn].pModInstrument != nullptr)
  3498. {
  3499. pwd = m_PlayState.Chn[nChn].pModInstrument->midiPWD;
  3500. }
  3501. plugin->MidiPitchBend(pitchBend, pwd, nChn);
  3502. }
  3503. #endif // NO_PLUGINS
  3504. }
  3505. }
  3506. void CSoundFile::FinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const
  3507. {
  3508. MPT_ASSERT(!chn.HasCustomTuning());
  3509. if(GetType() == MOD_TYPE_XM)
  3510. {
  3511. // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked
  3512. // Test case: Porta-LinkMem.xm
  3513. if(param) chn.nOldFinePortaUpDown = (chn.nOldFinePortaUpDown & 0x0F) | (param << 4); else param = (chn.nOldFinePortaUpDown >> 4);
  3514. } else if(GetType() == MOD_TYPE_MT2)
  3515. {
  3516. if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown;
  3517. }
  3518. if(chn.isFirstTick && chn.nPeriod && param)
  3519. DoFreqSlide(chn, chn.nPeriod, param * 4);
  3520. }
  3521. void CSoundFile::FinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const
  3522. {
  3523. MPT_ASSERT(!chn.HasCustomTuning());
  3524. if(GetType() == MOD_TYPE_XM)
  3525. {
  3526. // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked
  3527. // Test case: Porta-LinkMem.xm
  3528. if(param) chn.nOldFinePortaUpDown = (chn.nOldFinePortaUpDown & 0xF0) | (param & 0x0F); else param = (chn.nOldFinePortaUpDown & 0x0F);
  3529. } else if(GetType() == MOD_TYPE_MT2)
  3530. {
  3531. if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown;
  3532. }
  3533. if(chn.isFirstTick && chn.nPeriod && param)
  3534. {
  3535. DoFreqSlide(chn, chn.nPeriod, param * -4);
  3536. if(chn.nPeriod > 0xFFFF && !m_playBehaviour[kPeriodsAreHertz] && (!m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_XM))
  3537. chn.nPeriod = 0xFFFF;
  3538. }
  3539. }
  3540. void CSoundFile::ExtraFinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const
  3541. {
  3542. MPT_ASSERT(!chn.HasCustomTuning());
  3543. if(GetType() == MOD_TYPE_XM)
  3544. {
  3545. // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked
  3546. // Test case: Porta-LinkMem.xm
  3547. if(param) chn.nOldExtraFinePortaUpDown = (chn.nOldExtraFinePortaUpDown & 0x0F) | (param << 4); else param = (chn.nOldExtraFinePortaUpDown >> 4);
  3548. } else if(GetType() == MOD_TYPE_MT2)
  3549. {
  3550. if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown;
  3551. }
  3552. if(chn.isFirstTick && chn.nPeriod && param)
  3553. DoFreqSlide(chn, chn.nPeriod, param);
  3554. }
  3555. void CSoundFile::ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const
  3556. {
  3557. MPT_ASSERT(!chn.HasCustomTuning());
  3558. if(GetType() == MOD_TYPE_XM)
  3559. {
  3560. // FT2 compatibility: E1x / E2x / X1x / X2x memory is not linked
  3561. // Test case: Porta-LinkMem.xm
  3562. if(param) chn.nOldExtraFinePortaUpDown = (chn.nOldExtraFinePortaUpDown & 0xF0) | (param & 0x0F); else param = (chn.nOldExtraFinePortaUpDown & 0x0F);
  3563. } else if(GetType() == MOD_TYPE_MT2)
  3564. {
  3565. if(param) chn.nOldFinePortaUpDown = param; else param = chn.nOldFinePortaUpDown;
  3566. }
  3567. if(chn.isFirstTick && chn.nPeriod && param)
  3568. {
  3569. DoFreqSlide(chn, chn.nPeriod, -static_cast<int32>(param));
  3570. if(chn.nPeriod > 0xFFFF && !m_playBehaviour[kPeriodsAreHertz] && (!m_SongFlags[SONG_LINEARSLIDES] || GetType() == MOD_TYPE_XM))
  3571. chn.nPeriod = 0xFFFF;
  3572. }
  3573. }
  3574. void CSoundFile::SetFinetune(CHANNELINDEX channel, PlayState &playState, bool isSmooth) const
  3575. {
  3576. ModChannel &chn = playState.Chn[channel];
  3577. int16 newTuning = mpt::saturate_cast<int16>(static_cast<int32>(CalculateXParam(playState.m_nPattern, playState.m_nRow, channel, nullptr)) - 0x8000);
  3578. if(isSmooth)
  3579. {
  3580. const int32 ticksLeft = playState.TicksOnRow() - playState.m_nTickCount;
  3581. if(ticksLeft > 1)
  3582. {
  3583. const int32 step = (newTuning - chn.microTuning) / ticksLeft;
  3584. newTuning = mpt::saturate_cast<int16>(chn.microTuning + step);
  3585. }
  3586. }
  3587. chn.microTuning = newTuning;
  3588. }
  3589. // Implemented for IMF / PTM / OKT compatibility, can't actually save this in any formats
  3590. // Slide up / down every x ticks by y semitones
  3591. // Oktalyzer: Slide down on first tick only, or on every tick
  3592. void CSoundFile::NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const
  3593. {
  3594. if(m_SongFlags[SONG_FIRSTTICK])
  3595. {
  3596. if(param & 0xF0)
  3597. chn.noteSlideParam = static_cast<uint8>(param & 0xF0) | (chn.noteSlideParam & 0x0F);
  3598. if(param & 0x0F)
  3599. chn.noteSlideParam = (chn.noteSlideParam & 0xF0) | static_cast<uint8>(param & 0x0F);
  3600. chn.noteSlideCounter = (chn.noteSlideParam >> 4);
  3601. }
  3602. bool doTrigger = false;
  3603. if(GetType() == MOD_TYPE_OKT)
  3604. doTrigger = ((chn.noteSlideParam & 0xF0) == 0x10) || m_SongFlags[SONG_FIRSTTICK];
  3605. else
  3606. doTrigger = !m_SongFlags[SONG_FIRSTTICK] && (--chn.noteSlideCounter == 0);
  3607. if(doTrigger)
  3608. {
  3609. const uint8 speed = (chn.noteSlideParam >> 4), steps = (chn.noteSlideParam & 0x0F);
  3610. chn.noteSlideCounter = speed;
  3611. // update it
  3612. const int32 delta = (slideUp ? steps : -steps);
  3613. if(chn.HasCustomTuning())
  3614. chn.m_PortamentoFineSteps += delta * chn.pModInstrument->pTuning->GetFineStepCount();
  3615. else
  3616. chn.nPeriod = GetPeriodFromNote(delta + GetNoteFromPeriod(chn.nPeriod, chn.nFineTune, chn.nC5Speed), chn.nFineTune, chn.nC5Speed);
  3617. if(retrig)
  3618. chn.position.Set(0);
  3619. }
  3620. }
  3621. std::pair<uint16, bool> CSoundFile::GetVolCmdTonePorta(const ModCommand &m, uint32 startTick) const
  3622. {
  3623. if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_AMS | MOD_TYPE_DMF | MOD_TYPE_DBM | MOD_TYPE_IMF | MOD_TYPE_PSM | MOD_TYPE_J2B | MOD_TYPE_ULT | MOD_TYPE_OKT | MOD_TYPE_MT2 | MOD_TYPE_MDL))
  3624. {
  3625. return {ImpulseTrackerPortaVolCmd[m.vol & 0x0F], false};
  3626. } else
  3627. {
  3628. bool clearEffectColumn = false;
  3629. uint16 vol = m.vol;
  3630. if(m.command == CMD_TONEPORTAMENTO && GetType() == MOD_TYPE_XM)
  3631. {
  3632. // Yes, FT2 is *that* weird. If there is a Mx command in the volume column
  3633. // and a normal 3xx command, the 3xx command is ignored but the Mx command's
  3634. // effectiveness is doubled.
  3635. // Test case: TonePortamentoMemory.xm
  3636. clearEffectColumn = true;
  3637. vol *= 2;
  3638. }
  3639. // FT2 compatibility: If there's a portamento and a note delay, execute the portamento, but don't update the parameter
  3640. // Test case: PortaDelay.xm
  3641. if(m_playBehaviour[kFT2PortaDelay] && startTick != 0)
  3642. return {uint16(0), clearEffectColumn};
  3643. else
  3644. return {static_cast<uint16>(vol * 16), clearEffectColumn};
  3645. }
  3646. }
  3647. // Portamento Slide
  3648. void CSoundFile::TonePortamento(ModChannel &chn, uint16 param) const
  3649. {
  3650. chn.dwFlags.set(CHN_PORTAMENTO);
  3651. //IT compatibility 03: Share effect memory with portamento up/down
  3652. if((!m_SongFlags[SONG_ITCOMPATGXX] && m_playBehaviour[kITPortaMemoryShare]) || GetType() == MOD_TYPE_PLM)
  3653. {
  3654. if(param == 0) param = chn.nOldPortaUp;
  3655. chn.nOldPortaUp = chn.nOldPortaDown = static_cast<uint8>(param);
  3656. }
  3657. if(param)
  3658. chn.portamentoSlide = param;
  3659. if(chn.HasCustomTuning())
  3660. {
  3661. //Behavior: Param tells number of finesteps(or 'fullsteps'(notes) with glissando)
  3662. //to slide per row(not per tick).
  3663. if(chn.portamentoSlide == 0)
  3664. return;
  3665. const int32 oldPortamentoTickSlide = (m_PlayState.m_nTickCount != 0) ? chn.m_PortamentoTickSlide : 0;
  3666. int32 delta = chn.portamentoSlide;
  3667. if(chn.nPortamentoDest < 0)
  3668. delta = -delta;
  3669. chn.m_PortamentoTickSlide = static_cast<int32>((m_PlayState.m_nTickCount + 1.0) * delta / m_PlayState.m_nMusicSpeed);
  3670. if(chn.dwFlags[CHN_GLISSANDO])
  3671. {
  3672. chn.m_PortamentoTickSlide *= chn.pModInstrument->pTuning->GetFineStepCount() + 1;
  3673. //With glissando interpreting param as notes instead of finesteps.
  3674. }
  3675. const int32 slide = chn.m_PortamentoTickSlide - oldPortamentoTickSlide;
  3676. if(std::abs(chn.nPortamentoDest) <= std::abs(slide))
  3677. {
  3678. if(chn.nPortamentoDest != 0)
  3679. {
  3680. chn.m_PortamentoFineSteps += chn.nPortamentoDest;
  3681. chn.nPortamentoDest = 0;
  3682. chn.m_CalculateFreq = true;
  3683. }
  3684. } else
  3685. {
  3686. chn.m_PortamentoFineSteps += slide;
  3687. chn.nPortamentoDest -= slide;
  3688. chn.m_CalculateFreq = true;
  3689. }
  3690. return;
  3691. }
  3692. bool doPorta = !chn.isFirstTick
  3693. || (GetType() & (MOD_TYPE_DBM | MOD_TYPE_669))
  3694. || (m_PlayState.m_nMusicSpeed == 1 && m_playBehaviour[kSlidesAtSpeed1])
  3695. || (GetType() == MOD_TYPE_MED && m_SongFlags[SONG_FASTVOLSLIDES]);
  3696. int32 delta = chn.portamentoSlide;
  3697. if(GetType() == MOD_TYPE_PLM && delta >= 0xF0)
  3698. {
  3699. delta -= 0xF0;
  3700. doPorta = chn.isFirstTick;
  3701. }
  3702. if(chn.nPeriod && chn.nPortamentoDest && doPorta)
  3703. {
  3704. delta *= (GetType() == MOD_TYPE_669) ? 2 : 4;
  3705. if(!PeriodsAreFrequencies())
  3706. delta = -delta;
  3707. if(chn.nPeriod < chn.nPortamentoDest || chn.portaTargetReached)
  3708. {
  3709. DoFreqSlide(chn, chn.nPeriod, delta, true);
  3710. if(chn.nPeriod > chn.nPortamentoDest)
  3711. chn.nPeriod = chn.nPortamentoDest;
  3712. } else if(chn.nPeriod > chn.nPortamentoDest)
  3713. {
  3714. DoFreqSlide(chn, chn.nPeriod, -delta, true);
  3715. if(chn.nPeriod < chn.nPortamentoDest)
  3716. chn.nPeriod = chn.nPortamentoDest;
  3717. // FT2 compatibility: Reaching portamento target from below forces subsequent portamentos on the same note to use the logic for reaching the note from above instead.
  3718. // Test case: PortaResetDirection.xm
  3719. if(chn.nPeriod == chn.nPortamentoDest && m_playBehaviour[kFT2PortaResetDirection])
  3720. chn.portaTargetReached = true;
  3721. }
  3722. }
  3723. // IT compatibility 23. Portamento with no note
  3724. // ProTracker also disables portamento once the target is reached.
  3725. // Test case: PortaTarget.mod
  3726. if(chn.nPeriod == chn.nPortamentoDest && (m_playBehaviour[kITPortaTargetReached] || GetType() == MOD_TYPE_MOD))
  3727. chn.nPortamentoDest = 0;
  3728. }
  3729. void CSoundFile::Vibrato(ModChannel &chn, uint32 param) const
  3730. {
  3731. if (param & 0x0F) chn.nVibratoDepth = (param & 0x0F) * 4;
  3732. if (param & 0xF0) chn.nVibratoSpeed = (param >> 4) & 0x0F;
  3733. chn.dwFlags.set(CHN_VIBRATO);
  3734. }
  3735. void CSoundFile::FineVibrato(ModChannel &chn, uint32 param) const
  3736. {
  3737. if (param & 0x0F) chn.nVibratoDepth = param & 0x0F;
  3738. if (param & 0xF0) chn.nVibratoSpeed = (param >> 4) & 0x0F;
  3739. chn.dwFlags.set(CHN_VIBRATO);
  3740. // ST3 compatibility: Do not distinguish between vibrato types in effect memory
  3741. // Test case: VibratoTypeChange.s3m
  3742. if(m_playBehaviour[kST3VibratoMemory] && (param & 0x0F))
  3743. {
  3744. chn.nVibratoDepth *= 4u;
  3745. }
  3746. }
  3747. void CSoundFile::Panbrello(ModChannel &chn, uint32 param) const
  3748. {
  3749. if (param & 0x0F) chn.nPanbrelloDepth = param & 0x0F;
  3750. if (param & 0xF0) chn.nPanbrelloSpeed = (param >> 4) & 0x0F;
  3751. }
  3752. void CSoundFile::Panning(ModChannel &chn, uint32 param, PanningType panBits) const
  3753. {
  3754. // No panning in ProTracker mode
  3755. if(m_playBehaviour[kMODIgnorePanning])
  3756. {
  3757. return;
  3758. }
  3759. // IT Compatibility (and other trackers as well): panning disables surround (unless panning in rear channels is enabled, which is not supported by the original trackers anyway)
  3760. if (!m_SongFlags[SONG_SURROUNDPAN] && (panBits == Pan8bit || m_playBehaviour[kPanOverride]))
  3761. {
  3762. chn.dwFlags.reset(CHN_SURROUND);
  3763. }
  3764. if(panBits == Pan4bit)
  3765. {
  3766. // 0...15 panning
  3767. chn.nPan = (param * 256 + 8) / 15;
  3768. } else if(panBits == Pan6bit)
  3769. {
  3770. // 0...64 panning
  3771. if(param > 64) param = 64;
  3772. chn.nPan = param * 4;
  3773. } else
  3774. {
  3775. if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_DSM | MOD_TYPE_AMF0 | MOD_TYPE_AMF | MOD_TYPE_MTM)))
  3776. {
  3777. // Real 8-bit panning
  3778. chn.nPan = param;
  3779. } else
  3780. {
  3781. // 7-bit panning + surround
  3782. if(param <= 0x80)
  3783. {
  3784. chn.nPan = param << 1;
  3785. } else if(param == 0xA4)
  3786. {
  3787. chn.dwFlags.set(CHN_SURROUND);
  3788. chn.nPan = 0x80;
  3789. }
  3790. }
  3791. }
  3792. chn.dwFlags.set(CHN_FASTVOLRAMP);
  3793. chn.nRestorePanOnNewNote = 0;
  3794. //IT compatibility 20. Set pan overrides random pan
  3795. if(m_playBehaviour[kPanOverride])
  3796. {
  3797. chn.nPanSwing = 0;
  3798. chn.nPanbrelloOffset = 0;
  3799. }
  3800. }
  3801. void CSoundFile::VolumeSlide(ModChannel &chn, ModCommand::PARAM param) const
  3802. {
  3803. if (param)
  3804. chn.nOldVolumeSlide = param;
  3805. else
  3806. param = chn.nOldVolumeSlide;
  3807. if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP | MOD_TYPE_DTM)))
  3808. {
  3809. // MOD / XM nibble priority
  3810. if((param & 0xF0) != 0)
  3811. {
  3812. param &= 0xF0;
  3813. } else
  3814. {
  3815. param &= 0x0F;
  3816. }
  3817. }
  3818. int newVolume = chn.nVolume;
  3819. if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_AMF0 | MOD_TYPE_MED | MOD_TYPE_DIGI)))
  3820. {
  3821. if ((param & 0x0F) == 0x0F) //Fine upslide or slide -15
  3822. {
  3823. if (param & 0xF0) //Fine upslide
  3824. {
  3825. FineVolumeUp(chn, (param >> 4), false);
  3826. return;
  3827. } else //Slide -15
  3828. {
  3829. if(chn.isFirstTick && !m_SongFlags[SONG_FASTVOLSLIDES])
  3830. {
  3831. newVolume -= 0x0F * 4;
  3832. }
  3833. }
  3834. } else
  3835. if ((param & 0xF0) == 0xF0) //Fine downslide or slide +15
  3836. {
  3837. if (param & 0x0F) //Fine downslide
  3838. {
  3839. FineVolumeDown(chn, (param & 0x0F), false);
  3840. return;
  3841. } else //Slide +15
  3842. {
  3843. if(chn.isFirstTick && !m_SongFlags[SONG_FASTVOLSLIDES])
  3844. {
  3845. newVolume += 0x0F * 4;
  3846. }
  3847. }
  3848. }
  3849. }
  3850. if(!chn.isFirstTick || m_SongFlags[SONG_FASTVOLSLIDES] || (m_PlayState.m_nMusicSpeed == 1 && GetType() == MOD_TYPE_DBM))
  3851. {
  3852. // IT compatibility: Ignore slide commands with both nibbles set.
  3853. if (param & 0x0F)
  3854. {
  3855. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (param & 0xF0) == 0)
  3856. newVolume -= (int)((param & 0x0F) * 4);
  3857. }
  3858. else
  3859. {
  3860. newVolume += (int)((param & 0xF0) >> 2);
  3861. }
  3862. if (GetType() == MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP);
  3863. }
  3864. newVolume = Clamp(newVolume, 0, 256);
  3865. chn.nVolume = newVolume;
  3866. }
  3867. void CSoundFile::PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory) const
  3868. {
  3869. if(memory)
  3870. {
  3871. // FT2 compatibility: Use effect memory (lxx and rxx in XM shouldn't use effect memory).
  3872. // Test case: PanSlideMem.xm
  3873. if(param)
  3874. chn.nOldPanSlide = param;
  3875. else
  3876. param = chn.nOldPanSlide;
  3877. }
  3878. if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)))
  3879. {
  3880. // XM nibble priority
  3881. if((param & 0xF0) != 0)
  3882. {
  3883. param &= 0xF0;
  3884. } else
  3885. {
  3886. param &= 0x0F;
  3887. }
  3888. }
  3889. int32 nPanSlide = 0;
  3890. if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)))
  3891. {
  3892. if (((param & 0x0F) == 0x0F) && (param & 0xF0))
  3893. {
  3894. if(m_SongFlags[SONG_FIRSTTICK])
  3895. {
  3896. param = (param & 0xF0) / 4u;
  3897. nPanSlide = - (int)param;
  3898. }
  3899. } else if (((param & 0xF0) == 0xF0) && (param & 0x0F))
  3900. {
  3901. if(m_SongFlags[SONG_FIRSTTICK])
  3902. {
  3903. nPanSlide = (param & 0x0F) * 4u;
  3904. }
  3905. } else if(!m_SongFlags[SONG_FIRSTTICK])
  3906. {
  3907. if (param & 0x0F)
  3908. {
  3909. // IT compatibility: Ignore slide commands with both nibbles set.
  3910. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) || (param & 0xF0) == 0)
  3911. nPanSlide = (int)((param & 0x0F) * 4u);
  3912. } else
  3913. {
  3914. nPanSlide = -(int)((param & 0xF0) / 4u);
  3915. }
  3916. }
  3917. } else
  3918. {
  3919. if(!m_SongFlags[SONG_FIRSTTICK])
  3920. {
  3921. if (param & 0xF0)
  3922. {
  3923. nPanSlide = (int)((param & 0xF0) / 4u);
  3924. } else
  3925. {
  3926. nPanSlide = -(int)((param & 0x0F) * 4u);
  3927. }
  3928. // FT2 compatibility: FT2's panning slide is like IT's fine panning slide (not as deep)
  3929. if(m_playBehaviour[kFT2PanSlide])
  3930. nPanSlide /= 4;
  3931. }
  3932. }
  3933. if (nPanSlide)
  3934. {
  3935. nPanSlide += chn.nPan;
  3936. nPanSlide = Clamp(nPanSlide, 0, 256);
  3937. chn.nPan = nPanSlide;
  3938. chn.nRestorePanOnNewNote = 0;
  3939. }
  3940. }
  3941. void CSoundFile::FineVolumeUp(ModChannel &chn, ModCommand::PARAM param, bool volCol) const
  3942. {
  3943. if(GetType() == MOD_TYPE_XM)
  3944. {
  3945. // FT2 compatibility: EAx / EBx memory is not linked
  3946. // Test case: FineVol-LinkMem.xm
  3947. if(param) chn.nOldFineVolUpDown = (param << 4) | (chn.nOldFineVolUpDown & 0x0F); else param = (chn.nOldFineVolUpDown >> 4);
  3948. } else if(volCol)
  3949. {
  3950. if(param) chn.nOldVolParam = param; else param = chn.nOldVolParam;
  3951. } else
  3952. {
  3953. if(param) chn.nOldFineVolUpDown = param; else param = chn.nOldFineVolUpDown;
  3954. }
  3955. if(chn.isFirstTick)
  3956. {
  3957. chn.nVolume += param * 4;
  3958. if(chn.nVolume > 256) chn.nVolume = 256;
  3959. if(GetType() & MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP);
  3960. }
  3961. }
  3962. void CSoundFile::FineVolumeDown(ModChannel &chn, ModCommand::PARAM param, bool volCol) const
  3963. {
  3964. if(GetType() == MOD_TYPE_XM)
  3965. {
  3966. // FT2 compatibility: EAx / EBx memory is not linked
  3967. // Test case: FineVol-LinkMem.xm
  3968. if(param) chn.nOldFineVolUpDown = param | (chn.nOldFineVolUpDown & 0xF0); else param = (chn.nOldFineVolUpDown & 0x0F);
  3969. } else if(volCol)
  3970. {
  3971. if(param) chn.nOldVolParam = param; else param = chn.nOldVolParam;
  3972. } else
  3973. {
  3974. if(param) chn.nOldFineVolUpDown = param; else param = chn.nOldFineVolUpDown;
  3975. }
  3976. if(chn.isFirstTick)
  3977. {
  3978. chn.nVolume -= param * 4;
  3979. if(chn.nVolume < 0) chn.nVolume = 0;
  3980. if(GetType() & MOD_TYPE_MOD) chn.dwFlags.set(CHN_FASTVOLRAMP);
  3981. }
  3982. }
  3983. void CSoundFile::Tremolo(ModChannel &chn, uint32 param) const
  3984. {
  3985. if (param & 0x0F) chn.nTremoloDepth = (param & 0x0F) << 2;
  3986. if (param & 0xF0) chn.nTremoloSpeed = (param >> 4) & 0x0F;
  3987. chn.dwFlags.set(CHN_TREMOLO);
  3988. }
  3989. void CSoundFile::ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const
  3990. {
  3991. int32 nChnSlide = 0;
  3992. if (param) chn.nOldChnVolSlide = param; else param = chn.nOldChnVolSlide;
  3993. if (((param & 0x0F) == 0x0F) && (param & 0xF0))
  3994. {
  3995. if(m_SongFlags[SONG_FIRSTTICK]) nChnSlide = param >> 4;
  3996. } else if (((param & 0xF0) == 0xF0) && (param & 0x0F))
  3997. {
  3998. if(m_SongFlags[SONG_FIRSTTICK]) nChnSlide = - (int)(param & 0x0F);
  3999. } else
  4000. {
  4001. if(!m_SongFlags[SONG_FIRSTTICK])
  4002. {
  4003. if (param & 0x0F)
  4004. {
  4005. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_J2B | MOD_TYPE_DBM)) || (param & 0xF0) == 0)
  4006. nChnSlide = -(int)(param & 0x0F);
  4007. } else
  4008. {
  4009. nChnSlide = (int)((param & 0xF0) >> 4);
  4010. }
  4011. }
  4012. }
  4013. if (nChnSlide)
  4014. {
  4015. nChnSlide += chn.nGlobalVol;
  4016. nChnSlide = Clamp(nChnSlide, 0, 64);
  4017. chn.nGlobalVol = nChnSlide;
  4018. }
  4019. }
  4020. void CSoundFile::ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
  4021. {
  4022. ModChannel &chn = m_PlayState.Chn[nChn];
  4023. uint8 command = param & 0xF0;
  4024. param &= 0x0F;
  4025. switch(command)
  4026. {
  4027. // E0x: Set Filter
  4028. case 0x00:
  4029. for(CHANNELINDEX channel = 0; channel < GetNumChannels(); channel++)
  4030. {
  4031. m_PlayState.Chn[channel].dwFlags.set(CHN_AMIGAFILTER, !(param & 1));
  4032. }
  4033. break;
  4034. // E1x: Fine Portamento Up
  4035. case 0x10: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoUp(chn, param); break;
  4036. // E2x: Fine Portamento Down
  4037. case 0x20: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FinePortamentoDown(chn, param); break;
  4038. // E3x: Set Glissando Control
  4039. case 0x30: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break;
  4040. // E4x: Set Vibrato WaveForm
  4041. case 0x40: chn.nVibratoType = param & 0x07; break;
  4042. // E5x: Set FineTune
  4043. case 0x50: if(!m_SongFlags[SONG_FIRSTTICK])
  4044. break;
  4045. if(GetType() & (MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_AMF0 | MOD_TYPE_MED))
  4046. {
  4047. chn.nFineTune = MOD2XMFineTune(param);
  4048. if(chn.nPeriod && chn.rowCommand.IsNote()) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
  4049. } else if(GetType() == MOD_TYPE_MTM)
  4050. {
  4051. if(chn.rowCommand.IsNote() && chn.pModSample != nullptr)
  4052. {
  4053. // Effect is permanent in MultiTracker
  4054. const_cast<ModSample *>(chn.pModSample)->nFineTune = param;
  4055. chn.nFineTune = param;
  4056. if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
  4057. }
  4058. } else if(chn.rowCommand.IsNote())
  4059. {
  4060. chn.nFineTune = MOD2XMFineTune(param - 8);
  4061. if(chn.nPeriod) chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
  4062. }
  4063. break;
  4064. // E6x: Pattern Loop
  4065. case 0x60:
  4066. if(m_SongFlags[SONG_FIRSTTICK])
  4067. PatternLoop(m_PlayState, chn, param & 0x0F);
  4068. break;
  4069. // E7x: Set Tremolo WaveForm
  4070. case 0x70: chn.nTremoloType = param & 0x07; break;
  4071. // E8x: Set 4-bit Panning
  4072. case 0x80:
  4073. if(m_SongFlags[SONG_FIRSTTICK])
  4074. {
  4075. Panning(chn, param, Pan4bit);
  4076. }
  4077. break;
  4078. // E9x: Retrig
  4079. case 0x90: RetrigNote(nChn, param); break;
  4080. // EAx: Fine Volume Up
  4081. case 0xA0: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeUp(chn, param, false); break;
  4082. // EBx: Fine Volume Down
  4083. case 0xB0: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(chn, param, false); break;
  4084. // ECx: Note Cut
  4085. case 0xC0: NoteCut(nChn, param, false); break;
  4086. // EDx: Note Delay
  4087. // EEx: Pattern Delay
  4088. case 0xF0:
  4089. if(GetType() == MOD_TYPE_MOD) // MOD: Invert Loop
  4090. {
  4091. chn.nEFxSpeed = param;
  4092. if(m_SongFlags[SONG_FIRSTTICK]) InvertLoop(chn);
  4093. } else // XM: Set Active Midi Macro
  4094. {
  4095. chn.nActiveMacro = param;
  4096. }
  4097. break;
  4098. }
  4099. }
  4100. void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
  4101. {
  4102. ModChannel &chn = m_PlayState.Chn[nChn];
  4103. uint8 command = param & 0xF0;
  4104. param &= 0x0F;
  4105. switch(command)
  4106. {
  4107. // S0x: Set Filter
  4108. // S1x: Set Glissando Control
  4109. case 0x10: chn.dwFlags.set(CHN_GLISSANDO, param != 0); break;
  4110. // S2x: Set FineTune
  4111. case 0x20: if(!m_SongFlags[SONG_FIRSTTICK])
  4112. break;
  4113. if(chn.HasCustomTuning())
  4114. {
  4115. chn.nFineTune = param - 8;
  4116. chn.m_CalculateFreq = true;
  4117. } else if(GetType() != MOD_TYPE_669)
  4118. {
  4119. chn.nC5Speed = S3MFineTuneTable[param];
  4120. chn.nFineTune = MOD2XMFineTune(param);
  4121. if(chn.nPeriod)
  4122. chn.nPeriod = GetPeriodFromNote(chn.nNote, chn.nFineTune, chn.nC5Speed);
  4123. } else if(chn.pModSample != nullptr)
  4124. {
  4125. chn.nC5Speed = chn.pModSample->nC5Speed + param * 80;
  4126. }
  4127. break;
  4128. // S3x: Set Vibrato Waveform
  4129. case 0x30: if(GetType() == MOD_TYPE_S3M)
  4130. {
  4131. chn.nVibratoType = param & 0x03;
  4132. } else
  4133. {
  4134. // IT compatibility: Ignore waveform types > 3
  4135. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  4136. chn.nVibratoType = (param < 0x04) ? param : 0;
  4137. else
  4138. chn.nVibratoType = param & 0x07;
  4139. }
  4140. break;
  4141. // S4x: Set Tremolo Waveform
  4142. case 0x40: if(GetType() == MOD_TYPE_S3M)
  4143. {
  4144. chn.nTremoloType = param & 0x03;
  4145. } else
  4146. {
  4147. // IT compatibility: Ignore waveform types > 3
  4148. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  4149. chn.nTremoloType = (param < 0x04) ? param : 0;
  4150. else
  4151. chn.nTremoloType = param & 0x07;
  4152. }
  4153. break;
  4154. // S5x: Set Panbrello Waveform
  4155. case 0x50:
  4156. // IT compatibility: Ignore waveform types > 3
  4157. if(m_playBehaviour[kITVibratoTremoloPanbrello])
  4158. {
  4159. chn.nPanbrelloType = (param < 0x04) ? param : 0;
  4160. chn.nPanbrelloPos = 0;
  4161. } else
  4162. {
  4163. chn.nPanbrelloType = param & 0x07;
  4164. }
  4165. break;
  4166. // S6x: Pattern Delay for x frames
  4167. case 0x60:
  4168. if(m_SongFlags[SONG_FIRSTTICK] && m_PlayState.m_nTickCount == 0)
  4169. {
  4170. // Tick delays are added up.
  4171. // Scream Tracker 3 does actually not support this command.
  4172. // We'll use the same behaviour as for Impulse Tracker, as we can assume that
  4173. // most S3Ms that make use of this command were made with Impulse Tracker.
  4174. // MPT added this command to the XM format through the X6x effect, so we will use
  4175. // the same behaviour here as well.
  4176. // Test cases: PatternDelays.it, PatternDelays.s3m, PatternDelays.xm
  4177. m_PlayState.m_nFrameDelay += param;
  4178. }
  4179. break;
  4180. // S7x: Envelope Control / Instrument Control
  4181. case 0x70: if(!m_SongFlags[SONG_FIRSTTICK]) break;
  4182. switch(param)
  4183. {
  4184. case 0:
  4185. case 1:
  4186. case 2:
  4187. {
  4188. for (CHANNELINDEX i = m_nChannels; i < MAX_CHANNELS; i++)
  4189. {
  4190. ModChannel &bkChn = m_PlayState.Chn[i];
  4191. if (bkChn.nMasterChn == nChn + 1)
  4192. {
  4193. if (param == 1)
  4194. {
  4195. KeyOff(bkChn);
  4196. if(bkChn.dwFlags[CHN_ADLIB] && m_opl)
  4197. m_opl->NoteOff(i);
  4198. } else if (param == 2)
  4199. {
  4200. bkChn.dwFlags.set(CHN_NOTEFADE);
  4201. if(bkChn.dwFlags[CHN_ADLIB] && m_opl)
  4202. m_opl->NoteOff(i);
  4203. } else
  4204. {
  4205. bkChn.dwFlags.set(CHN_NOTEFADE);
  4206. bkChn.nFadeOutVol = 0;
  4207. if(bkChn.dwFlags[CHN_ADLIB] && m_opl)
  4208. m_opl->NoteCut(i);
  4209. }
  4210. #ifndef NO_PLUGINS
  4211. const ModInstrument *pIns = bkChn.pModInstrument;
  4212. IMixPlugin *pPlugin;
  4213. if(pIns != nullptr && pIns->nMixPlug && (pPlugin = m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin) != nullptr)
  4214. {
  4215. pPlugin->MidiCommand(*pIns, bkChn.nNote + NOTE_MAX_SPECIAL, 0, nChn);
  4216. }
  4217. #endif // NO_PLUGINS
  4218. }
  4219. }
  4220. }
  4221. break;
  4222. default: // S73-S7E
  4223. chn.InstrumentControl(param, *this);
  4224. break;
  4225. }
  4226. break;
  4227. // S8x: Set 4-bit Panning
  4228. case 0x80:
  4229. if(m_SongFlags[SONG_FIRSTTICK])
  4230. {
  4231. Panning(chn, param, Pan4bit);
  4232. }
  4233. break;
  4234. // S9x: Sound Control
  4235. case 0x90: ExtendedChannelEffect(chn, param); break;
  4236. // SAx: Set 64k Offset
  4237. case 0xA0: if(m_SongFlags[SONG_FIRSTTICK])
  4238. {
  4239. chn.nOldHiOffset = static_cast<uint8>(param);
  4240. if (!m_playBehaviour[kITHighOffsetNoRetrig] && chn.rowCommand.IsNote())
  4241. {
  4242. SmpLength pos = param << 16;
  4243. if (pos < chn.nLength) chn.position.SetInt(pos);
  4244. }
  4245. }
  4246. break;
  4247. // SBx: Pattern Loop
  4248. case 0xB0:
  4249. if(m_SongFlags[SONG_FIRSTTICK])
  4250. PatternLoop(m_PlayState, chn, param & 0x0F);
  4251. break;
  4252. // SCx: Note Cut
  4253. case 0xC0:
  4254. if(param == 0)
  4255. {
  4256. //IT compatibility 22. SC0 == SC1
  4257. if(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT))
  4258. param = 1;
  4259. // ST3 doesn't cut notes with SC0
  4260. else if(GetType() == MOD_TYPE_S3M)
  4261. return;
  4262. }
  4263. // S3M/IT compatibility: Note Cut really cuts notes and does not just mute them (so that following volume commands could restore the sample)
  4264. // Test case: scx.it
  4265. NoteCut(nChn, param, m_playBehaviour[kITSCxStopsSample] || GetType() == MOD_TYPE_S3M);
  4266. break;
  4267. // SDx: Note Delay
  4268. // SEx: Pattern Delay for x rows
  4269. // SFx: S3M: Not used, IT: Set Active Midi Macro
  4270. case 0xF0:
  4271. if(GetType() != MOD_TYPE_S3M)
  4272. {
  4273. chn.nActiveMacro = static_cast<uint8>(param);
  4274. }
  4275. break;
  4276. }
  4277. }
  4278. void CSoundFile::ExtendedChannelEffect(ModChannel &chn, uint32 param)
  4279. {
  4280. // S9x and X9x commands (S3M/XM/IT only)
  4281. if(!m_SongFlags[SONG_FIRSTTICK]) return;
  4282. switch(param & 0x0F)
  4283. {
  4284. // S90: Surround Off
  4285. case 0x00: chn.dwFlags.reset(CHN_SURROUND); break;
  4286. // S91: Surround On
  4287. case 0x01: chn.dwFlags.set(CHN_SURROUND); chn.nPan = 128; break;
  4288. ////////////////////////////////////////////////////////////
  4289. // ModPlug Extensions
  4290. // S98: Reverb Off
  4291. case 0x08:
  4292. chn.dwFlags.reset(CHN_REVERB);
  4293. chn.dwFlags.set(CHN_NOREVERB);
  4294. break;
  4295. // S99: Reverb On
  4296. case 0x09:
  4297. chn.dwFlags.reset(CHN_NOREVERB);
  4298. chn.dwFlags.set(CHN_REVERB);
  4299. break;
  4300. // S9A: 2-Channels surround mode
  4301. case 0x0A:
  4302. m_SongFlags.reset(SONG_SURROUNDPAN);
  4303. break;
  4304. // S9B: 4-Channels surround mode
  4305. case 0x0B:
  4306. m_SongFlags.set(SONG_SURROUNDPAN);
  4307. break;
  4308. // S9C: IT Filter Mode
  4309. case 0x0C:
  4310. m_SongFlags.reset(SONG_MPTFILTERMODE);
  4311. break;
  4312. // S9D: MPT Filter Mode
  4313. case 0x0D:
  4314. m_SongFlags.set(SONG_MPTFILTERMODE);
  4315. break;
  4316. // S9E: Go forward
  4317. case 0x0E:
  4318. chn.dwFlags.reset(CHN_PINGPONGFLAG);
  4319. break;
  4320. // S9F: Go backward (and set playback position to the end if sample just started)
  4321. case 0x0F:
  4322. if(chn.position.IsZero() && chn.nLength && (chn.rowCommand.IsNote() || !chn.dwFlags[CHN_LOOP]))
  4323. {
  4324. chn.position.Set(chn.nLength - 1, SamplePosition::fractMax);
  4325. }
  4326. chn.dwFlags.set(CHN_PINGPONGFLAG);
  4327. break;
  4328. }
  4329. }
  4330. void CSoundFile::InvertLoop(ModChannel &chn)
  4331. {
  4332. // EFx implementation for MOD files (PT 1.1A and up: Invert Loop)
  4333. // This effect trashes samples. Thanks to 8bitbubsy for making this work. :)
  4334. if(GetType() != MOD_TYPE_MOD || chn.nEFxSpeed == 0)
  4335. return;
  4336. ModSample *pModSample = const_cast<ModSample *>(chn.pModSample);
  4337. if(pModSample == nullptr || !pModSample->HasSampleData() || !pModSample->uFlags[CHN_LOOP | CHN_SUSTAINLOOP])
  4338. return;
  4339. chn.nEFxDelay += ModEFxTable[chn.nEFxSpeed & 0x0F];
  4340. if(chn.nEFxDelay < 128)
  4341. return;
  4342. chn.nEFxDelay = 0;
  4343. const SmpLength loopStart = pModSample->uFlags[CHN_LOOP] ? pModSample->nLoopStart : pModSample->nSustainStart;
  4344. const SmpLength loopEnd = pModSample->uFlags[CHN_LOOP] ? pModSample->nLoopEnd : pModSample->nSustainEnd;
  4345. if(++chn.nEFxOffset >= loopEnd - loopStart)
  4346. chn.nEFxOffset = 0;
  4347. // TRASH IT!!! (Yes, the sample!)
  4348. const uint8 bps = pModSample->GetBytesPerSample();
  4349. uint8 *begin = mpt::byte_cast<uint8 *>(pModSample->sampleb()) + (loopStart + chn.nEFxOffset) * bps;
  4350. for(auto &sample : mpt::as_span(begin, bps))
  4351. {
  4352. sample = ~sample;
  4353. }
  4354. pModSample->PrecomputeLoops(*this, false);
  4355. }
  4356. // Process a MIDI Macro.
  4357. // Parameters:
  4358. // playState: The playback state to operate on.
  4359. // nChn: Mod channel to apply macro on
  4360. // isSmooth: If true, internal macros are interpolated between two rows
  4361. // macro: MIDI Macro string to process
  4362. // param: Parameter for parametric macros (Zxx / \xx parameter)
  4363. // plugin: Plugin to send MIDI message to (if not specified but needed, it is autodetected)
  4364. void CSoundFile::ProcessMIDIMacro(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const MIDIMacroConfigData::Macro &macro, uint8 param, PLUGINDEX plugin)
  4365. {
  4366. playState.m_midiMacroScratchSpace.resize(macro.Length() + 1);
  4367. auto out = mpt::as_span(playState.m_midiMacroScratchSpace);
  4368. ParseMIDIMacro(playState, nChn, isSmooth, macro, out, param, plugin);
  4369. // Macro string has been parsed and translated, now send the message(s)...
  4370. uint32 outSize = static_cast<uint32>(out.size());
  4371. uint32 sendPos = 0;
  4372. uint8 runningStatus = 0;
  4373. while(sendPos < out.size())
  4374. {
  4375. uint32 sendLen = 0;
  4376. if(out[sendPos] == 0xF0)
  4377. {
  4378. // SysEx start
  4379. if((outSize - sendPos >= 4) && (out[sendPos + 1] == 0xF0 || out[sendPos + 1] == 0xF1))
  4380. {
  4381. // Internal macro (normal (F0F0) or extended (F0F1)), 4 bytes long
  4382. sendLen = 4;
  4383. } else
  4384. {
  4385. // SysEx message, find end of message
  4386. for(uint32 i = sendPos + 1; i < outSize; i++)
  4387. {
  4388. if(out[i] == 0xF7)
  4389. {
  4390. // Found end of SysEx message
  4391. sendLen = i - sendPos + 1;
  4392. break;
  4393. }
  4394. }
  4395. if(sendLen == 0)
  4396. {
  4397. // Didn't find end, so "invent" end of SysEx message
  4398. out[outSize++] = 0xF7;
  4399. sendLen = outSize - sendPos;
  4400. }
  4401. }
  4402. } else if(!(out[sendPos] & 0x80))
  4403. {
  4404. // Missing status byte? Try inserting running status
  4405. if(runningStatus != 0)
  4406. {
  4407. sendPos--;
  4408. out[sendPos] = runningStatus;
  4409. } else
  4410. {
  4411. // No running status to re-use; skip this byte
  4412. sendPos++;
  4413. }
  4414. continue;
  4415. } else
  4416. {
  4417. // Other MIDI messages
  4418. sendLen = std::min(static_cast<uint32>(MIDIEvents::GetEventLength(out[sendPos])), outSize - sendPos);
  4419. }
  4420. if(sendLen == 0)
  4421. break;
  4422. if(out[sendPos] < 0xF0)
  4423. {
  4424. runningStatus = out[sendPos];
  4425. }
  4426. const auto midiMsg = out.subspan(sendPos, sendLen);
  4427. SendMIDIData(playState, nChn, isSmooth, midiMsg, plugin);
  4428. sendPos += sendLen;
  4429. }
  4430. }
  4431. void CSoundFile::ParseMIDIMacro(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span<const char> macro, mpt::span<uint8> &out, uint8 param, PLUGINDEX plugin) const
  4432. {
  4433. ModChannel &chn = playState.Chn[nChn];
  4434. const ModInstrument *pIns = chn.pModInstrument;
  4435. const uint8 lastZxxParam = chn.lastZxxParam; // always interpolate based on original value in case z appears multiple times in macro string
  4436. uint8 updateZxxParam = 0xFF; // avoid updating lastZxxParam immediately if macro contains both internal and external MIDI message
  4437. bool firstNibble = true;
  4438. size_t outPos = 0; // output buffer position, which also equals the number of complete bytes
  4439. for(size_t pos = 0; pos < macro.size() && outPos < out.size(); pos++)
  4440. {
  4441. bool isNibble = false; // did we parse a nibble or a byte value?
  4442. uint8 data = 0; // data that has just been parsed
  4443. // Parse next macro byte... See Impulse Tracker's MIDI.TXT for detailed information on each possible character.
  4444. if(macro[pos] >= '0' && macro[pos] <= '9')
  4445. {
  4446. isNibble = true;
  4447. data = static_cast<uint8>(macro[pos] - '0');
  4448. } else if(macro[pos] >= 'A' && macro[pos] <= 'F')
  4449. {
  4450. isNibble = true;
  4451. data = static_cast<uint8>(macro[pos] - 'A' + 0x0A);
  4452. } else if(macro[pos] == 'c')
  4453. {
  4454. // MIDI channel
  4455. isNibble = true;
  4456. data = 0xFF;
  4457. #ifndef NO_PLUGINS
  4458. const PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(playState, nChn, PrioritiseChannel, EvenIfMuted);
  4459. if(plug > 0 && plug <= MAX_MIXPLUGINS)
  4460. {
  4461. auto midiPlug = dynamic_cast<const IMidiPlugin *>(m_MixPlugins[plug - 1u].pMixPlugin);
  4462. if(midiPlug)
  4463. data = midiPlug->GetMidiChannel(playState.Chn[nChn], nChn);
  4464. }
  4465. #endif // NO_PLUGINS
  4466. if(data == 0xFF)
  4467. {
  4468. // Fallback if no plugin was found
  4469. if(pIns)
  4470. data = pIns->GetMIDIChannel(playState.Chn[nChn], nChn);
  4471. else
  4472. data = 0;
  4473. }
  4474. } else if(macro[pos] == 'n')
  4475. {
  4476. // Last triggered note
  4477. if(ModCommand::IsNote(chn.nLastNote))
  4478. {
  4479. data = chn.nLastNote - NOTE_MIN;
  4480. }
  4481. } else if(macro[pos] == 'v')
  4482. {
  4483. // Velocity
  4484. // This is "almost" how IT does it - apparently, IT seems to lag one row behind on global volume or channel volume changes.
  4485. const int swing = (m_playBehaviour[kITSwingBehaviour] || m_playBehaviour[kMPTOldSwingBehaviour]) ? chn.nVolSwing : 0;
  4486. const int vol = Util::muldiv((chn.nVolume + swing) * m_PlayState.m_nGlobalVolume, chn.nGlobalVol * chn.nInsVol, 1 << 20);
  4487. data = static_cast<uint8>(Clamp(vol / 2, 1, 127));
  4488. //data = (unsigned char)std::min((chn.nVolume * chn.nGlobalVol * m_nGlobalVolume) >> (1 + 6 + 8), 127);
  4489. } else if(macro[pos] == 'u')
  4490. {
  4491. // Calculated volume
  4492. // Same note as with velocity applies here, but apparently also for instrument / sample volumes?
  4493. const int vol = Util::muldiv(chn.nCalcVolume * m_PlayState.m_nGlobalVolume, chn.nGlobalVol * chn.nInsVol, 1 << 26);
  4494. data = static_cast<uint8>(Clamp(vol / 2, 1, 127));
  4495. //data = (unsigned char)std::min((chn.nCalcVolume * chn.nGlobalVol * m_nGlobalVolume) >> (7 + 6 + 8), 127);
  4496. } else if(macro[pos] == 'x')
  4497. {
  4498. // Pan set
  4499. data = static_cast<uint8>(std::min(static_cast<int>(chn.nPan / 2), 127));
  4500. } else if(macro[pos] == 'y')
  4501. {
  4502. // Calculated pan
  4503. data = static_cast<uint8>(std::min(static_cast<int>(chn.nRealPan / 2), 127));
  4504. } else if(macro[pos] == 'a')
  4505. {
  4506. // High byte of bank select
  4507. if(pIns && pIns->wMidiBank)
  4508. {
  4509. data = static_cast<uint8>(((pIns->wMidiBank - 1) >> 7) & 0x7F);
  4510. }
  4511. } else if(macro[pos] == 'b')
  4512. {
  4513. // Low byte of bank select
  4514. if(pIns && pIns->wMidiBank)
  4515. {
  4516. data = static_cast<uint8>((pIns->wMidiBank - 1) & 0x7F);
  4517. }
  4518. } else if(macro[pos] == 'o')
  4519. {
  4520. // Offset (ignoring high offset)
  4521. data = static_cast<uint8>((chn.oldOffset >> 8) & 0xFF);
  4522. } else if(macro[pos] == 'h')
  4523. {
  4524. // Host channel number
  4525. data = static_cast<uint8>((nChn >= GetNumChannels() ? (chn.nMasterChn - 1) : nChn) & 0x7F);
  4526. } else if(macro[pos] == 'm')
  4527. {
  4528. // Loop direction (judging from the character, it was supposed to be loop type, though)
  4529. data = chn.dwFlags[CHN_PINGPONGFLAG] ? 1 : 0;
  4530. } else if(macro[pos] == 'p')
  4531. {
  4532. // Program select
  4533. if(pIns && pIns->nMidiProgram)
  4534. {
  4535. data = static_cast<uint8>((pIns->nMidiProgram - 1) & 0x7F);
  4536. }
  4537. } else if(macro[pos] == 'z')
  4538. {
  4539. // Zxx parameter
  4540. data = param;
  4541. if(isSmooth && chn.lastZxxParam < 0x80
  4542. && (outPos < 3 || out[outPos - 3] != 0xF0 || out[outPos - 2] < 0xF0))
  4543. {
  4544. // Interpolation for external MIDI messages - interpolation for internal messages
  4545. // is handled separately to allow for more than 7-bit granularity where it's possible
  4546. data = static_cast<uint8>(CalculateSmoothParamChange(playState, lastZxxParam, data));
  4547. chn.lastZxxParam = data;
  4548. updateZxxParam = 0x80;
  4549. } else if(updateZxxParam == 0xFF)
  4550. {
  4551. updateZxxParam = data;
  4552. }
  4553. } else if(macro[pos] == 's')
  4554. {
  4555. // SysEx Checksum (not an original Impulse Tracker macro variable, but added for convenience)
  4556. auto startPos = outPos;
  4557. while(startPos > 0 && out[--startPos] != 0xF0);
  4558. if(outPos - startPos < 5 || out[startPos] != 0xF0)
  4559. {
  4560. continue;
  4561. }
  4562. for(auto p = startPos + 5u; p != outPos; p++)
  4563. {
  4564. data += out[p];
  4565. }
  4566. data = (~data + 1) & 0x7F;
  4567. } else
  4568. {
  4569. // Unrecognized byte (e.g. space char)
  4570. continue;
  4571. }
  4572. // Append parsed data
  4573. if(isNibble) // parsed a nibble (constant or 'c' variable)
  4574. {
  4575. if(firstNibble)
  4576. {
  4577. out[outPos] = data;
  4578. } else
  4579. {
  4580. out[outPos] = (out[outPos] << 4) | data;
  4581. outPos++;
  4582. }
  4583. firstNibble = !firstNibble;
  4584. } else // parsed a byte (variable)
  4585. {
  4586. if(!firstNibble) // From MIDI.TXT: '9n' is exactly the same as '09 n' or '9 n' -- so finish current byte first
  4587. {
  4588. outPos++;
  4589. }
  4590. out[outPos++] = data;
  4591. firstNibble = true;
  4592. }
  4593. }
  4594. if(!firstNibble)
  4595. {
  4596. // Finish current byte
  4597. outPos++;
  4598. }
  4599. if(updateZxxParam < 0x80)
  4600. chn.lastZxxParam = updateZxxParam;
  4601. out = out.first(outPos);
  4602. }
  4603. // Calculate smooth MIDI macro slide parameter for current tick.
  4604. float CSoundFile::CalculateSmoothParamChange(const PlayState &playState, float currentValue, float param)
  4605. {
  4606. MPT_ASSERT(playState.TicksOnRow() > playState.m_nTickCount);
  4607. const uint32 ticksLeft = playState.TicksOnRow() - playState.m_nTickCount;
  4608. if(ticksLeft > 1)
  4609. {
  4610. // Slide param
  4611. const float step = (param - currentValue) / static_cast<float>(ticksLeft);
  4612. return (currentValue + step);
  4613. } else
  4614. {
  4615. // On last tick, set exact value.
  4616. return param;
  4617. }
  4618. }
  4619. // Process exactly one MIDI message parsed by ProcessMIDIMacro. Returns bytes sent on success, 0 on (parse) failure.
  4620. void CSoundFile::SendMIDIData(PlayState &playState, CHANNELINDEX nChn, bool isSmooth, const mpt::span<const uint8> macro, PLUGINDEX plugin)
  4621. {
  4622. if(macro.size() < 1)
  4623. return;
  4624. // Don't do anything that modifies state outside of the playState itself.
  4625. const bool localOnly = playState.m_midiMacroEvaluationResults.has_value();
  4626. if(macro[0] == 0xFA || macro[0] == 0xFC || macro[0] == 0xFF)
  4627. {
  4628. // Start Song, Stop Song, MIDI Reset - both interpreted internally and sent to plugins
  4629. for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++)
  4630. {
  4631. playState.Chn[chn].nCutOff = 0x7F;
  4632. playState.Chn[chn].nResonance = 0x00;
  4633. }
  4634. }
  4635. ModChannel &chn = playState.Chn[nChn];
  4636. if(macro.size() == 4 && macro[0] == 0xF0 && (macro[1] == 0xF0 || macro[1] == 0xF1))
  4637. {
  4638. // Internal device.
  4639. const bool isExtended = (macro[1] == 0xF1);
  4640. const uint8 macroCode = macro[2];
  4641. const uint8 param = macro[3];
  4642. if(macroCode == 0x00 && !isExtended && param < 0x80)
  4643. {
  4644. // F0.F0.00.xx: Set CutOff
  4645. if(!isSmooth)
  4646. chn.nCutOff = param;
  4647. else
  4648. chn.nCutOff = mpt::saturate_round<uint8>(CalculateSmoothParamChange(playState, chn.nCutOff, param));
  4649. chn.nRestoreCutoffOnNewNote = 0;
  4650. int cutoff = SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]);
  4651. if(cutoff >= 0 && chn.dwFlags[CHN_ADLIB] && m_opl && !localOnly)
  4652. {
  4653. // Cutoff doubles as modulator intensity for FM instruments
  4654. m_opl->Volume(nChn, static_cast<uint8>(cutoff / 4), true);
  4655. }
  4656. } else if(macroCode == 0x01 && !isExtended && param < 0x80)
  4657. {
  4658. // F0.F0.01.xx: Set Resonance
  4659. if(!isSmooth)
  4660. chn.nResonance = param;
  4661. else
  4662. chn.nResonance = mpt::saturate_round<uint8>(CalculateSmoothParamChange(playState, chn.nResonance, param));
  4663. chn.nRestoreResonanceOnNewNote = 0;
  4664. SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]);
  4665. } else if(macroCode == 0x02 && !isExtended)
  4666. {
  4667. // F0.F0.02.xx: Set filter mode (high nibble determines filter mode)
  4668. if(param < 0x20)
  4669. {
  4670. chn.nFilterMode = static_cast<FilterMode>(param >> 4);
  4671. SetupChannelFilter(chn, !chn.dwFlags[CHN_FILTER]);
  4672. }
  4673. #ifndef NO_PLUGINS
  4674. } else if(macroCode == 0x03 && !isExtended)
  4675. {
  4676. // F0.F0.03.xx: Set plug dry/wet
  4677. PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(playState, nChn, PrioritiseChannel, EvenIfMuted);
  4678. if(plug > 0 && plug <= MAX_MIXPLUGINS && param < 0x80)
  4679. {
  4680. plug--;
  4681. if(IMixPlugin* pPlugin = m_MixPlugins[plug].pMixPlugin; pPlugin)
  4682. {
  4683. const float newRatio = (127 - param) / 127.0f;
  4684. if(localOnly)
  4685. playState.m_midiMacroEvaluationResults->pluginDryWetRatio[plug] = newRatio;
  4686. else if(!isSmooth)
  4687. pPlugin->SetDryRatio(newRatio);
  4688. else
  4689. pPlugin->SetDryRatio(CalculateSmoothParamChange(playState, m_MixPlugins[plug].fDryRatio, newRatio));
  4690. }
  4691. }
  4692. } else if((macroCode & 0x80) || isExtended)
  4693. {
  4694. // F0.F0.{80|n}.xx / F0.F1.n.xx: Set VST effect parameter n to xx
  4695. PLUGINDEX plug = (plugin != 0) ? plugin : GetBestPlugin(playState, nChn, PrioritiseChannel, EvenIfMuted);
  4696. if(plug > 0 && plug <= MAX_MIXPLUGINS && param < 0x80)
  4697. {
  4698. plug--;
  4699. if(IMixPlugin *pPlugin = m_MixPlugins[plug].pMixPlugin; pPlugin)
  4700. {
  4701. const PlugParamIndex plugParam = isExtended ? (0x80 + macroCode) : (macroCode & 0x7F);
  4702. const PlugParamValue value = param / 127.0f;
  4703. if(localOnly)
  4704. playState.m_midiMacroEvaluationResults->pluginParameter[{plug, plugParam}] = value;
  4705. else if(!isSmooth)
  4706. pPlugin->SetParameter(plugParam, value);
  4707. else
  4708. pPlugin->SetParameter(plugParam, CalculateSmoothParamChange(playState, pPlugin->GetParameter(plugParam), value));
  4709. }
  4710. }
  4711. #endif // NO_PLUGINS
  4712. }
  4713. } else if(!localOnly)
  4714. {
  4715. #ifndef NO_PLUGINS
  4716. // Not an internal device. Pass on to appropriate plugin.
  4717. const CHANNELINDEX plugChannel = (nChn < GetNumChannels()) ? nChn + 1 : chn.nMasterChn;
  4718. if(plugChannel > 0 && plugChannel <= GetNumChannels()) // XXX do we need this? I guess it might be relevant for previewing notes in the pattern... Or when using this mechanism for volume/panning!
  4719. {
  4720. PLUGINDEX plug = 0;
  4721. if(!chn.dwFlags[CHN_NOFX])
  4722. {
  4723. plug = (plugin != 0) ? plugin : GetBestPlugin(playState, nChn, PrioritiseChannel, EvenIfMuted);
  4724. }
  4725. if(plug > 0 && plug <= MAX_MIXPLUGINS)
  4726. {
  4727. if(IMixPlugin *pPlugin = m_MixPlugins[plug - 1].pMixPlugin; pPlugin != nullptr)
  4728. {
  4729. if(macro[0] == 0xF0)
  4730. {
  4731. pPlugin->MidiSysexSend(mpt::byte_cast<mpt::const_byte_span>(macro));
  4732. } else
  4733. {
  4734. size_t len = std::min(static_cast<size_t>(MIDIEvents::GetEventLength(macro[0])), macro.size());
  4735. uint32 curData = 0;
  4736. memcpy(&curData, macro.data(), len);
  4737. pPlugin->MidiSend(curData);
  4738. }
  4739. }
  4740. }
  4741. }
  4742. #else
  4743. MPT_UNREFERENCED_PARAMETER(plugin);
  4744. #endif // NO_PLUGINS
  4745. }
  4746. }
  4747. void CSoundFile::SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume)
  4748. {
  4749. #ifndef NO_PLUGINS
  4750. auto &channel = m_PlayState.Chn[chn];
  4751. const ModInstrument *pIns = channel.pModInstrument;
  4752. // instro sends to a midi chan
  4753. if (pIns && pIns->HasValidMIDIChannel())
  4754. {
  4755. PLUGINDEX plug = pIns->nMixPlug;
  4756. if(plug > 0 && plug <= MAX_MIXPLUGINS)
  4757. {
  4758. IMixPlugin *pPlug = m_MixPlugins[plug - 1].pMixPlugin;
  4759. if (pPlug != nullptr)
  4760. {
  4761. pPlug->MidiCommand(*pIns, note, volume, chn);
  4762. if(note < NOTE_MIN_SPECIAL)
  4763. channel.nLeftVU = channel.nRightVU = 0xFF;
  4764. }
  4765. }
  4766. }
  4767. #endif // NO_PLUGINS
  4768. }
  4769. void CSoundFile::ProcessSampleOffset(ModChannel &chn, CHANNELINDEX nChn, const PlayState &playState) const
  4770. {
  4771. const ModCommand &m = chn.rowCommand;
  4772. uint32 extendedRows = 0;
  4773. SmpLength offset = CalculateXParam(playState.m_nPattern, playState.m_nRow, nChn, &extendedRows), highOffset = 0;
  4774. if(!extendedRows)
  4775. {
  4776. // No X-param (normal behaviour)
  4777. const bool isPercentageOffset = (m.volcmd == VOLCMD_OFFSET && m.vol == 0);
  4778. offset <<= 8;
  4779. if(offset)
  4780. chn.oldOffset = offset;
  4781. else if(m.volcmd != VOLCMD_OFFSET)
  4782. offset = chn.oldOffset;
  4783. if(!isPercentageOffset)
  4784. highOffset = static_cast<SmpLength>(chn.nOldHiOffset) << 16;
  4785. }
  4786. if(m.volcmd == VOLCMD_OFFSET)
  4787. {
  4788. if(m.vol == 0)
  4789. offset = Util::muldivr_unsigned(chn.nLength, offset, 256u << (8u * std::max(uint32(1), extendedRows))); // o00 + Oxx = Percentage Offset
  4790. else if(m.vol <= std::size(ModSample().cues) && chn.pModSample != nullptr)
  4791. offset += chn.pModSample->cues[m.vol - 1]; // Offset relative to cue point
  4792. chn.oldOffset = offset;
  4793. }
  4794. SampleOffset(chn, offset + highOffset);
  4795. }
  4796. void CSoundFile::SampleOffset(ModChannel &chn, SmpLength param) const
  4797. {
  4798. // ST3 compatibility: Instrument-less note recalls previous note's offset
  4799. // Test case: OxxMemory.s3m
  4800. if(m_playBehaviour[kST3OffsetWithoutInstrument])
  4801. chn.prevNoteOffset = 0;
  4802. chn.prevNoteOffset += param;
  4803. if(param >= chn.nLoopEnd && (GetType() & (MOD_TYPE_S3M | MOD_TYPE_MTM)) && chn.dwFlags[CHN_LOOP] && chn.nLoopEnd > 0)
  4804. {
  4805. // Offset wrap-around
  4806. // Note that ST3 only does this in GUS mode. SoundBlaster stops the sample entirely instead.
  4807. // Test case: OffsetLoopWraparound.s3m
  4808. param = (param - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart) + chn.nLoopStart;
  4809. }
  4810. if(GetType() == MOD_TYPE_MDL && chn.dwFlags[CHN_16BIT])
  4811. {
  4812. // Digitrakker really uses byte offsets, not sample offsets. WTF!
  4813. param /= 2u;
  4814. }
  4815. if(chn.rowCommand.IsNote() || m_playBehaviour[kApplyOffsetWithoutNote])
  4816. {
  4817. // IT compatibility: If this note is not mapped to a sample, ignore it.
  4818. // Test case: empty_sample_offset.it
  4819. if(chn.pModInstrument != nullptr && chn.rowCommand.IsNote())
  4820. {
  4821. SAMPLEINDEX smp = chn.pModInstrument->Keyboard[chn.rowCommand.note - NOTE_MIN];
  4822. if(smp == 0 || smp > GetNumSamples())
  4823. return;
  4824. }
  4825. if(m_SongFlags[SONG_PT_MODE])
  4826. {
  4827. // ProTracker compatbility: PT1/2-style funky 9xx offset command
  4828. // Test case: ptoffset.mod
  4829. chn.position.Set(chn.prevNoteOffset);
  4830. chn.prevNoteOffset += param;
  4831. } else
  4832. {
  4833. chn.position.Set(param);
  4834. }
  4835. if (chn.position.GetUInt() >= chn.nLength || (chn.dwFlags[CHN_LOOP] && chn.position.GetUInt() >= chn.nLoopEnd))
  4836. {
  4837. // Offset beyond sample size
  4838. if(m_playBehaviour[kFT2ST3OffsetOutOfRange] || GetType() == MOD_TYPE_MTM)
  4839. {
  4840. // FT2 Compatibility: Don't play note if offset is beyond sample length
  4841. // ST3 Compatibility: Don't play note if offset is beyond sample length (non-looped samples only)
  4842. // Test cases: 3xx-no-old-samp.xm, OffsetPastSampleEnd.s3m
  4843. chn.dwFlags.set(CHN_FASTVOLRAMP);
  4844. chn.nPeriod = 0;
  4845. } else if(!(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MOD)))
  4846. {
  4847. // IT Compatibility: Offset
  4848. if(m_playBehaviour[kITOffset])
  4849. {
  4850. if(m_SongFlags[SONG_ITOLDEFFECTS])
  4851. chn.position.Set(chn.nLength); // Old FX: Clip to end of sample
  4852. else
  4853. chn.position.Set(0); // Reset to beginning of sample
  4854. } else
  4855. {
  4856. chn.position.Set(chn.nLoopStart);
  4857. if(m_SongFlags[SONG_ITOLDEFFECTS] && chn.nLength > 4)
  4858. {
  4859. chn.position.Set(chn.nLength - 2);
  4860. }
  4861. }
  4862. } else if(GetType() == MOD_TYPE_MOD && chn.dwFlags[CHN_LOOP])
  4863. {
  4864. chn.position.Set(chn.nLoopStart);
  4865. }
  4866. }
  4867. } else if ((param < chn.nLength) && (GetType() & (MOD_TYPE_MTM | MOD_TYPE_DMF | MOD_TYPE_MDL | MOD_TYPE_PLM)))
  4868. {
  4869. // Some trackers can also call offset effects without notes next to them...
  4870. chn.position.Set(param);
  4871. }
  4872. }
  4873. void CSoundFile::ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) const
  4874. {
  4875. if(chn.pModSample != nullptr && chn.pModSample->nLength > 0)
  4876. {
  4877. chn.dwFlags.set(CHN_PINGPONGFLAG);
  4878. chn.dwFlags.reset(CHN_LOOP);
  4879. chn.nLength = chn.pModSample->nLength; // If there was a loop, extend sample to whole length.
  4880. chn.position.Set((chn.nLength - 1) - std::min(SmpLength(param) << 8, chn.nLength - SmpLength(1)), 0);
  4881. }
  4882. }
  4883. void CSoundFile::DigiBoosterSampleReverse(ModChannel &chn, ModCommand::PARAM param) const
  4884. {
  4885. if(chn.isFirstTick && chn.pModSample != nullptr && chn.pModSample->nLength > 0)
  4886. {
  4887. chn.dwFlags.set(CHN_PINGPONGFLAG);
  4888. chn.nLength = chn.pModSample->nLength; // If there was a loop, extend sample to whole length.
  4889. chn.position.Set(chn.nLength - 1, 0);
  4890. chn.dwFlags.set(CHN_LOOP | CHN_PINGPONGLOOP, param > 0);
  4891. if(param > 0)
  4892. {
  4893. chn.nLoopStart = 0;
  4894. chn.nLoopEnd = chn.nLength;
  4895. // TODO: When the sample starts playing in forward direction again, the loop should be updated to the normal sample loop.
  4896. }
  4897. }
  4898. }
  4899. void CSoundFile::HandleDigiSamplePlayDirection(PlayState &state, CHANNELINDEX chn) const
  4900. {
  4901. // Digi Booster mixes two channels into one Paula channel, and when a note is triggered on one of them it resets the reverse play flag on the other.
  4902. if(GetType() == MOD_TYPE_DIGI)
  4903. {
  4904. state.Chn[chn].dwFlags.reset(CHN_PINGPONGFLAG);
  4905. const CHANNELINDEX otherChn = chn ^ 1;
  4906. if(otherChn < GetNumChannels())
  4907. state.Chn[otherChn].dwFlags.reset(CHN_PINGPONGFLAG);
  4908. }
  4909. }
  4910. void CSoundFile::RetrigNote(CHANNELINDEX nChn, int param, int offset)
  4911. {
  4912. // Retrig: bit 8 is set if it's the new XM retrig
  4913. ModChannel &chn = m_PlayState.Chn[nChn];
  4914. int retrigSpeed = param & 0x0F;
  4915. uint8 retrigCount = chn.nRetrigCount;
  4916. bool doRetrig = false;
  4917. // IT compatibility 15. Retrigger
  4918. if(m_playBehaviour[kITRetrigger])
  4919. {
  4920. if(m_PlayState.m_nTickCount == 0 && chn.rowCommand.note)
  4921. {
  4922. chn.nRetrigCount = param & 0x0F;
  4923. } else if(!chn.nRetrigCount || !--chn.nRetrigCount)
  4924. {
  4925. chn.nRetrigCount = param & 0x0F;
  4926. doRetrig = true;
  4927. }
  4928. } else if(m_playBehaviour[kFT2Retrigger] && (param & 0x100))
  4929. {
  4930. // Buggy-like-hell FT2 Rxy retrig!
  4931. // Test case: retrig.xm
  4932. if(m_SongFlags[SONG_FIRSTTICK])
  4933. {
  4934. // Here are some really stupid things FT2 does on the first tick.
  4935. // Test case: RetrigTick0.xm
  4936. if(chn.rowCommand.instr > 0 && chn.rowCommand.IsNoteOrEmpty())
  4937. retrigCount = 1;
  4938. if(chn.rowCommand.volcmd == VOLCMD_VOLUME && chn.rowCommand.vol != 0)
  4939. {
  4940. // I guess this condition simply checked if the volume byte was != 0 in FT2.
  4941. chn.nRetrigCount = retrigCount;
  4942. return;
  4943. }
  4944. }
  4945. if(retrigCount >= retrigSpeed)
  4946. {
  4947. if(!m_SongFlags[SONG_FIRSTTICK] || !chn.rowCommand.IsNote())
  4948. {
  4949. doRetrig = true;
  4950. retrigCount = 0;
  4951. }
  4952. }
  4953. } else
  4954. {
  4955. // old routines
  4956. if (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))
  4957. {
  4958. if(!retrigSpeed)
  4959. retrigSpeed = 1;
  4960. if(retrigCount && !(retrigCount % retrigSpeed))
  4961. doRetrig = true;
  4962. retrigCount++;
  4963. } else if(GetType() == MOD_TYPE_MOD)
  4964. {
  4965. // ProTracker-style retrigger
  4966. // Test case: PTRetrigger.mod
  4967. const auto tick = m_PlayState.m_nTickCount % m_PlayState.m_nMusicSpeed;
  4968. if(!tick && chn.rowCommand.IsNote())
  4969. return;
  4970. if(retrigSpeed && !(tick % retrigSpeed))
  4971. doRetrig = true;
  4972. } else if(GetType() == MOD_TYPE_MTM)
  4973. {
  4974. // In MultiTracker, E9x retriggers the last note at exactly the x-th tick of the row
  4975. doRetrig = m_PlayState.m_nTickCount == static_cast<uint32>(param & 0x0F) && retrigSpeed != 0;
  4976. } else
  4977. {
  4978. int realspeed = retrigSpeed;
  4979. // FT2 bug: if a retrig (Rxy) occurs together with a volume command, the first retrig interval is increased by one tick
  4980. if((param & 0x100) && (chn.rowCommand.volcmd == VOLCMD_VOLUME) && (chn.rowCommand.param & 0xF0))
  4981. realspeed++;
  4982. if(!m_SongFlags[SONG_FIRSTTICK] || (param & 0x100))
  4983. {
  4984. if(!realspeed)
  4985. realspeed = 1;
  4986. if(!(param & 0x100) && m_PlayState.m_nMusicSpeed && !(m_PlayState.m_nTickCount % realspeed))
  4987. doRetrig = true;
  4988. retrigCount++;
  4989. } else if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
  4990. retrigCount = 0;
  4991. if (retrigCount >= realspeed)
  4992. {
  4993. if(m_PlayState.m_nTickCount || ((param & 0x100) && !chn.rowCommand.note))
  4994. doRetrig = true;
  4995. }
  4996. if(m_playBehaviour[kFT2Retrigger] && param == 0)
  4997. {
  4998. // E90 = Retrig instantly, and only once
  4999. doRetrig = (m_PlayState.m_nTickCount == 0);
  5000. }
  5001. }
  5002. }
  5003. // IT compatibility: If a sample is shorter than the retrig time (i.e. it stops before the retrig counter hits zero), it is not retriggered.
  5004. // Test case: retrig-short.it
  5005. if(chn.nLength == 0 && m_playBehaviour[kITShortSampleRetrig] && !chn.HasMIDIOutput())
  5006. return;
  5007. // ST3 compatibility: No retrig after Note Cut
  5008. // Test case: RetrigAfterNoteCut.s3m
  5009. if(m_playBehaviour[kST3RetrigAfterNoteCut] && !chn.nFadeOutVol)
  5010. return;
  5011. if(doRetrig)
  5012. {
  5013. uint32 dv = (param >> 4) & 0x0F;
  5014. int vol = chn.nVolume;
  5015. if(dv)
  5016. {
  5017. // FT2 compatibility: Retrig + volume will not change volume of retrigged notes
  5018. if(!m_playBehaviour[kFT2Retrigger] || !(chn.rowCommand.volcmd == VOLCMD_VOLUME))
  5019. {
  5020. if(retrigTable1[dv])
  5021. vol = (vol * retrigTable1[dv]) / 16;
  5022. else
  5023. vol += ((int)retrigTable2[dv]) * 4;
  5024. }
  5025. Limit(vol, 0, 256);
  5026. chn.dwFlags.set(CHN_FASTVOLRAMP);
  5027. }
  5028. uint32 note = chn.nNewNote;
  5029. int32 oldPeriod = chn.nPeriod;
  5030. // ST3 doesn't retrigger OPL notes
  5031. // Test case: RetrigSlide.s3m
  5032. const bool oplRealRetrig = chn.dwFlags[CHN_ADLIB] && m_playBehaviour[kOPLRealRetrig];
  5033. if(note >= NOTE_MIN && note <= NOTE_MAX && chn.nLength && (GetType() != MOD_TYPE_S3M || oplRealRetrig))
  5034. CheckNNA(nChn, 0, note, true);
  5035. bool resetEnv = false;
  5036. if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2))
  5037. {
  5038. if(chn.rowCommand.instr && param < 0x100)
  5039. {
  5040. InstrumentChange(chn, chn.rowCommand.instr, false, false);
  5041. resetEnv = true;
  5042. }
  5043. if(param < 0x100)
  5044. resetEnv = true;
  5045. }
  5046. const bool fading = chn.dwFlags[CHN_NOTEFADE];
  5047. const auto oldPrevNoteOffset = chn.prevNoteOffset;
  5048. chn.prevNoteOffset = 0; // Retriggered notes should not use previous offset (test case: OxxMemoryWithRetrig.s3m)
  5049. // IT compatibility: Really weird combination of envelopes and retrigger (see Storlek's q.it testcase)
  5050. // Test cases: retrig.it, RetrigSlide.s3m
  5051. const bool itS3Mstyle = m_playBehaviour[kITRetrigger] || (GetType() == MOD_TYPE_S3M && chn.nLength && !oplRealRetrig);
  5052. NoteChange(chn, note, itS3Mstyle, resetEnv, false, nChn);
  5053. if(!chn.rowCommand.instr)
  5054. chn.prevNoteOffset = oldPrevNoteOffset;
  5055. // XM compatibility: Prevent NoteChange from resetting the fade flag in case an instrument number + note-off is present.
  5056. // Test case: RetrigFade.xm
  5057. if(fading && GetType() == MOD_TYPE_XM)
  5058. chn.dwFlags.set(CHN_NOTEFADE);
  5059. chn.nVolume = vol;
  5060. if(m_nInstruments)
  5061. {
  5062. chn.rowCommand.note = static_cast<ModCommand::NOTE>(note); // No retrig without note...
  5063. #ifndef NO_PLUGINS
  5064. ProcessMidiOut(nChn); //Send retrig to Midi
  5065. #endif // NO_PLUGINS
  5066. }
  5067. if((GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT)) && chn.rowCommand.note == NOTE_NONE && oldPeriod != 0)
  5068. chn.nPeriod = oldPeriod;
  5069. if(!(GetType() & (MOD_TYPE_S3M | MOD_TYPE_IT | MOD_TYPE_MPT)))
  5070. retrigCount = 0;
  5071. // IT compatibility: see previous IT compatibility comment =)
  5072. if(itS3Mstyle)
  5073. chn.position.Set(0);
  5074. offset--;
  5075. if(chn.pModSample != nullptr && offset >= 0 && offset <= static_cast<int>(std::size(chn.pModSample->cues)))
  5076. {
  5077. if(offset == 0)
  5078. offset = chn.oldOffset;
  5079. else
  5080. offset = chn.oldOffset = chn.pModSample->cues[offset - 1];
  5081. SampleOffset(chn, offset);
  5082. }
  5083. }
  5084. // buggy-like-hell FT2 Rxy retrig!
  5085. if(m_playBehaviour[kFT2Retrigger] && (param & 0x100))
  5086. retrigCount++;
  5087. // Now we can also store the retrig value for IT...
  5088. if(!m_playBehaviour[kITRetrigger])
  5089. chn.nRetrigCount = retrigCount;
  5090. }
  5091. // Execute a frequency slide on given channel.
  5092. // Positive amounts increase the frequency, negative amounts decrease it.
  5093. // The period or frequency that is read and written is in the period variable, chn.nPeriod is not touched.
  5094. void CSoundFile::DoFreqSlide(ModChannel &chn, int32 &period, int32 amount, bool isTonePorta) const
  5095. {
  5096. if(!period || !amount)
  5097. return;
  5098. MPT_ASSERT(!chn.HasCustomTuning());
  5099. if(GetType() == MOD_TYPE_669)
  5100. {
  5101. // Like other oldskool trackers, Composer 669 doesn't have linear slides...
  5102. // But the slides are done in Hertz rather than periods, meaning that they
  5103. // are more effective in the lower notes (rather than the higher notes).
  5104. period += amount * 20;
  5105. } else if(GetType() == MOD_TYPE_FAR)
  5106. {
  5107. period += (amount * 36318 / 1024);
  5108. } else if(m_SongFlags[SONG_LINEARSLIDES] && GetType() != MOD_TYPE_XM)
  5109. {
  5110. // IT Linear slides
  5111. const auto oldPeriod = period;
  5112. uint32 n = std::abs(amount);
  5113. LimitMax(n, 255u * 4u);
  5114. // Note: IT ignores the lower 2 bits when abs(mount) > 16 (it either uses the fine *or* the regular table, not both)
  5115. // This means that vibratos are slightly less accurate in this range than they could be.
  5116. // Other code paths will *either* have an amount that's a multiple of 4 *or* it's less than 16.
  5117. if(amount > 0)
  5118. {
  5119. if(n < 16)
  5120. period = Util::muldivr(period, GetFineLinearSlideUpTable(this, n), 65536);
  5121. else
  5122. period = Util::muldivr(period, GetLinearSlideUpTable(this, n / 4u), 65536);
  5123. } else
  5124. {
  5125. if(n < 16)
  5126. period = Util::muldivr(period, GetFineLinearSlideDownTable(this, n), 65536);
  5127. else
  5128. period = Util::muldivr(period, GetLinearSlideDownTable(this, n / 4u), 65536);
  5129. }
  5130. if(period == oldPeriod)
  5131. {
  5132. const bool incPeriod = m_playBehaviour[kPeriodsAreHertz] == (amount > 0);
  5133. if(incPeriod && period < Util::MaxValueOfType(period))
  5134. period++;
  5135. else if(!incPeriod && period > 1)
  5136. period--;
  5137. }
  5138. } else if(!m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kPeriodsAreHertz])
  5139. {
  5140. // IT Amiga slides
  5141. if(amount < 0)
  5142. {
  5143. // Go down
  5144. period = mpt::saturate_cast<int32>(Util::mul32to64_unsigned(1712 * 8363, period) / (Util::mul32to64_unsigned(period, -amount) + 1712 * 8363));
  5145. } else if(amount > 0)
  5146. {
  5147. // Go up
  5148. const auto periodDiv = 1712 * 8363 - Util::mul32to64(period, amount);
  5149. if(periodDiv <= 0)
  5150. {
  5151. if(isTonePorta)
  5152. {
  5153. period = int32_max;
  5154. return;
  5155. } else
  5156. {
  5157. period = 0;
  5158. chn.nFadeOutVol = 0;
  5159. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  5160. }
  5161. return;
  5162. }
  5163. period = mpt::saturate_cast<int32>(Util::mul32to64_unsigned(1712 * 8363, period) / periodDiv);
  5164. }
  5165. } else
  5166. {
  5167. period -= amount;
  5168. }
  5169. if(period < 1)
  5170. {
  5171. period = 1;
  5172. if(GetType() == MOD_TYPE_S3M && !isTonePorta)
  5173. {
  5174. chn.nFadeOutVol = 0;
  5175. chn.dwFlags.set(CHN_NOTEFADE | CHN_FASTVOLRAMP);
  5176. }
  5177. }
  5178. }
  5179. void CSoundFile::NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample)
  5180. {
  5181. if (m_PlayState.m_nTickCount == nTick)
  5182. {
  5183. ModChannel &chn = m_PlayState.Chn[nChn];
  5184. if(cutSample)
  5185. {
  5186. chn.increment.Set(0);
  5187. chn.nFadeOutVol = 0;
  5188. chn.dwFlags.set(CHN_NOTEFADE);
  5189. } else
  5190. {
  5191. chn.nVolume = 0;
  5192. }
  5193. chn.dwFlags.set(CHN_FASTVOLRAMP);
  5194. // instro sends to a midi chan
  5195. SendMIDINote(nChn, /*chn.nNote+*/NOTE_MAX_SPECIAL, 0);
  5196. if(chn.dwFlags[CHN_ADLIB] && m_opl)
  5197. {
  5198. m_opl->NoteCut(nChn, false);
  5199. }
  5200. }
  5201. }
  5202. void CSoundFile::KeyOff(ModChannel &chn) const
  5203. {
  5204. const bool keyIsOn = !chn.dwFlags[CHN_KEYOFF];
  5205. chn.dwFlags.set(CHN_KEYOFF);
  5206. if(chn.pModInstrument != nullptr && !chn.VolEnv.flags[ENV_ENABLED])
  5207. {
  5208. chn.dwFlags.set(CHN_NOTEFADE);
  5209. }
  5210. if (!chn.nLength) return;
  5211. if (chn.dwFlags[CHN_SUSTAINLOOP] && chn.pModSample && keyIsOn)
  5212. {
  5213. const ModSample *pSmp = chn.pModSample;
  5214. if(pSmp->uFlags[CHN_LOOP])
  5215. {
  5216. if (pSmp->uFlags[CHN_PINGPONGLOOP])
  5217. chn.dwFlags.set(CHN_PINGPONGLOOP);
  5218. else
  5219. chn.dwFlags.reset(CHN_PINGPONGLOOP | CHN_PINGPONGFLAG);
  5220. chn.dwFlags.set(CHN_LOOP);
  5221. chn.nLength = pSmp->nLength;
  5222. chn.nLoopStart = pSmp->nLoopStart;
  5223. chn.nLoopEnd = pSmp->nLoopEnd;
  5224. if (chn.nLength > chn.nLoopEnd) chn.nLength = chn.nLoopEnd;
  5225. if(chn.position.GetUInt() > chn.nLength)
  5226. {
  5227. // Test case: SusAfterLoop.it
  5228. chn.position.Set(chn.nLoopStart + ((chn.position.GetInt() - chn.nLoopStart) % (chn.nLoopEnd - chn.nLoopStart)));
  5229. }
  5230. } else
  5231. {
  5232. chn.dwFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_PINGPONGFLAG);
  5233. chn.nLength = pSmp->nLength;
  5234. }
  5235. }
  5236. if (chn.pModInstrument)
  5237. {
  5238. const ModInstrument *pIns = chn.pModInstrument;
  5239. if((pIns->VolEnv.dwFlags[ENV_LOOP] || (GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MDL))) && pIns->nFadeOut != 0)
  5240. {
  5241. chn.dwFlags.set(CHN_NOTEFADE);
  5242. }
  5243. if (pIns->VolEnv.nReleaseNode != ENV_RELEASE_NODE_UNSET && chn.VolEnv.nEnvValueAtReleaseJump == NOT_YET_RELEASED)
  5244. {
  5245. chn.VolEnv.nEnvValueAtReleaseJump = mpt::saturate_cast<int16>(pIns->VolEnv.GetValueFromPosition(chn.VolEnv.nEnvPosition, 256));
  5246. chn.VolEnv.nEnvPosition = pIns->VolEnv[pIns->VolEnv.nReleaseNode].tick;
  5247. }
  5248. }
  5249. }
  5250. //////////////////////////////////////////////////////////
  5251. // CSoundFile: Global Effects
  5252. void CSoundFile::SetSpeed(PlayState &playState, uint32 param) const
  5253. {
  5254. #ifdef MODPLUG_TRACKER
  5255. // FT2 appears to be decrementing the tick count before checking for zero,
  5256. // so it effectively counts down 65536 ticks with speed = 0 (song speed is a 16-bit variable in FT2)
  5257. if(GetType() == MOD_TYPE_XM && !param)
  5258. {
  5259. playState.m_nMusicSpeed = uint16_max;
  5260. }
  5261. #endif // MODPLUG_TRACKER
  5262. if(param > 0) playState.m_nMusicSpeed = param;
  5263. if(GetType() == MOD_TYPE_STM && param > 0)
  5264. {
  5265. playState.m_nMusicSpeed = std::max(param >> 4, uint32(1));
  5266. playState.m_nMusicTempo = ConvertST2Tempo(static_cast<uint8>(param));
  5267. }
  5268. }
  5269. // Convert a ST2 tempo byte to classic tempo and speed combination
  5270. TEMPO CSoundFile::ConvertST2Tempo(uint8 tempo)
  5271. {
  5272. static constexpr uint8 ST2TempoFactor[] = { 140, 50, 25, 15, 10, 7, 6, 4, 3, 3, 2, 2, 2, 2, 1, 1 };
  5273. static constexpr uint32 st2MixingRate = 23863; // Highest possible setting in ST2
  5274. // This underflows at tempo 06...0F, and the resulting tick lengths depend on the mixing rate.
  5275. // Note: ST2.3 uses the constant 50 below, earlier versions use 49 but they also play samples at a different speed.
  5276. int32 samplesPerTick = st2MixingRate / (50 - ((ST2TempoFactor[tempo >> 4u] * (tempo & 0x0F)) >> 4u));
  5277. if(samplesPerTick <= 0)
  5278. samplesPerTick += 65536;
  5279. return TEMPO().SetRaw(Util::muldivrfloor(st2MixingRate, 5 * TEMPO::fractFact, samplesPerTick * 2));
  5280. }
  5281. void CSoundFile::SetTempo(TEMPO param, bool setFromUI)
  5282. {
  5283. const CModSpecifications &specs = GetModSpecifications();
  5284. // Anything lower than the minimum tempo is considered to be a tempo slide
  5285. const TEMPO minTempo = (GetType() & (MOD_TYPE_MDL | MOD_TYPE_MED | MOD_TYPE_MOD)) ? TEMPO(1, 0) : TEMPO(32, 0);
  5286. if(setFromUI)
  5287. {
  5288. // Set tempo from UI - ignore slide commands and such.
  5289. m_PlayState.m_nMusicTempo = Clamp(param, specs.GetTempoMin(), specs.GetTempoMax());
  5290. } else if(param >= minTempo && m_SongFlags[SONG_FIRSTTICK] == !m_playBehaviour[kMODTempoOnSecondTick])
  5291. {
  5292. // ProTracker sets the tempo after the first tick.
  5293. // Note: The case of one tick per row is handled in ProcessRow() instead.
  5294. // Test case: TempoChange.mod
  5295. m_PlayState.m_nMusicTempo = std::min(param, specs.GetTempoMax());
  5296. } else if(param < minTempo && !m_SongFlags[SONG_FIRSTTICK])
  5297. {
  5298. // Tempo Slide
  5299. TEMPO tempDiff(param.GetInt() & 0x0F, 0);
  5300. if((param.GetInt() & 0xF0) == 0x10)
  5301. m_PlayState.m_nMusicTempo += tempDiff;
  5302. else
  5303. m_PlayState.m_nMusicTempo -= tempDiff;
  5304. TEMPO tempoMin = specs.GetTempoMin(), tempoMax = specs.GetTempoMax();
  5305. if(m_playBehaviour[kTempoClamp]) // clamp tempo correctly in compatible mode
  5306. {
  5307. tempoMax.Set(255);
  5308. }
  5309. Limit(m_PlayState.m_nMusicTempo, tempoMin, tempoMax);
  5310. }
  5311. }
  5312. void CSoundFile::PatternLoop(PlayState &state, ModChannel &chn, ModCommand::PARAM param) const
  5313. {
  5314. if(m_playBehaviour[kST3NoMutedChannels] && chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE])
  5315. return; // not even effects are processed on muted S3M channels
  5316. if(!param)
  5317. {
  5318. // Loop Start
  5319. chn.nPatternLoop = state.m_nRow;
  5320. return;
  5321. }
  5322. // Loop Repeat
  5323. if(chn.nPatternLoopCount)
  5324. {
  5325. // There's a loop left
  5326. chn.nPatternLoopCount--;
  5327. if(!chn.nPatternLoopCount)
  5328. {
  5329. // IT compatibility 10. Pattern loops (+ same fix for S3M files)
  5330. // When finishing a pattern loop, the next loop without a dedicated SB0 starts on the first row after the previous loop.
  5331. if(m_playBehaviour[kITPatternLoopTargetReset] || (GetType() == MOD_TYPE_S3M))
  5332. chn.nPatternLoop = state.m_nRow + 1;
  5333. return;
  5334. }
  5335. } else
  5336. {
  5337. // First time we get into the loop => Set loop count.
  5338. // IT compatibility 10. Pattern loops (+ same fix for XM / MOD / S3M files)
  5339. if(!m_playBehaviour[kITFT2PatternLoop] && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_S3M)))
  5340. {
  5341. auto p = std::cbegin(state.Chn);
  5342. for(CHANNELINDEX i = 0; i < GetNumChannels(); i++, p++)
  5343. {
  5344. // Loop on other channel
  5345. if(p != &chn && p->nPatternLoopCount)
  5346. return;
  5347. }
  5348. }
  5349. chn.nPatternLoopCount = param;
  5350. }
  5351. state.m_nextPatStartRow = chn.nPatternLoop; // Nasty FT2 E60 bug emulation!
  5352. const auto loopTarget = chn.nPatternLoop;
  5353. if(loopTarget != ROWINDEX_INVALID)
  5354. {
  5355. // FT2 compatibility: E6x overwrites jump targets of Dxx effects that are located left of the E6x effect.
  5356. // Test cases: PatLoop-Jumps.xm, PatLoop-Various.xm
  5357. if(state.m_breakRow != ROWINDEX_INVALID && m_playBehaviour[kFT2PatternLoopWithJumps])
  5358. state.m_breakRow = loopTarget;
  5359. state.m_patLoopRow = loopTarget;
  5360. // IT compatibility: SBx is prioritized over Position Jump (Bxx) effects that are located left of the SBx effect.
  5361. // Test case: sbx-priority.it, LoopBreak.it
  5362. if(m_playBehaviour[kITPatternLoopWithJumps])
  5363. state.m_posJump = ORDERINDEX_INVALID;
  5364. }
  5365. if(GetType() == MOD_TYPE_S3M)
  5366. {
  5367. // ST3 doesn't have per-channel pattern loop memory, so spam all changes to other channels as well.
  5368. for(CHANNELINDEX i = 0; i < GetNumChannels(); i++)
  5369. {
  5370. state.Chn[i].nPatternLoop = chn.nPatternLoop;
  5371. state.Chn[i].nPatternLoopCount = chn.nPatternLoopCount;
  5372. }
  5373. }
  5374. }
  5375. void CSoundFile::GlobalVolSlide(ModCommand::PARAM param, uint8 &nOldGlobalVolSlide)
  5376. {
  5377. int32 nGlbSlide = 0;
  5378. if (param) nOldGlobalVolSlide = param; else param = nOldGlobalVolSlide;
  5379. if((GetType() & (MOD_TYPE_XM | MOD_TYPE_MT2)))
  5380. {
  5381. // XM nibble priority
  5382. if((param & 0xF0) != 0)
  5383. {
  5384. param &= 0xF0;
  5385. } else
  5386. {
  5387. param &= 0x0F;
  5388. }
  5389. }
  5390. if (((param & 0x0F) == 0x0F) && (param & 0xF0))
  5391. {
  5392. if(m_SongFlags[SONG_FIRSTTICK]) nGlbSlide = (param >> 4) * 2;
  5393. } else
  5394. if (((param & 0xF0) == 0xF0) && (param & 0x0F))
  5395. {
  5396. if(m_SongFlags[SONG_FIRSTTICK]) nGlbSlide = - (int)((param & 0x0F) * 2);
  5397. } else
  5398. {
  5399. if(!m_SongFlags[SONG_FIRSTTICK])
  5400. {
  5401. if (param & 0xF0)
  5402. {
  5403. // IT compatibility: Ignore slide commands with both nibbles set.
  5404. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM)) || (param & 0x0F) == 0)
  5405. nGlbSlide = (int)((param & 0xF0) >> 4) * 2;
  5406. } else
  5407. {
  5408. nGlbSlide = -(int)((param & 0x0F) * 2);
  5409. }
  5410. }
  5411. }
  5412. if (nGlbSlide)
  5413. {
  5414. if(!(GetType() & (MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_IMF | MOD_TYPE_J2B | MOD_TYPE_MID | MOD_TYPE_AMS | MOD_TYPE_DBM))) nGlbSlide *= 2;
  5415. nGlbSlide += m_PlayState.m_nGlobalVolume;
  5416. Limit(nGlbSlide, 0, 256);
  5417. m_PlayState.m_nGlobalVolume = nGlbSlide;
  5418. }
  5419. }
  5420. //////////////////////////////////////////////////////
  5421. // Note/Period/Frequency functions
  5422. // Find lowest note which has same or lower period as a given period (i.e. the note has the same or higher frequency)
  5423. uint32 CSoundFile::GetNoteFromPeriod(uint32 period, int32 nFineTune, uint32 nC5Speed) const
  5424. {
  5425. if(!period) return 0;
  5426. if(m_playBehaviour[kFT2Periods])
  5427. {
  5428. // FT2's "RelocateTon" function actually rounds up and down, while GetNoteFromPeriod normally just truncates.
  5429. nFineTune += 64;
  5430. }
  5431. // This essentially implements std::lower_bound, with the difference that we don't need an iterable container.
  5432. uint32 minNote = NOTE_MIN, maxNote = NOTE_MAX, count = maxNote - minNote + 1;
  5433. const bool periodIsFreq = PeriodsAreFrequencies();
  5434. while(count > 0)
  5435. {
  5436. const uint32 step = count / 2, midNote = minNote + step;
  5437. uint32 n = GetPeriodFromNote(midNote, nFineTune, nC5Speed);
  5438. if((n > period && !periodIsFreq) || (n < period && periodIsFreq) || !n)
  5439. {
  5440. minNote = midNote + 1;
  5441. count -= step + 1;
  5442. } else
  5443. {
  5444. count = step;
  5445. }
  5446. }
  5447. return minNote;
  5448. }
  5449. uint32 CSoundFile::GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Speed) const
  5450. {
  5451. if (note == NOTE_NONE || (note >= NOTE_MIN_SPECIAL)) return 0;
  5452. note -= NOTE_MIN;
  5453. if(!UseFinetuneAndTranspose())
  5454. {
  5455. if(GetType() & (MOD_TYPE_MDL | MOD_TYPE_DTM))
  5456. {
  5457. // MDL uses non-linear slides, but their effectiveness does not depend on the middle-C frequency.
  5458. return (FreqS3MTable[note % 12u] << 4) >> (note / 12);
  5459. }
  5460. if(!nC5Speed)
  5461. nC5Speed = 8363;
  5462. if(PeriodsAreFrequencies())
  5463. {
  5464. // Compute everything in Hertz rather than periods.
  5465. uint32 freq = Util::muldiv_unsigned(nC5Speed, LinearSlideUpTable[(note % 12u) * 16u] << (note / 12u), 65536 << 5);
  5466. LimitMax(freq, static_cast<uint32>(int32_max));
  5467. return freq;
  5468. } else if(m_SongFlags[SONG_LINEARSLIDES])
  5469. {
  5470. return (FreqS3MTable[note % 12u] << 5) >> (note / 12);
  5471. } else
  5472. {
  5473. LimitMax(nC5Speed, uint32_max >> (note / 12u));
  5474. //(a*b)/c
  5475. return Util::muldiv_unsigned(8363, (FreqS3MTable[note % 12u] << 5), nC5Speed << (note / 12u));
  5476. //8363 * freq[note%12] / nC5Speed * 2^(5-note/12)
  5477. }
  5478. } else if(GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM))
  5479. {
  5480. if (note < 12) note = 12;
  5481. note -= 12;
  5482. if(GetType() == MOD_TYPE_MTM)
  5483. {
  5484. nFineTune *= 16;
  5485. } else if(m_playBehaviour[kFT2FinetunePrecision])
  5486. {
  5487. // FT2 Compatibility: The lower three bits of the finetune are truncated.
  5488. // Test case: Finetune-Precision.xm
  5489. nFineTune &= ~7;
  5490. }
  5491. if(m_SongFlags[SONG_LINEARSLIDES])
  5492. {
  5493. int l = ((NOTE_MAX - note) << 6) - (nFineTune / 2);
  5494. if (l < 1) l = 1;
  5495. return static_cast<uint32>(l);
  5496. } else
  5497. {
  5498. int finetune = nFineTune;
  5499. uint32 rnote = (note % 12) << 3;
  5500. uint32 roct = note / 12;
  5501. int rfine = finetune / 16;
  5502. int i = rnote + rfine + 8;
  5503. Limit(i , 0, 103);
  5504. uint32 per1 = XMPeriodTable[i];
  5505. if(finetune < 0)
  5506. {
  5507. rfine--;
  5508. finetune = -finetune;
  5509. } else rfine++;
  5510. i = rnote+rfine+8;
  5511. if (i < 0) i = 0;
  5512. if (i >= 104) i = 103;
  5513. uint32 per2 = XMPeriodTable[i];
  5514. rfine = finetune & 0x0F;
  5515. per1 *= 16-rfine;
  5516. per2 *= rfine;
  5517. return ((per1 + per2) << 1) >> roct;
  5518. }
  5519. } else
  5520. {
  5521. nFineTune = XM2MODFineTune(nFineTune);
  5522. if ((nFineTune) || (note < 24) || (note >= 24 + std::size(ProTrackerPeriodTable)))
  5523. return (ProTrackerTunedPeriods[nFineTune * 12u + note % 12u] << 5) >> (note / 12u);
  5524. else
  5525. return (ProTrackerPeriodTable[note - 24] << 2);
  5526. }
  5527. }
  5528. // Converts period value to sample frequency. Return value is fixed point, with FREQ_FRACBITS fractional bits.
  5529. uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac) const
  5530. {
  5531. if (!period) return 0;
  5532. if (GetType() & (MOD_TYPE_XM | MOD_TYPE_MTM))
  5533. {
  5534. if(m_playBehaviour[kFT2Periods])
  5535. {
  5536. // FT2 compatibility: Period is a 16-bit value in FT2, and it overflows happily.
  5537. // Test case: FreqWraparound.xm
  5538. period &= 0xFFFF;
  5539. }
  5540. if(m_SongFlags[SONG_LINEARSLIDES])
  5541. {
  5542. uint32 octave;
  5543. if(m_playBehaviour[kFT2Periods])
  5544. {
  5545. // Under normal circumstances, this calculation returns the same values as the non-compatible one.
  5546. // However, once the 12 octaves are exceeded (through portamento slides), the octave shift goes
  5547. // crazy in FT2, meaning that the frequency wraps around randomly...
  5548. // The entries in FT2's conversion table are four times as big, hence we have to do an additional shift by two bits.
  5549. // Test case: FreqWraparound.xm
  5550. // 12 octaves * (12 * 64) LUT entries = 9216, add 767 for rounding
  5551. uint32 div = ((9216u + 767u - period) / 768);
  5552. octave = ((14 - div) & 0x1F);
  5553. } else
  5554. {
  5555. octave = (period / 768) + 2;
  5556. }
  5557. return (XMLinearTable[period % 768] << (FREQ_FRACBITS + 2)) >> octave;
  5558. } else
  5559. {
  5560. if(!period) period = 1;
  5561. return ((8363 * 1712L) << FREQ_FRACBITS) / period;
  5562. }
  5563. } else if(UseFinetuneAndTranspose())
  5564. {
  5565. return ((3546895L * 4) << FREQ_FRACBITS) / period;
  5566. } else if(GetType() == MOD_TYPE_669)
  5567. {
  5568. // We only really use c5speed for the finetune pattern command. All samples in 669 files have the same middle-C speed (imported as 8363 Hz).
  5569. return (period + c5speed - 8363) << FREQ_FRACBITS;
  5570. } else if(GetType() & (MOD_TYPE_MDL | MOD_TYPE_DTM))
  5571. {
  5572. LimitMax(period, Util::MaxValueOfType(period) >> 8);
  5573. if (!c5speed) c5speed = 8363;
  5574. return Util::muldiv_unsigned(c5speed, (1712L << 7) << FREQ_FRACBITS, (period << 8) + nPeriodFrac);
  5575. } else
  5576. {
  5577. LimitMax(period, Util::MaxValueOfType(period) >> 8);
  5578. if(PeriodsAreFrequencies())
  5579. {
  5580. // Input is already a frequency in Hertz, not a period.
  5581. static_assert(FREQ_FRACBITS <= 8, "Check this shift operator");
  5582. return uint32(((uint64(period) << 8) + nPeriodFrac) >> (8 - FREQ_FRACBITS));
  5583. } else if(m_SongFlags[SONG_LINEARSLIDES])
  5584. {
  5585. if(!c5speed)
  5586. c5speed = 8363;
  5587. return Util::muldiv_unsigned(c5speed, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac);
  5588. } else
  5589. {
  5590. return Util::muldiv_unsigned(8363, (1712L << 8) << FREQ_FRACBITS, (period << 8) + nPeriodFrac);
  5591. }
  5592. }
  5593. }
  5594. PLUGINDEX CSoundFile::GetBestPlugin(const PlayState &playState, CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const
  5595. {
  5596. if (nChn >= MAX_CHANNELS) //Check valid channel number
  5597. {
  5598. return 0;
  5599. }
  5600. //Define search source order
  5601. PLUGINDEX plugin = 0;
  5602. switch (priority)
  5603. {
  5604. case ChannelOnly:
  5605. plugin = GetChannelPlugin(playState, nChn, respectMutes);
  5606. break;
  5607. case InstrumentOnly:
  5608. plugin = GetActiveInstrumentPlugin(playState.Chn[nChn], respectMutes);
  5609. break;
  5610. case PrioritiseInstrument:
  5611. plugin = GetActiveInstrumentPlugin(playState.Chn[nChn], respectMutes);
  5612. if(!plugin || plugin > MAX_MIXPLUGINS)
  5613. {
  5614. plugin = GetChannelPlugin(playState, nChn, respectMutes);
  5615. }
  5616. break;
  5617. case PrioritiseChannel:
  5618. plugin = GetChannelPlugin(playState, nChn, respectMutes);
  5619. if(!plugin || plugin > MAX_MIXPLUGINS)
  5620. {
  5621. plugin = GetActiveInstrumentPlugin(playState.Chn[nChn], respectMutes);
  5622. }
  5623. break;
  5624. }
  5625. return plugin; // 0 Means no plugin found.
  5626. }
  5627. PLUGINDEX CSoundFile::GetChannelPlugin(const PlayState &playState, CHANNELINDEX nChn, PluginMutePriority respectMutes) const
  5628. {
  5629. const ModChannel &channel = playState.Chn[nChn];
  5630. PLUGINDEX plugin;
  5631. if((respectMutes == RespectMutes && channel.dwFlags[CHN_MUTE | CHN_SYNCMUTE]) || channel.dwFlags[CHN_NOFX])
  5632. {
  5633. plugin = 0;
  5634. } else
  5635. {
  5636. // If it looks like this is an NNA channel, we need to find the master channel.
  5637. // This ensures we pick up the right ChnSettings.
  5638. if(channel.nMasterChn > 0)
  5639. {
  5640. nChn = channel.nMasterChn - 1;
  5641. }
  5642. if(nChn < MAX_BASECHANNELS)
  5643. {
  5644. plugin = ChnSettings[nChn].nMixPlugin;
  5645. } else
  5646. {
  5647. plugin = 0;
  5648. }
  5649. }
  5650. return plugin;
  5651. }
  5652. PLUGINDEX CSoundFile::GetActiveInstrumentPlugin(const ModChannel &chn, PluginMutePriority respectMutes)
  5653. {
  5654. // Unlike channel settings, pModInstrument is copied from the original chan to the NNA chan,
  5655. // so we don't need to worry about finding the master chan.
  5656. PLUGINDEX plug = 0;
  5657. if(chn.pModInstrument != nullptr)
  5658. {
  5659. // TODO this looks fishy. Shouldn't it check the mute status of the instrument itself?!
  5660. if(respectMutes == RespectMutes && chn.pModSample && chn.pModSample->uFlags[CHN_MUTE])
  5661. {
  5662. plug = 0;
  5663. } else
  5664. {
  5665. plug = chn.pModInstrument->nMixPlug;
  5666. }
  5667. }
  5668. return plug;
  5669. }
  5670. // Retrieve the plugin that is associated with the channel's current instrument.
  5671. // No plugin is returned if the channel is muted or if the instrument doesn't have a MIDI channel set up,
  5672. // As this is meant to be used with instrument plugins.
  5673. IMixPlugin *CSoundFile::GetChannelInstrumentPlugin(const ModChannel &chn) const
  5674. {
  5675. #ifndef NO_PLUGINS
  5676. if(chn.dwFlags[CHN_MUTE | CHN_SYNCMUTE])
  5677. {
  5678. // Don't process portamento on muted channels. Note that this might have a side-effect
  5679. // on other channels which trigger notes on the same MIDI channel of the same plugin,
  5680. // as those won't be pitch-bent anymore.
  5681. return nullptr;
  5682. }
  5683. if(chn.HasMIDIOutput())
  5684. {
  5685. const ModInstrument *pIns = chn.pModInstrument;
  5686. // Instrument sends to a MIDI channel
  5687. if(pIns->nMixPlug != 0 && pIns->nMixPlug <= MAX_MIXPLUGINS)
  5688. {
  5689. return m_MixPlugins[pIns->nMixPlug - 1].pMixPlugin;
  5690. }
  5691. }
  5692. #else
  5693. MPT_UNREFERENCED_PARAMETER(chn);
  5694. #endif // NO_PLUGINS
  5695. return nullptr;
  5696. }
  5697. #ifdef MODPLUG_TRACKER
  5698. void CSoundFile::HandlePatternTransitionEvents()
  5699. {
  5700. // MPT sequence override
  5701. if(m_PlayState.m_nSeqOverride != ORDERINDEX_INVALID && m_PlayState.m_nSeqOverride < Order().size())
  5702. {
  5703. if(m_SongFlags[SONG_PATTERNLOOP])
  5704. {
  5705. m_PlayState.m_nPattern = Order()[m_PlayState.m_nSeqOverride];
  5706. }
  5707. m_PlayState.m_nCurrentOrder = m_PlayState.m_nSeqOverride;
  5708. m_PlayState.m_nSeqOverride = ORDERINDEX_INVALID;
  5709. }
  5710. // Channel mutes
  5711. for (CHANNELINDEX chan = 0; chan < GetNumChannels(); chan++)
  5712. {
  5713. if (m_bChannelMuteTogglePending[chan])
  5714. {
  5715. if(GetpModDoc())
  5716. {
  5717. GetpModDoc()->MuteChannel(chan, !GetpModDoc()->IsChannelMuted(chan));
  5718. }
  5719. m_bChannelMuteTogglePending[chan] = false;
  5720. }
  5721. }
  5722. }
  5723. #endif // MODPLUG_TRACKER
  5724. // Update time signatures (global or pattern-specific). Don't forget to call this when changing the RPB/RPM settings anywhere!
  5725. void CSoundFile::UpdateTimeSignature()
  5726. {
  5727. if(!Patterns.IsValidIndex(m_PlayState.m_nPattern) || !Patterns[m_PlayState.m_nPattern].GetOverrideSignature())
  5728. {
  5729. m_PlayState.m_nCurrentRowsPerBeat = m_nDefaultRowsPerBeat;
  5730. m_PlayState.m_nCurrentRowsPerMeasure = m_nDefaultRowsPerMeasure;
  5731. } else
  5732. {
  5733. m_PlayState.m_nCurrentRowsPerBeat = Patterns[m_PlayState.m_nPattern].GetRowsPerBeat();
  5734. m_PlayState.m_nCurrentRowsPerMeasure = Patterns[m_PlayState.m_nPattern].GetRowsPerMeasure();
  5735. }
  5736. }
  5737. void CSoundFile::PortamentoMPT(ModChannel &chn, int param)
  5738. {
  5739. //Behavior: Modifies portamento by param-steps on every tick.
  5740. //Note that step meaning depends on tuning.
  5741. chn.m_PortamentoFineSteps += param;
  5742. chn.m_CalculateFreq = true;
  5743. }
  5744. void CSoundFile::PortamentoFineMPT(ModChannel &chn, int param)
  5745. {
  5746. //Behavior: Divides portamento change between ticks/row. For example
  5747. //if Ticks/row == 6, and param == +-6, portamento goes up/down by one tuning-dependent
  5748. //fine step every tick.
  5749. if(m_PlayState.m_nTickCount == 0)
  5750. chn.nOldFinePortaUpDown = 0;
  5751. const int tickParam = static_cast<int>((m_PlayState.m_nTickCount + 1.0) * param / m_PlayState.m_nMusicSpeed);
  5752. chn.m_PortamentoFineSteps += (param >= 0) ? tickParam - chn.nOldFinePortaUpDown : tickParam + chn.nOldFinePortaUpDown;
  5753. if(m_PlayState.m_nTickCount + 1 == m_PlayState.m_nMusicSpeed)
  5754. chn.nOldFinePortaUpDown = static_cast<int8>(std::abs(param));
  5755. else
  5756. chn.nOldFinePortaUpDown = static_cast<int8>(std::abs(tickParam));
  5757. chn.m_CalculateFreq = true;
  5758. }
  5759. void CSoundFile::PortamentoExtraFineMPT(ModChannel &chn, int param)
  5760. {
  5761. // This kinda behaves like regular fine portamento.
  5762. // It changes the pitch by n finetune steps on the first tick.
  5763. if(chn.isFirstTick)
  5764. {
  5765. chn.m_PortamentoFineSteps += param;
  5766. chn.m_CalculateFreq = true;
  5767. }
  5768. }
  5769. OPENMPT_NAMESPACE_END