|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804 |
- /* CLM (Music V) implementation */
-
- #include "mus-config.h"
-
- #if USE_SND
- #include "snd.h"
- #endif
-
- #include <stddef.h>
- #include <math.h>
- #include <stdio.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
-
- #ifndef _MSC_VER
- #include <unistd.h>
- #else
- #include <io.h>
- #pragma warning(disable: 4244)
- #endif
-
- #include "_sndlib.h"
- #include "clm.h"
- #include "clm-strings.h"
-
- #if HAVE_GSL
- #include <gsl/gsl_complex.h>
- #include <gsl/gsl_complex_math.h>
- #endif
-
- #if HAVE_FFTW3
- #include <fftw3.h>
- #endif
-
- #if HAVE_COMPLEX_TRIG
- #include <complex.h>
- #endif
-
- #if (!DISABLE_SINCOS) && defined(__GNUC__) && defined(__linux__)
- #define HAVE_SINCOS 1
- void sincos(double x, double *sin, double *cos);
- #else
- #define HAVE_SINCOS 0
- #endif
-
- #ifndef TWO_PI
- #define TWO_PI (2.0 * M_PI)
- #endif
-
- struct mus_any_class {
- int type;
- char *name;
- void (*release)(mus_any *ptr);
- char *(*describe)(mus_any *ptr); /* caller should free the string */
- bool (*equalp)(mus_any *gen1, mus_any *gen2);
- mus_float_t *(*data)(mus_any *ptr);
- mus_float_t *(*set_data)(mus_any *ptr, mus_float_t *new_data);
- mus_long_t (*length)(mus_any *ptr);
- mus_long_t (*set_length)(mus_any *ptr, mus_long_t new_length);
- mus_float_t (*frequency)(mus_any *ptr);
- mus_float_t (*set_frequency)(mus_any *ptr, mus_float_t new_freq);
- mus_float_t (*phase)(mus_any *ptr);
- mus_float_t (*set_phase)(mus_any *ptr, mus_float_t new_phase);
- mus_float_t (*scaler)(mus_any *ptr);
- mus_float_t (*set_scaler)(mus_any *ptr, mus_float_t val);
- mus_float_t (*increment)(mus_any *ptr);
- mus_float_t (*set_increment)(mus_any *ptr, mus_float_t val);
- mus_float_t (*run)(mus_any *gen, mus_float_t arg1, mus_float_t arg2);
- mus_clm_extended_t extended_type;
- void *(*closure)(mus_any *gen);
- int (*channels)(mus_any *ptr);
- mus_float_t (*offset)(mus_any *ptr);
- mus_float_t (*set_offset)(mus_any *ptr, mus_float_t val);
- mus_float_t (*width)(mus_any *ptr);
- mus_float_t (*set_width)(mus_any *ptr, mus_float_t val);
- mus_float_t (*xcoeff)(mus_any *ptr, int index);
- mus_float_t (*set_xcoeff)(mus_any *ptr, int index, mus_float_t val);
- mus_long_t (*hop)(mus_any *ptr);
- mus_long_t (*set_hop)(mus_any *ptr, mus_long_t new_length);
- mus_long_t (*ramp)(mus_any *ptr);
- mus_long_t (*set_ramp)(mus_any *ptr, mus_long_t new_length);
- mus_float_t (*read_sample)(mus_any *ptr, mus_long_t samp, int chan);
- mus_float_t (*write_sample)(mus_any *ptr, mus_long_t samp, int chan, mus_float_t data);
- char *(*file_name)(mus_any *ptr);
- int (*end)(mus_any *ptr);
- mus_long_t (*location)(mus_any *ptr);
- mus_long_t (*set_location)(mus_any *ptr, mus_long_t loc);
- int (*channel)(mus_any *ptr);
- mus_float_t (*ycoeff)(mus_any *ptr, int index);
- mus_float_t (*set_ycoeff)(mus_any *ptr, int index, mus_float_t val);
- mus_float_t *(*xcoeffs)(mus_any *ptr);
- mus_float_t *(*ycoeffs)(mus_any *ptr);
- void (*reset)(mus_any *ptr);
- void *(*set_closure)(mus_any *gen, void *e);
- mus_any *(*copy)(mus_any *ptr);
- };
-
-
- enum {MUS_OSCIL, MUS_NCOS, MUS_DELAY, MUS_COMB, MUS_NOTCH, MUS_ALL_PASS,
- MUS_TABLE_LOOKUP, MUS_SQUARE_WAVE, MUS_SAWTOOTH_WAVE, MUS_TRIANGLE_WAVE, MUS_PULSE_TRAIN,
- MUS_RAND, MUS_RAND_INTERP, MUS_ASYMMETRIC_FM, MUS_ONE_ZERO, MUS_ONE_POLE, MUS_TWO_ZERO, MUS_TWO_POLE, MUS_FORMANT,
- MUS_SRC, MUS_GRANULATE, MUS_WAVE_TRAIN,
- MUS_FILTER, MUS_FIR_FILTER, MUS_IIR_FILTER, MUS_CONVOLVE, MUS_ENV, MUS_LOCSIG,
- MUS_READIN, MUS_FILE_TO_SAMPLE, MUS_FILE_TO_FRAMPLE,
- MUS_SAMPLE_TO_FILE, MUS_FRAMPLE_TO_FILE, MUS_PHASE_VOCODER,
- MUS_MOVING_AVERAGE, MUS_MOVING_MAX, MUS_MOVING_NORM, MUS_NSIN, MUS_SSB_AM, MUS_POLYSHAPE, MUS_FILTERED_COMB,
- MUS_MOVE_SOUND, MUS_NRXYSIN, MUS_NRXYCOS, MUS_POLYWAVE, MUS_FIRMANT, MUS_FORMANT_BANK,
- MUS_ONE_POLE_ALL_PASS, MUS_COMB_BANK, MUS_ALL_PASS_BANK, MUS_FILTERED_COMB_BANK, MUS_OSCIL_BANK,
- MUS_PULSED_ENV, MUS_RXYKSIN, MUS_RXYKCOS,
- MUS_INITIAL_GEN_TAG};
-
- mus_any_class *mus_generator_class(mus_any *ptr) {return(ptr->core);}
-
- void mus_generator_set_extended_type(mus_any_class *p, mus_clm_extended_t extended_type) {p->extended_type = extended_type;}
- void mus_generator_set_length(mus_any_class *p, mus_long_t (*length)(mus_any *ptr)) {p->length = length;}
- void mus_generator_set_scaler(mus_any_class *p, mus_float_t (*scaler)(mus_any *ptr)) {p->scaler = scaler;}
- void mus_generator_set_channels(mus_any_class *p, int (*channels)(mus_any *ptr)) {p->channels = channels;}
- void mus_generator_set_location(mus_any_class *p, mus_long_t (*location)(mus_any *ptr)) {p->location = location;}
- void mus_generator_set_set_location(mus_any_class *p, mus_long_t (*set_location)(mus_any *ptr, mus_long_t loc)) {p->set_location = set_location;}
- void mus_generator_set_read_sample(mus_any_class *p, mus_float_t (*read_sample)(mus_any *ptr, mus_long_t samp, int chan)) {p->read_sample = read_sample;}
- void mus_generator_set_channel(mus_any_class *p, int (*channel)(mus_any *ptr)) {p->channel = channel;}
- void mus_generator_set_file_name(mus_any_class *p, char *(*file_name)(mus_any *ptr)) {p->file_name = file_name;}
-
- mus_any_class *mus_make_generator(int type, char *name,
- void (*release)(mus_any *ptr),
- char *(*describe)(mus_any *ptr),
- bool (*equalp)(mus_any *gen1, mus_any *gen2))
- {
- mus_any_class *p;
- p = (mus_any_class *)calloc(1, sizeof(mus_any_class));
- p->type = type;
- p->name = name;
- p->release = release;
- p->describe = describe;
- p->equalp = equalp;
- return(p);
- }
-
-
- static int mus_generator_type = MUS_INITIAL_GEN_TAG;
-
- int mus_make_generator_type(void) {return(mus_generator_type++);}
-
-
- static const char *interp_name[] = {"step", "linear", "sinusoidal", "all-pass", "lagrange", "bezier", "hermite"};
-
- static const char *interp_type_to_string(int type)
- {
- if (mus_is_interp_type(type))
- return(interp_name[type]);
- return("unknown");
- }
-
-
- static mus_float_t sampling_rate = MUS_DEFAULT_SAMPLING_RATE;
-
- static mus_float_t w_rate = (TWO_PI / MUS_DEFAULT_SAMPLING_RATE);
-
-
- static mus_float_t float_equal_fudge_factor = 0.0000001;
-
- mus_float_t mus_float_equal_fudge_factor(void) {return(float_equal_fudge_factor);}
-
- mus_float_t mus_set_float_equal_fudge_factor(mus_float_t val)
- {
- mus_float_t prev;
- prev = float_equal_fudge_factor;
- float_equal_fudge_factor = val;
- return(prev);
- }
-
-
- static int array_print_length = MUS_DEFAULT_ARRAY_PRINT_LENGTH;
-
- int mus_array_print_length(void) {return(array_print_length);}
-
- int mus_set_array_print_length(int val)
- {
- int prev;
- prev = array_print_length;
- if (val >= 0) array_print_length = val;
- return(prev);
- }
-
-
- static mus_long_t clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
-
- mus_long_t mus_file_buffer_size(void) {return(clm_file_buffer_size);}
-
- mus_long_t mus_set_file_buffer_size(mus_long_t size)
- {
- /* this is set in with-sound, among other places */
- mus_long_t prev;
- prev = clm_file_buffer_size;
- clm_file_buffer_size = size;
- return(prev);
- }
-
-
- mus_float_t mus_radians_to_hz(mus_float_t rads) {return(rads / w_rate);}
- mus_float_t mus_hz_to_radians(mus_float_t hz) {return(hz * w_rate);}
-
-
- mus_float_t mus_degrees_to_radians(mus_float_t degree) {return(degree * TWO_PI / 360.0);}
- mus_float_t mus_radians_to_degrees(mus_float_t rads) {return(rads * 360.0 / TWO_PI);}
-
-
- mus_float_t mus_db_to_linear(mus_float_t x) {return(pow(10.0, x / 20.0));}
- mus_float_t mus_linear_to_db(mus_float_t x) {if (x > 0.0) return(20.0 * log10(x)); return(-100.0);}
-
-
- mus_float_t mus_odd_multiple(mus_float_t x, mus_float_t y) {mus_long_t f; f = (mus_long_t)floor(x); return(y * ((f & 1) ? f : (f + 1)));}
- mus_float_t mus_even_multiple(mus_float_t x, mus_float_t y) {mus_long_t f; f = (mus_long_t)floor(x); return(y * ((f & 1) ? (f + 1) : f));}
- mus_float_t mus_odd_weight(mus_float_t x) {mus_long_t f; f = (mus_long_t)floor(x); return(1.0 - fabs(x - ((f & 1) ? f : (f + 1))));}
- mus_float_t mus_even_weight(mus_float_t x) {mus_long_t f; f = (mus_long_t)floor(x); return(1.0 - fabs(x - ((f & 1) ? (f + 1) : f)));}
-
- mus_float_t mus_srate(void) {return(sampling_rate);}
-
- mus_float_t mus_set_srate(mus_float_t val)
- {
- mus_float_t prev;
- prev = sampling_rate;
- if (val > 0.0)
- {
- sampling_rate = val;
- w_rate = (TWO_PI / sampling_rate);
- }
- return(prev);
- }
-
-
- mus_long_t mus_seconds_to_samples(mus_float_t secs) {return((mus_long_t)(secs * sampling_rate));}
- mus_float_t mus_samples_to_seconds(mus_long_t samps) {return((mus_float_t)((mus_float_t)samps / (mus_float_t)sampling_rate));}
-
-
- #define DESCRIBE_BUFFER_SIZE 2048
- #define STR_SIZE 128
-
-
- static char *float_array_to_string(mus_float_t *arr, int len, int loc)
- {
- /* %g is needed here rather than %f -- otherwise the number strings can be any size */
- #define MAX_NUM_SIZE 64
- char *base, *str;
- int i, lim, size = 512;
- if (arr == NULL)
- {
- str = (char *)malloc(4 * sizeof(char));
- snprintf(str, 4, "nil");
- return(str);
- }
- lim = (array_print_length + 4) * MAX_NUM_SIZE; /* 4 for possible bounds below */
- if (lim > size) size = lim;
- if (loc < 0) loc = 0;
-
- base = (char *)calloc(size, sizeof(char));
- str = (char *)malloc(STR_SIZE * sizeof(char));
-
- if (len > 0)
- {
- int k;
- snprintf(base, size, "[");
- lim = len;
- if (lim > array_print_length) lim = array_print_length;
- k = loc;
- if (k >= len) k = 0;
- for (i = 0; i < lim - 1; i++)
- {
- snprintf(str, STR_SIZE, "%.3g ", arr[k]);
- strcat(base, str);
- if ((int)(strlen(base) + MAX_NUM_SIZE) > size)
- {
- base = (char *)realloc(base, size * 2 * sizeof(char));
- base[size] = 0;
- size *= 2;
- }
- k++;
- if (k >= len) k = 0;
- }
- snprintf(str, STR_SIZE, "%.3g%s", arr[k], (len > lim) ? "..." : "]");
- strcat(base, str);
- }
- else snprintf(base, size, "[]");
- if (len > lim)
- {
- /* print ranges */
- int min_loc = 0, max_loc = 0;
- mus_float_t min_val, max_val;
- min_val = arr[0];
- max_val = arr[0];
- for (i = 1; i < len; i++)
- {
- if (arr[i] < min_val) {min_val = arr[i]; min_loc = i;}
- if (arr[i] > max_val) {max_val = arr[i]; max_loc = i;}
- }
- snprintf(str, STR_SIZE, "(%d: %.3g, %d: %.3g)]", min_loc, min_val, max_loc, max_val);
- strcat(base, str);
- }
- free(str);
- return(base);
- }
-
-
- static char *clm_array_to_string(mus_any **gens, int num_gens, const char *name, const char *indent)
- {
- char *descr = NULL;
- if ((gens) && (num_gens > 0))
- {
- int i, len = 0;
- char **descrs;
- descrs = (char **)calloc(num_gens, sizeof(char *));
- for (i = 0; i < num_gens; i++)
- {
- if (gens[i])
- {
- char *str = NULL;
- descrs[i] = mus_format("\n%s[%d]: %s", indent, i, str = mus_describe(gens[i]));
- if (str) free(str);
- }
- else descrs[i] = mus_format("\n%s[%d]: nil", indent, i);
- len += strlen(descrs[i]);
- }
- len += (64 + strlen(name));
- descr = (char *)malloc(len * sizeof(char));
- snprintf(descr, len, "%s[%d]:", name, num_gens);
- for (i = 0; i < num_gens; i++)
- {
- strcat(descr, descrs[i]);
- free(descrs[i]);
- }
- free(descrs);
- }
- else
- {
- descr = (char *)malloc(128 * sizeof(char));
- snprintf(descr, 128, "%s: nil", name);
- }
- return(descr);
- }
-
-
- static char *int_array_to_string(int *arr, int num_ints, const char *name)
- {
- #define MAX_INT_SIZE 32
- char *descr = NULL;
- if ((arr) && (num_ints > 0))
- {
- int i, len;
- char *intstr;
- len = num_ints * MAX_INT_SIZE + 64;
- descr = (char *)calloc(len, sizeof(char));
- intstr = (char *)malloc(MAX_INT_SIZE * sizeof(char));
- snprintf(descr, len, "%s[%d]: (", name, num_ints);
- for (i = 0; i < num_ints - 1; i++)
- {
- snprintf(intstr, MAX_INT_SIZE, "%d ", arr[i]);
- strcat(descr, intstr);
- }
- snprintf(intstr, MAX_INT_SIZE, "%d)", arr[num_ints - 1]);
- strcat(descr, intstr);
- free(intstr);
- }
- else
- {
- descr = (char *)malloc(128 * sizeof(char));
- snprintf(descr, 128, "%s: nil", name);
- }
- return(descr);
- }
-
-
- /* ---------------- generic functions ---------------- */
-
- #define check_gen(Ptr, Name) ((Ptr) ? true : (!mus_error(MUS_NO_GEN, "null generator passed to %s", Name)))
-
- int mus_type(mus_any *ptr)
- {
- return(((check_gen(ptr, S_mus_type)) && (ptr->core)) ? ptr->core->type : -1);
- }
-
-
- const char *mus_name(mus_any *ptr)
- {
- return((ptr == NULL) ? "null" : ptr->core->name);
- }
-
-
- void mus_free(mus_any *gen)
- {
- if (gen)
- (*(gen->core->release))(gen);
- }
-
-
- char *mus_describe(mus_any *gen)
- {
- if (gen == NULL)
- return(mus_strdup((char *)"null"));
- if ((gen->core) && (gen->core->describe))
- return((*(gen->core->describe))(gen));
- else mus_error(MUS_NO_DESCRIBE, "can't describe %s", mus_name(gen));
- return(NULL);
- }
-
-
- bool mus_equalp(mus_any *p1, mus_any *p2)
- {
- if ((p1) && (p2))
- {
- if ((p1->core)->equalp)
- return((*((p1->core)->equalp))(p1, p2));
- else return(p1 == p2);
- }
- return(true); /* (eq nil nil) */
- }
-
-
- void mus_reset(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_reset)) &&
- (gen->core->reset))
- (*(gen->core->reset))(gen);
- else mus_error(MUS_NO_RESET, "can't reset %s", mus_name(gen));
- }
-
-
- mus_any *mus_copy(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_copy)) &&
- (gen->core->copy))
- return((*(gen->core->copy))(gen));
- else mus_error(MUS_NO_COPY, "can't copy %s", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t mus_frequency(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_frequency)) &&
- (gen->core->frequency))
- return((*(gen->core->frequency))(gen));
- return((mus_float_t)mus_error(MUS_NO_FREQUENCY, "can't get %s's frequency", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_frequency(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_frequency)) &&
- (gen->core->set_frequency))
- return((*(gen->core->set_frequency))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FREQUENCY, "can't set %s's frequency", mus_name(gen)));
- }
-
-
- mus_float_t mus_phase(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_phase)) &&
- (gen->core->phase))
- return((*(gen->core->phase))(gen));
- return((mus_float_t)mus_error(MUS_NO_PHASE, "can't get %s's phase", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_phase(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_phase)) &&
- (gen->core->set_phase))
- return((*(gen->core->set_phase))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_PHASE, "can't set %s's phase", mus_name(gen)));
- }
-
-
-
- mus_float_t mus_scaler(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_scaler)) &&
- (gen->core->scaler))
- return((*(gen->core->scaler))(gen));
- return((mus_float_t)mus_error(MUS_NO_SCALER, "can't get %s's scaler", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_scaler(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_scaler)) &&
- (gen->core->set_scaler))
- return((*(gen->core->set_scaler))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_SCALER, "can't set %s's scaler", mus_name(gen)));
- }
-
-
- mus_float_t mus_feedforward(mus_any *gen) /* shares "scaler" */
- {
- if ((check_gen(gen, S_mus_feedforward)) &&
- (gen->core->scaler))
- return((*(gen->core->scaler))(gen));
- return((mus_float_t)mus_error(MUS_NO_FEEDFORWARD, "can't get %s's feedforward", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_feedforward(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_feedforward)) &&
- (gen->core->set_scaler))
- return((*(gen->core->set_scaler))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FEEDFORWARD, "can't set %s's feedforward", mus_name(gen)));
- }
-
-
- mus_float_t mus_offset(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_offset)) &&
- (gen->core->offset))
- return((*(gen->core->offset))(gen));
- return((mus_float_t)mus_error(MUS_NO_OFFSET, "can't get %s's offset", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_offset(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_offset)) &&
- (gen->core->set_offset))
- return((*(gen->core->set_offset))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_OFFSET, "can't set %s's offset", mus_name(gen)));
- }
-
-
- mus_float_t mus_width(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_width)) &&
- (gen->core->width))
- return((*(gen->core->width))(gen));
- return((mus_float_t)mus_error(MUS_NO_WIDTH, "can't get %s's width", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_width(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_width)) &&
- (gen->core->set_width))
- return((*(gen->core->set_width))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_WIDTH, "can't set %s's width", mus_name(gen)));
- }
-
-
- mus_float_t mus_increment(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_increment)) &&
- (gen->core->increment))
- return((*(gen->core->increment))(gen));
- return((mus_float_t)mus_error(MUS_NO_INCREMENT, "can't get %s's increment", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_increment(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_increment)) &&
- (gen->core->set_increment))
- return((*(gen->core->set_increment))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_INCREMENT, "can't set %s's increment", mus_name(gen)));
- }
-
-
- mus_float_t mus_feedback(mus_any *gen) /* shares "increment" */
- {
- if ((check_gen(gen, S_mus_feedback)) &&
- (gen->core->increment))
- return((*(gen->core->increment))(gen));
- return((mus_float_t)mus_error(MUS_NO_FEEDBACK, "can't get %s's feedback", mus_name(gen)));
- }
-
-
- mus_float_t mus_set_feedback(mus_any *gen, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_feedback)) &&
- (gen->core->set_increment))
- return((*(gen->core->set_increment))(gen, val));
- return((mus_float_t)mus_error(MUS_NO_FEEDBACK, "can't set %s's feedback", mus_name(gen)));
- }
-
-
- void *mus_environ(mus_any *gen)
- {
- if (check_gen(gen, "mus-environ"))
- return((*(gen->core->closure))(gen));
- return(NULL);
- }
-
-
- void *mus_set_environ(mus_any *gen, void *e)
- {
- if (check_gen(gen, S_set "mus-environ"))
- return((*(gen->core->set_closure))(gen, e));
- return(NULL);
- }
-
-
- mus_float_t mus_run(mus_any *gen, mus_float_t arg1, mus_float_t arg2)
- {
- if ((check_gen(gen, "mus-run")) &&
- (gen->core->run))
- return((*(gen->core->run))(gen, arg1, arg2));
- return((mus_float_t)mus_error(MUS_NO_RUN, "can't run %s", mus_name(gen)));
- }
-
-
- mus_long_t mus_length(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_length)) &&
- (gen->core->length))
- return((*(gen->core->length))(gen));
- return(mus_error(MUS_NO_LENGTH, "can't get %s's length", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_length(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_length)) &&
- (gen->core->set_length))
- return((*(gen->core->set_length))(gen, len));
- return(mus_error(MUS_NO_LENGTH, "can't set %s's length", mus_name(gen)));
- }
-
-
- mus_long_t mus_order(mus_any *gen) /* shares "length", no set */
- {
- if ((check_gen(gen, S_mus_order)) &&
- (gen->core->length))
- return((*(gen->core->length))(gen));
- return(mus_error(MUS_NO_ORDER, "can't get %s's order", mus_name(gen)));
- }
-
-
- int mus_channels(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_channels)) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_CHANNELS, "can't get %s's channels", mus_name(gen)));
- }
-
-
- int mus_interp_type(mus_any *gen) /* shares "channels", no set */
- {
- if ((check_gen(gen, S_mus_interp_type)) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_INTERP_TYPE, "can't get %s's interp type", mus_name(gen)));
- }
-
-
- int mus_position(mus_any *gen) /* shares "channels", no set, only used in C (snd-env.c) */
- {
- if ((check_gen(gen, "mus-position")) &&
- (gen->core->channels))
- return((*(gen->core->channels))(gen));
- return(mus_error(MUS_NO_POSITION, "can't get %s's position", mus_name(gen)));
- }
-
-
- int mus_channel(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_channel)) &&
- (gen->core->channel))
- return(((*gen->core->channel))(gen));
- return(mus_error(MUS_NO_CHANNEL, "can't get %s's channel", mus_name(gen)));
- }
-
-
- mus_long_t mus_hop(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_hop)) &&
- (gen->core->hop))
- return((*(gen->core->hop))(gen));
- return(mus_error(MUS_NO_HOP, "can't get %s's hop value", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_hop(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_hop)) &&
- (gen->core->set_hop))
- return((*(gen->core->set_hop))(gen, len));
- return(mus_error(MUS_NO_HOP, "can't set %s's hop value", mus_name(gen)));
- }
-
-
- mus_long_t mus_ramp(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_ramp)) &&
- (gen->core->ramp))
- return((*(gen->core->ramp))(gen));
- return(mus_error(MUS_NO_RAMP, "can't get %s's ramp value", mus_name(gen)));
- }
-
-
- mus_long_t mus_set_ramp(mus_any *gen, mus_long_t len)
- {
- if ((check_gen(gen, S_set S_mus_ramp)) &&
- (gen->core->set_ramp))
- return((*(gen->core->set_ramp))(gen, len));
- return(mus_error(MUS_NO_RAMP, "can't set %s's ramp value", mus_name(gen)));
- }
-
-
- mus_float_t *mus_data(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_data)) &&
- (gen->core->data))
- return((*(gen->core->data))(gen));
- mus_error(MUS_NO_DATA, "can't get %s's data", mus_name(gen));
- return(NULL);
- }
-
-
- /* every case that implements the data or set data functions needs to include
- * a var-allocated flag, since all such memory has to be handled via vcts
- */
-
- mus_float_t *mus_set_data(mus_any *gen, mus_float_t *new_data)
- {
- if (check_gen(gen, S_set S_mus_data))
- {
- if (gen->core->set_data)
- {
- (*(gen->core->set_data))(gen, new_data);
- return(new_data);
- }
- else mus_error(MUS_NO_DATA, "can't set %s's data", mus_name(gen));
- }
- return(new_data);
- }
-
-
- mus_float_t *mus_xcoeffs(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_xcoeffs)) &&
- (gen->core->xcoeffs))
- return((*(gen->core->xcoeffs))(gen));
- mus_error(MUS_NO_XCOEFFS, "can't get %s's xcoeffs", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t *mus_ycoeffs(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_ycoeffs)) &&
- (gen->core->ycoeffs))
- return((*(gen->core->ycoeffs))(gen));
- mus_error(MUS_NO_YCOEFFS, "can't get %s's ycoeffs", mus_name(gen));
- return(NULL);
- }
-
-
- mus_float_t mus_xcoeff(mus_any *gen, int index)
- {
- if ((check_gen(gen, S_mus_xcoeff)) &&
- (gen->core->xcoeff))
- return((*(gen->core->xcoeff))(gen, index));
- return(mus_error(MUS_NO_XCOEFF, "can't get %s's xcoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_set_xcoeff(mus_any *gen, int index, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_xcoeff)) &&
- (gen->core->set_xcoeff))
- return((*(gen->core->set_xcoeff))(gen, index, val));
- return(mus_error(MUS_NO_XCOEFF, "can't set %s's xcoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_ycoeff(mus_any *gen, int index)
- {
- if ((check_gen(gen, S_mus_ycoeff)) &&
- (gen->core->ycoeff))
- return((*(gen->core->ycoeff))(gen, index));
- return(mus_error(MUS_NO_YCOEFF, "can't get %s's ycoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_float_t mus_set_ycoeff(mus_any *gen, int index, mus_float_t val)
- {
- if ((check_gen(gen, S_set S_mus_ycoeff)) &&
- (gen->core->set_ycoeff))
- return((*(gen->core->set_ycoeff))(gen, index, val));
- return(mus_error(MUS_NO_YCOEFF, "can't set %s's ycoeff[%d] value", mus_name(gen), index));
- }
-
-
- mus_long_t mus_location(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_location)) &&
- (gen->core->location))
- return(((*gen->core->location))(gen));
- return((mus_long_t)mus_error(MUS_NO_LOCATION, "can't get %s's location", mus_name(gen)));
- }
-
-
- /* ---------------- AM etc ---------------- */
-
- mus_float_t mus_ring_modulate(mus_float_t sig1, mus_float_t sig2)
- {
- return(sig1 * sig2);
- }
-
-
- mus_float_t mus_amplitude_modulate(mus_float_t carrier, mus_float_t sig1, mus_float_t sig2)
- {
- return(sig1 * (carrier + sig2));
- }
-
-
- mus_float_t mus_contrast_enhancement(mus_float_t sig, mus_float_t index)
- {
- return(sin((sig * M_PI_2) + (index * sin(sig * TWO_PI))));
- }
-
-
- bool mus_arrays_are_equal(mus_float_t *arr1, mus_float_t *arr2, mus_float_t fudge, mus_long_t len)
- {
- mus_long_t i;
- if (fudge == 0.0)
- {
- for (i = 0; i < len; i++)
- if (arr1[i] != arr2[i])
- return(false);
- }
- else
- {
- mus_long_t len4;
- len4 = len - 4;
- i = 0;
- while (i <= len4)
- {
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- i++;
- }
- for (; i < len; i++)
- if (fabs(arr1[i] - arr2[i]) > fudge)
- return(false);
- }
- return(true);
- }
-
-
- static bool clm_arrays_are_equal(mus_float_t *arr1, mus_float_t *arr2, mus_long_t len)
- {
- return(mus_arrays_are_equal(arr1, arr2, float_equal_fudge_factor, len));
- }
-
-
- mus_float_t mus_dot_product(mus_float_t *data1, mus_float_t *data2, mus_long_t size)
- {
- mus_long_t i, size4;
- mus_float_t sum = 0.0;
- size4 = size - 4;
- i = 0;
- while (i <= size4)
- {
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- sum += (data1[i] * data2[i]);
- i++;
- }
- for (; i < size; i++)
- sum += (data1[i] * data2[i]);
- return(sum);
- }
-
-
- #if HAVE_COMPLEX_TRIG
- #if HAVE_FORTH
- #include "xen.h"
- #endif
-
- complex double mus_edot_product(complex double freq, complex double *data, mus_long_t size)
- {
- int i;
- complex double sum = 0.0;
- for (i = 0; i < size; i++)
- sum += (cexp(i * freq) * data[i]);
- return(sum);
- }
- #endif
-
-
- mus_float_t mus_polynomial(mus_float_t *coeffs, mus_float_t x, int ncoeffs)
- {
- mus_float_t sum;
- int i;
- if (ncoeffs <= 0) return(0.0);
- if (ncoeffs == 1) return(coeffs[0]); /* just a constant term */
- sum = coeffs[ncoeffs - 1];
- /* unrolled is slower */
- for (i = ncoeffs - 2; i >= 0; i--)
- sum = (sum * x) + coeffs[i];
- return((mus_float_t)sum);
- }
-
- void mus_rectangular_to_polar(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- mus_float_t temp; /* apparently floating underflows (denormals?) in sqrt are bringing us to a halt */
- temp = rl[i] * rl[i] + im[i] * im[i];
- if (temp < .00000001)
- {
- rl[i] = 0.0;
- im[i] = 0.0;
- }
- else
- {
- im[i] = -atan2(im[i], rl[i]); /* "-" here so that clockwise is positive? is this backwards? */
- rl[i] = sqrt(temp);
- }
- }
- }
-
-
- void mus_rectangular_to_magnitudes(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- mus_float_t temp; /* apparently floating underflows in sqrt are bringing us to a halt */
- temp = rl[i] * rl[i] + im[i] * im[i];
- if (temp < .00000001)
- rl[i] = 0.0;
- else rl[i] = sqrt(temp);
- }
- }
-
-
- void mus_polar_to_rectangular(mus_float_t *rl, mus_float_t *im, mus_long_t size)
- {
- mus_long_t i;
- for (i = 0; i < size; i++)
- {
- #if HAVE_SINCOS
- double sx, cx;
- sincos(-im[i], &sx, &cx);
- im[i] = sx * rl[i];
- rl[i] *= cx;
- #else
- mus_float_t temp;
- temp = rl[i] * sin(-im[i]); /* minus to match sense of rectangular->polar above */
- rl[i] *= cos(-im[i]);
- im[i] = temp;
- #endif
- }
- }
-
-
- static mus_float_t *array_normalize(mus_float_t *table, mus_long_t table_size)
- {
- mus_float_t amp = 0.0;
- mus_long_t i;
-
- for (i = 0; i < table_size; i++)
- if (amp < (fabs(table[i])))
- amp = fabs(table[i]);
-
- if ((amp > 0.0) &&
- (amp != 1.0))
- for (i = 0; i < table_size; i++)
- table[i] /= amp;
-
- return(table);
- }
-
-
- /* ---------------- interpolation ---------------- */
-
- mus_float_t mus_array_interp(mus_float_t *wave, mus_float_t phase, mus_long_t size)
- {
- /* changed 26-Sep-00 to be closer to mus.lisp */
- mus_long_t int_part;
- mus_float_t frac_part;
- if ((phase < 0.0) || (phase > size))
- {
- /* 28-Mar-01 changed to fmod; I was hoping to avoid this... */
- phase = fmod((mus_float_t)phase, (mus_float_t)size);
- if (phase < 0.0) phase += size;
- }
-
- int_part = (mus_long_t)phase; /* (mus_long_t)floor(phase); */
- frac_part = phase - int_part;
- if (int_part == size) int_part = 0;
-
- if (frac_part == 0.0)
- return(wave[int_part]);
- else
- {
- mus_long_t inx;
- inx = int_part + 1;
- if (inx >= size) inx = 0;
- return(wave[int_part] + (frac_part * (wave[inx] - wave[int_part])));
- }
- }
-
-
- static mus_float_t mus_array_all_pass_interp(mus_float_t *wave, mus_float_t phase, mus_long_t size, mus_float_t yn1)
- {
- /* this is intended for delay lines where you have a stream of values; in table-lookup it can be a mess */
- mus_long_t int_part, inx;
- mus_float_t frac_part;
- if ((phase < 0.0) || (phase > size))
- {
- phase = fmod((mus_float_t)phase, (mus_float_t)size);
- if (phase < 0.0) phase += size;
- }
- int_part = (mus_long_t)floor(phase);
- frac_part = phase - int_part;
- if (int_part == size) int_part = 0;
- inx = int_part + 1;
- if (inx >= size) inx -= size;
- #if 1
- /* from DAFX */
- if (frac_part == 0.0)
- return(wave[inx] - yn1);
- return(wave[int_part] * frac_part + (1.0 - frac_part) * (wave[inx] - yn1));
- #else
- /* from Perry Cook */
- if (frac_part == 0.0)
- return(wave[int_part] + wave[inx] - yn1);
- else return(wave[int_part] + ((1.0 - frac_part) / (1 + frac_part)) * (wave[inx] - yn1));
- #endif
- }
-
-
- static mus_float_t mus_array_lagrange_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- /* Abramovitz and Stegun 25.2.11 -- everyone badmouths this poor formula */
- /* x assumed to be in the middle, between second and third vals */
- mus_long_t x0, xp1, xm1;
- mus_float_t p, pp;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x0 = (mus_long_t)floor(x);
- p = x - x0;
- if (x0 >= size) x0 -= size;
- if (p == 0.0) return(wave[x0]);
- xp1 = x0 + 1;
- if (xp1 >= size) xp1 -= size;
- xm1 = x0 - 1;
- if (xm1 < 0) xm1 += size;
- pp = p * p;
- return((wave[xm1] * 0.5 * (pp - p)) +
- (wave[x0] * (1.0 - pp)) +
- (wave[xp1] * 0.5 * (p + pp)));
- }
-
-
- static mus_float_t mus_array_hermite_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- /* from James McCartney */
- mus_long_t x0, x1, x2, x3;
- mus_float_t p, c0, c1, c2, c3, y0, y1, y2, y3;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x1 = (mus_long_t)floor(x);
- p = x - x1;
- if (x1 == size) x1 = 0;
- if (p == 0.0) return(wave[x1]);
- x2 = x1 + 1;
- if (x2 == size) x2 = 0;
- x3 = x2 + 1;
- if (x3 == size) x3 = 0;
- x0 = x1 - 1;
- if (x0 < 0) x0 = size - 1;
- y0 = wave[x0];
- y1 = wave[x1];
- y2 = wave[x2];
- y3 = wave[x3];
- c0 = y1;
- c1 = 0.5 * (y2 - y0);
- c3 = 1.5 * (y1 - y2) + 0.5 * (y3 - y0);
- c2 = y0 - y1 + c1 - c3;
- return(((c3 * p + c2) * p + c1) * p + c0);
- }
-
-
- static mus_float_t mus_array_bezier_interp(mus_float_t *wave, mus_float_t x, mus_long_t size)
- {
- mus_long_t x0, x1, x2, x3;
- mus_float_t p, y0, y1, y2, y3, ay, by, cy;
- if ((x < 0.0) || (x > size))
- {
- x = fmod((mus_float_t)x, (mus_float_t)size);
- if (x < 0.0) x += size;
- }
- x1 = (mus_long_t)floor(x);
- p = ((x - x1) + 1.0) / 3.0;
- if (x1 == size) x1 = 0;
- x2 = x1 + 1;
- if (x2 == size) x2 = 0;
- x3 = x2 + 1;
- if (x3 == size) x3 = 0;
- x0 = x1 - 1;
- if (x0 < 0) x0 = size - 1;
- y0 = wave[x0];
- y1 = wave[x1];
- y2 = wave[x2];
- y3 = wave[x3];
- cy = 3 * (y1 - y0);
- by = 3 * (y2 - y1) - cy;
- ay = y3 - y0 - cy - by;
- return(y0 + p * (cy + (p * (by + (p * ay)))));
- }
-
-
- bool mus_is_interp_type(int val)
- {
- /* this is C++'s fault. */
- switch (val)
- {
- case MUS_INTERP_NONE:
- case MUS_INTERP_LINEAR:
- case MUS_INTERP_SINUSOIDAL:
- case MUS_INTERP_LAGRANGE:
- case MUS_INTERP_HERMITE:
- case MUS_INTERP_ALL_PASS:
- case MUS_INTERP_BEZIER:
- return(true);
- break;
- }
- return(false);
- }
-
-
- mus_float_t mus_interpolate(mus_interp_t type, mus_float_t x, mus_float_t *table, mus_long_t table_size, mus_float_t y)
- {
- switch (type)
- {
- case MUS_INTERP_NONE:
- {
- mus_long_t x0;
- x0 = ((mus_long_t)x) % table_size;
- if (x0 < 0) x0 += table_size;
- return(table[x0]);
- }
- break;
-
- case MUS_INTERP_LAGRANGE:
- return(mus_array_lagrange_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_HERMITE:
- return(mus_array_hermite_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_LINEAR:
- return(mus_array_interp(table, x, table_size));
- break;
-
- case MUS_INTERP_ALL_PASS:
- return(mus_array_all_pass_interp(table, x, table_size, y));
- break;
-
- case MUS_INTERP_BEZIER:
- return(mus_array_bezier_interp(table, x, table_size));
- break;
-
- default:
- mus_error(MUS_ARG_OUT_OF_RANGE, "unknown interpolation type: %d", type);
- break;
- }
- return(0.0);
- }
-
-
-
- /* ---------------- oscil ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t phase, freq;
- } osc;
-
-
- mus_float_t mus_oscil(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase + pm;
- gen->phase += (gen->freq + fm);
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_unmodulated(mus_any *ptr)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase;
- gen->phase += gen->freq;
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_fm(mus_any *ptr, mus_float_t fm)
- {
- osc *gen = (osc *)ptr;
- mus_float_t result;
- result = gen->phase;
- gen->phase += (gen->freq + fm);
- return(sin(result));
- }
-
-
- mus_float_t mus_oscil_pm(mus_any *ptr, mus_float_t pm)
- {
- mus_float_t result;
- osc *gen = (osc *)ptr;
- result = gen->phase + pm;
- gen->phase += gen->freq;
- return(sin(result));
- }
-
-
- bool mus_is_oscil(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_OSCIL));
- }
- /* this could be: bool mus_is_oscil(mus_any *ptr) {return((ptr) && (ptr->core == &OSCIL_CLASS));}
- */
-
-
- static void free_oscil(mus_any *ptr) {free(ptr);}
-
- static mus_float_t oscil_freq(mus_any *ptr) {return(mus_radians_to_hz(((osc *)ptr)->freq));}
- static mus_float_t oscil_set_freq(mus_any *ptr, mus_float_t val) {((osc *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t oscil_increment(mus_any *ptr) {return(((osc *)ptr)->freq);}
- static mus_float_t oscil_set_increment(mus_any *ptr, mus_float_t val) {((osc *)ptr)->freq = val; return(val);}
-
- static mus_float_t oscil_phase(mus_any *ptr) {return(fmod(((osc *)ptr)->phase, TWO_PI));}
- static mus_float_t oscil_set_phase(mus_any *ptr, mus_float_t val) {((osc *)ptr)->phase = val; return(val);}
-
- static mus_long_t oscil_cosines(mus_any *ptr) {return(1);}
- static void oscil_reset(mus_any *ptr) {((osc *)ptr)->phase = 0.0;}
-
- static mus_any *oscil_copy(mus_any *ptr)
- {
- osc *g;
- g = (osc *)malloc(sizeof(osc));
- memcpy((void *)g, (void *)ptr, sizeof(osc));
- return((mus_any *)g);
- }
-
- static mus_float_t fallback_scaler(mus_any *ptr) {return(1.0);}
-
-
- static bool oscil_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_oscil((mus_any *)p1)) &&
- (mus_is_oscil((mus_any *)p2)) &&
- ((((osc *)p1)->freq) == (((osc *)p2)->freq)) &&
- ((((osc *)p1)->phase) == (((osc *)p2)->phase))));
- }
-
-
- static char *describe_oscil(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr));
- return(describe_buffer);
- }
-
-
- static mus_any_class OSCIL_CLASS = {
- MUS_OSCIL,
- (char *)S_oscil, /* the "(char *)" business is for g++'s benefit */
- &free_oscil,
- &describe_oscil,
- &oscil_equalp,
- 0, 0,
- &oscil_cosines, 0,
- &oscil_freq,
- &oscil_set_freq,
- &oscil_phase,
- &oscil_set_phase,
- &fallback_scaler, 0,
- &oscil_increment,
- &oscil_set_increment,
- &mus_oscil,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &oscil_reset,
- 0,
- &oscil_copy
- };
-
-
-
- mus_any *mus_make_oscil(mus_float_t freq, mus_float_t phase)
- {
- osc *gen;
- gen = (osc *)malloc(sizeof(osc));
- gen->core = &OSCIL_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- return((mus_any *)gen);
- }
-
- /* decided against feedback-oscil (as in cellon) because it's not clear how to handle the index,
- * and there are many options for the filtering -- since this part of the signal path
- * is not hidden, there's no reason to bring it out explicitly (as in filtered-comb)
- */
-
-
- /* ---------------- oscil-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size, orig_size;
- mus_float_t *amps, *phases, *freqs; /* these can change, so sincos is not always safe */
- bool free_phases;
- mus_float_t (*ob_func)(mus_any *ptr);
- #if HAVE_SINCOS
- double *sn1, *cs1, *sn2, *cs2, *phs;
- bool use_sc;
- #endif
- } ob;
-
-
- static void free_oscil_bank(mus_any *ptr)
- {
- ob *g = (ob *)ptr;
- #if HAVE_SINCOS
- if (g->sn1) {free(g->sn1); g->sn1 = NULL;}
- if (g->sn2) {free(g->sn2); g->sn2 = NULL;}
- if (g->cs1) {free(g->cs1); g->cs1 = NULL;}
- if (g->cs2) {free(g->cs2); g->cs2 = NULL;}
- if (g->phs) {free(g->phs); g->phs = NULL;}
- #endif
- if ((g->phases) && (g->free_phases)) {free(g->phases); g->phases = NULL;}
- free(ptr);
- }
-
- static mus_any *ob_copy(mus_any *ptr)
- {
- ob *g, *p;
- int bytes;
-
- p = (ob *)ptr;
- g = (ob *)malloc(sizeof(ob));
- memcpy((void *)g, (void *)ptr, sizeof(ob));
-
- g->ob_func = p->ob_func;
-
- #if HAVE_SINCOS
- if (g->sn1)
- {
- bytes = g->size * sizeof(double);
- g->sn1 = (double *)malloc(bytes);
- memcpy((void *)(g->sn1), (void *)(p->sn1), bytes);
- g->sn2 = (double *)malloc(bytes);
- memcpy((void *)(g->sn2), (void *)(p->sn2), bytes);
- g->cs1 = (double *)malloc(bytes);
- memcpy((void *)(g->cs1), (void *)(p->cs1), bytes);
- g->cs2 = (double *)malloc(bytes);
- memcpy((void *)(g->cs2), (void *)(p->cs2), bytes);
- g->phs = (double *)malloc(bytes);
- memcpy((void *)(g->phs), (void *)(p->phs), bytes);
- g->use_sc = p->use_sc;
- }
- #endif
-
- bytes = g->size * sizeof(mus_float_t);
- /* we have to make a new phases array -- otherwise the original and copy step on each other */
- g->free_phases = true;
- g->phases = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phases), (void *)(p->phases), bytes);
- return((mus_any *)g);
- }
-
- static mus_float_t *ob_data(mus_any *ptr) {return(((ob *)ptr)->phases);}
-
- static mus_float_t run_oscil_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_oscil_bank(ptr));
- }
-
-
- static mus_long_t oscil_bank_length(mus_any *ptr)
- {
- return(((ob *)ptr)->size);
- }
-
-
- static mus_long_t oscil_bank_set_length(mus_any *ptr, mus_long_t len)
- {
- ob *g = (ob *)ptr;
- if (len < 0)
- g->size = 0;
- else
- {
- if (len > g->orig_size)
- g->size = g->orig_size;
- else g->size = len;
- }
- return(len);
- }
-
-
- static void oscil_bank_reset(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- p->size = p->orig_size;
- memset((void *)(p->phases), 0, p->orig_size * sizeof(mus_float_t));
- }
-
-
- static bool oscil_bank_equalp(mus_any *p1, mus_any *p2)
- {
- ob *o1 = (ob *)p1;
- ob *o2 = (ob *)p2;
- if (p1 == p2) return(true);
- return((o1->size == o2->size) &&
- (o1->orig_size == o2->orig_size) &&
- (o1->amps == o2->amps) &&
- (o1->freqs == o2->freqs) &&
- ((o1->phases == o2->phases) ||
- (clm_arrays_are_equal(o1->phases, o2->phases, o2->size))));
- }
-
-
- static char *describe_oscil_bank(mus_any *ptr)
- {
- ob *gen = (ob *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class OSCIL_BANK_CLASS = {
- MUS_OSCIL_BANK,
- (char *)S_oscil_bank,
- &free_oscil_bank,
- &describe_oscil_bank,
- &oscil_bank_equalp,
- &ob_data, 0,
- &oscil_bank_length, &oscil_bank_set_length,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_oscil_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &oscil_bank_reset,
- 0, &ob_copy
- };
-
-
- bool mus_is_oscil_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_OSCIL_BANK));
- }
-
-
- static mus_float_t oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- int i;
- mus_float_t sum = 0.0;
- if (!p->amps)
- {
- for (i = 0; i < p->size; i++)
- {
- sum += sin(p->phases[i]);
- p->phases[i] += p->freqs[i];
- }
- }
- else
- {
- for (i = 0; i < p->size; i++)
- {
- sum += (p->amps[i] * sin(p->phases[i]));
- p->phases[i] += p->freqs[i];
- }
- }
- return(sum);
- }
-
-
- #if HAVE_SINCOS
- static mus_float_t stable_oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- int i;
- mus_float_t sum = 0.0;
- if (p->use_sc)
- {
- for (i = 0; i < p->size; i++)
- sum += (p->sn1[i] * p->cs2[i] + p->cs1[i] * p->sn2[i]);
- p->use_sc = false;
- }
- else
- {
- double s, c;
- if (!p->amps)
- {
- for (i = 0; i < p->size; i++)
- {
- sincos(p->phases[i], &s, &c);
- p->sn2[i] = s;
- p->cs2[i] = c;
- sum += s;
- p->phases[i] += p->phs[i];
- }
- }
- else
- {
- for (i = 0; i < p->size; i++)
- {
- sincos(p->phases[i], &s, &c);
- p->sn2[i] = s;
- p->cs2[i] = c;
- sum += p->amps[i] * s;
- p->phases[i] += p->phs[i];
- }
- }
- p->use_sc = true;
- }
- return(sum);
- }
- #endif
-
-
- mus_float_t mus_oscil_bank(mus_any *ptr)
- {
- ob *p = (ob *)ptr;
- return(p->ob_func(ptr));
- }
-
-
- mus_any *mus_make_oscil_bank(int size, mus_float_t *freqs, mus_float_t *phases, mus_float_t *amps, bool stable)
- {
- ob *gen;
-
- gen = (ob *)malloc(sizeof(ob));
- gen->core = &OSCIL_BANK_CLASS;
- gen->orig_size = size;
- gen->size = size;
- gen->amps = amps;
- gen->freqs = freqs;
- gen->phases = phases;
- gen->free_phases = false;
- gen->ob_func = oscil_bank;
-
- #if HAVE_SINCOS
- if (stable)
- {
- int i;
- double s, c;
-
- gen->ob_func = stable_oscil_bank;
- gen->use_sc = false;
- gen->sn1 = (double *)malloc(size * sizeof(double));
- gen->sn2 = (double *)malloc(size * sizeof(double));
- gen->cs1 = (double *)malloc(size * sizeof(double));
- gen->cs2 = (double *)malloc(size * sizeof(double));
- gen->phs = (double *)malloc(size * sizeof(double));
-
- for (i = 0; i < size; i++)
- {
- sincos(freqs[i], &s, &c);
- if (amps)
- {
- s *= amps[i];
- c *= amps[i];
- }
- gen->sn1[i] = s;
- gen->cs1[i] = c;
- gen->phs[i] = freqs[i] * 2.0;
- }
- }
- else
- {
- gen->sn1 = NULL;
- gen->sn2 = NULL;
- gen->cs1 = NULL;
- gen->cs2 = NULL;
- gen->phs = NULL;
- }
- #endif
-
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- ncos ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int n;
- mus_float_t scaler, cos5, phase, freq;
- } cosp;
-
- #define DIVISOR_NEAR_ZERO(Den) (fabs(Den) < 1.0e-14)
-
- mus_float_t mus_ncos(mus_any *ptr, mus_float_t fm)
- {
- /* changed 25-Apr-04: use less stupid formula */
- /* (/ (- (/ (sin (* (+ n 0.5) angle)) (* 2 (sin (* 0.5 angle)))) 0.5) n) */
- mus_float_t val, den;
- cosp *gen = (cosp *)ptr;
- den = sin(gen->phase * 0.5);
- if (DIVISOR_NEAR_ZERO(den)) /* see note -- this was den == 0.0 1-Aug-07 */
- /* perhaps use DBL_EPSILON (1.0e-9 I think) */
- val = 1.0;
- else
- {
- val = (gen->scaler * (((sin(gen->phase * gen->cos5)) / (2.0 * den)) - 0.5));
- if (val > 1.0) val = 1.0;
- /* I think this can't happen now that we check den above, but just in case... */
- /* this check is actually incomplete, since we can be much below the correct value also, but the den check should fix those cases too */
- }
- gen->phase += (gen->freq + fm);
- return((mus_float_t)val);
- }
-
-
- /* I think we could add ncos_pm via:
- *
- * mus_float_t mus_ncos_pm(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- * {
- * cosp *gen = (cosp *)ptr;
- * mus_float_t result;
- * gen->phase += pm;
- * result = mus_ncos(ptr, fm);
- * gen->phase -= pm;
- * return(result);
- * }
- *
- * and the same trick could add pm to anything:
- *
- * mus_float_t mus_run_with_pm(mus_any *ptr, mus_float_t fm, mus_float_t pm)
- * {
- * mus_float_t result;
- * mus_set_phase(ptr, mus_phase(ptr) + pm);
- * result = mus_run(ptr, fm, 0.0);
- * mus_set_phase (ptr, mus_phase(ptr) - pm);
- * return(result);
- * }
- *
- * fm could also be handled here so the 4 cases become gen, mus_run_with_fm|pm|fm_and_pm(gen)
- * but... this could just as well happen at the extension language level, except that run doesn't expand macros?
- * The problem with differentiating the pm and using the fm arg is that we'd need a closure.
- */
-
- #if 0
- /* if the current phase is close to 0.0, there were numerical troubles here:
- :(/ (cos (* 1.5 pi 1.0000000000000007)) (cos (* 0.5 pi 1.0000000000000007)))
- -3.21167411694788
- :(/ (cos (* 1.5 pi 1.0000000000000004)) (cos (* 0.5 pi 1.0000000000000004)))
- -2.63292557243357
- :(/ (cos (* 1.5 pi 1.0000000000000002)) (cos (* 0.5 pi 1.0000000000000002)))
- -1.84007079646018
- :(/ (cos (* 1.5 pi 1.0000000000000001)) (cos (* 0.5 pi 1.0000000000000001)))
- -3.0
- :(/ (cos (* 1.5 pi 1.0000000000000008)) (cos (* 0.5 pi 1.0000000000000008)))
- -3.34939116712516
- ;; 16 bits in is probably too much for mus_float_ts
- ;; these numbers can be hit in normal cases:
-
- (define (ncos-with-inversions n x)
- ;; Andrews Askey Roy 261
- (let* ((num (cos (* x (+ 0.5 n))))
- (den (cos (* x 0.5)))
- (val (/ num den))) ; Chebyshev polynomial of the third kind! (4th uses sin = our current formula)
- (/ (- (if (even? n) val (- val))
- 0.5)
- (+ 1 (* n 2)))))
-
- (with-sound (:scaled-to 1.0)
- (do ((i 0 (+ i 1))
- (x 0.0 (+ x .01)))
- ((= i 200)) ; glitch at 100 (= 1)
- (outa i (ncos-with-inversions 1 (* pi x)) *output*)))
- */
- #endif
-
-
- bool mus_is_ncos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NCOS));
- }
-
-
- static void free_ncos(mus_any *ptr) {free(ptr);}
- static void ncos_reset(mus_any *ptr) {((cosp *)ptr)->phase = 0.0;}
-
- static mus_float_t ncos_freq(mus_any *ptr) {return(mus_radians_to_hz(((cosp *)ptr)->freq));}
- static mus_float_t ncos_set_freq(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t ncos_increment(mus_any *ptr) {return(((cosp *)ptr)->freq);}
- static mus_float_t ncos_set_increment(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->freq = val; return(val);}
-
- static mus_float_t ncos_phase(mus_any *ptr) {return(fmod(((cosp *)ptr)->phase, TWO_PI));}
- static mus_float_t ncos_set_phase(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->phase = val; return(val);}
-
- static mus_float_t ncos_scaler(mus_any *ptr) {return(((cosp *)ptr)->scaler);}
- static mus_float_t ncos_set_scaler(mus_any *ptr, mus_float_t val) {((cosp *)ptr)->scaler = val; return(val);}
-
- static mus_long_t ncos_n(mus_any *ptr) {return(((cosp *)ptr)->n);}
-
- static mus_any *cosp_copy(mus_any *ptr)
- {
- cosp *g;
- g = (cosp *)malloc(sizeof(cosp));
- memcpy((void *)g, (void *)ptr, sizeof(cosp));
- return((mus_any *)g);
- }
-
- static mus_long_t ncos_set_n(mus_any *ptr, mus_long_t val)
- {
- cosp *gen = (cosp *)ptr;
- if (val > 0)
- {
- gen->n = (int)val;
- gen->cos5 = val + 0.5;
- gen->scaler = 1.0 / (mus_float_t)val;
- }
- return(val);
- }
-
- static mus_float_t run_ncos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_ncos(ptr, fm));}
-
-
- static bool ncos_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_ncos((mus_any *)p1)) && (mus_is_ncos((mus_any *)p2)) &&
- ((((cosp *)p1)->freq) == (((cosp *)p2)->freq)) &&
- ((((cosp *)p1)->phase) == (((cosp *)p2)->phase)) &&
- ((((cosp *)p1)->n) == (((cosp *)p2)->n)) &&
- ((((cosp *)p1)->scaler) == (((cosp *)p2)->scaler))));
- }
-
-
- static char *describe_ncos(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, n: %d",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- static mus_any_class NCOS_CLASS = {
- MUS_NCOS,
- (char *)S_ncos,
- &free_ncos,
- &describe_ncos,
- &ncos_equalp,
- 0, 0, /* data */
- &ncos_n,
- &ncos_set_n,
- &ncos_freq,
- &ncos_set_freq,
- &ncos_phase,
- &ncos_set_phase,
- &ncos_scaler,
- &ncos_set_scaler,
- &ncos_increment,
- &ncos_set_increment,
- &run_ncos,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &ncos_reset,
- 0,
- &cosp_copy
- };
-
-
- mus_any *mus_make_ncos(mus_float_t freq, int n)
- {
- cosp *gen;
- gen = (cosp *)malloc(sizeof(cosp));
- gen->core = &NCOS_CLASS;
- if (n == 0) n = 1;
- gen->scaler = 1.0 / (mus_float_t)n;
- gen->n = n;
- gen->cos5 = n + 0.5;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = 0.0;
- return((mus_any *)gen);
- }
-
-
- /* ---------------- nsin ---------------- */
-
- static bool nsin_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_nsin((mus_any *)p1)) && (mus_is_nsin((mus_any *)p2)) &&
- ((((cosp *)p1)->freq) == (((cosp *)p2)->freq)) &&
- ((((cosp *)p1)->phase) == (((cosp *)p2)->phase)) &&
- ((((cosp *)p1)->n) == (((cosp *)p2)->n)) &&
- ((((cosp *)p1)->scaler) == (((cosp *)p2)->scaler))));
- }
-
-
- static char *describe_nsin(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, n: %d",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_nsin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NSIN));
- }
-
-
- #if 0
- /* its simplest to get the maxes by running an example and recording the maxamp, but it also
- * works for small "n" to use the derivative of the sum-of-sines as a Chebyshev polynomial in cos x,
- * find its roots, and plug acos(root) into the original, recording the max:
- *
- (define (smax coeffs)
- (let* ((n (vct-length coeffs))
- (dcos (make-vct n 1.0)))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (vct-set! dcos i (* (+ i 1) (vct-ref coeffs i))))
- (let ((partials ()))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (set! partials (append (list (vct-ref dcos i) (+ i 1)) partials)))
- (let ((Tn (partials->polynomial (reverse partials))))
- (let ((roots (poly-roots Tn)))
- (let ((mx (* -2 n)))
- (for-each
- (lambda (root)
- (let ((acr (acos root))
- (sum 0.0))
- (do ((i 0 (+ i 1)))
- ((= i n))
- (set! sum (+ sum (* (vct-ref coeffs i) (sin (* (+ i 1) acr))))))
- (if (> (abs sum) mx)
- (set! mx (abs sum)))))
- roots)
- mx))))))
-
- (smax (make-vct n 1.0))
-
- * but that's too much effort for an initialization function.
- * much faster is this search (it usually hits an answer in 2 or 3 tries):
- *
- (define (find-nsin-max n)
-
- (define (ns x n)
- (let* ((a2 (/ x 2))
- (den (sin a2)))
- (if (= den 0.0)
- 0.0
- (/ (* (sin (* n a2)) (sin (* (+ n 1) a2))) den))))
-
- (define (find-mid-max n lo hi)
- (let ((mid (/ (+ lo hi) 2)))
- (let ((ylo (ns lo n))
- (yhi (ns hi n)))
- (if (< (abs (- ylo yhi)) 1e-100)
- (list (ns mid n)
- (rationalize (/ mid pi) 0.0))
- (if (> ylo yhi)
- (find-mid-max n lo mid)
- (find-mid-max n mid hi))))))
-
- (find-mid-max n 0.0 (/ pi (+ n .5))))
- *
- * the 'mid' point has a surprisingly simple relation to pi:
- *
- * (find-max 100000000000000)
- * 7.24518620297426541161857919764185053934850053037407235e13
- *
- * (find-max 1000000000000000000000000)
- * 7.24518620297422918568756794921595308358209723004380140e23 1/1333333333333333333333334 = .75e-24 -> (3*pi)/(4*n)
- *
- * (find-max 10000000000000000000000000000000000)
- * 7.24518620297422918568756432662285195872681453497436666955413707681801083640192066844820049586929551886747925783e33
- *
- * which is approximately (/ (* 8 (expt (sin (* pi 3/8)) 2)) (* 3 pi)):
- * 7.245186202974229185687564326622851596467504
- *
- * (to get that expression, plug in 3pi/4n, treat (n+1)/n as essentially 1 as n gets very large,
- * treat (sin x) as about x when x is very small, and simplify)
- * so if n>10, we could use (ns (/ (* 3 pi) (* 4 n)) n) without major error
- * It's possible to differentiate the nsin formula:
- *
- * -(cos(x/2)sin(nx/2)sin((n+1)x/2))/(2sin^2(x/2)) + ncos(nx/2)sin((n+1)x/2)/(2sin(x/2)) + (n+1)sin(nx/2)cos((n+1)x/2)/(2sin(x/2))
- *
- * and find the first 0 when n is very large -- it is very close to 3pi/(4*n)
- */
- #endif
-
-
- static mus_float_t nsin_ns(mus_float_t x, int n)
- {
- mus_float_t a2, den;
- a2 = x / 2;
- den = sin(a2);
- if (den == 0.0)
- return(0.0);
- return(sin(n * a2) * sin((n + 1) * a2) / den);
- }
-
-
- static mus_float_t find_nsin_scaler(int n, mus_float_t lo, mus_float_t hi)
- {
- mus_float_t mid, ylo, yhi;
- mid = (lo + hi) / 2;
- ylo = nsin_ns(lo, n);
- yhi = nsin_ns(hi, n);
- if (fabs(ylo - yhi) < 1e-12)
- return(nsin_ns(mid, n));
- if (ylo > yhi)
- return(find_nsin_scaler(n, lo, mid));
- return(find_nsin_scaler(n, mid, hi));
- }
-
-
- static mus_float_t nsin_scaler(int n)
- {
- return(1.0 / find_nsin_scaler(n, 0.0, M_PI / (n + 0.5)));
- }
-
-
- static mus_long_t nsin_set_n(mus_any *ptr, mus_long_t val)
- {
- cosp *gen = (cosp *)ptr;
- gen->n = (int)val;
- gen->cos5 = val + 1.0;
- gen->scaler = nsin_scaler((int)val);
- return(val);
- }
-
-
- mus_float_t mus_nsin(mus_any *ptr, mus_float_t fm)
- {
- /* (let* ((a2 (* angle 0.5))
- (den (sin a2)))
- (if (= den 0.0)
- 0.0
- (/ (* (sin (* n a2)) (sin (* (+ n 1) a2))) den)))
- */
- #if HAVE_SINCOS
- double val, a2, ns, nc, s, c;
- cosp *gen = (cosp *)ptr;
- a2 = gen->phase * 0.5;
- sincos(a2, &s, &c);
- if (DIVISOR_NEAR_ZERO(s)) /* see note under ncos */
- val = 0.0;
- else
- {
- sincos(gen->n * a2, &ns, &nc);
- val = gen->scaler * ns * (ns * c + nc * s) / s;
- }
- #else
- mus_float_t val, den, a2;
- cosp *gen = (cosp *)ptr;
- a2 = gen->phase * 0.5;
- den = sin(a2);
- if (DIVISOR_NEAR_ZERO(den)) /* see note under ncos */
- val = 0.0;
- else val = gen->scaler * sin(gen->n * a2) * sin(a2 * gen->cos5) / den;
- #endif
- gen->phase += (gen->freq + fm);
- return((mus_float_t)val);
- }
-
-
- static mus_float_t run_nsin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nsin(ptr, fm));}
-
- static mus_any_class NSIN_CLASS = {
- MUS_NSIN,
- (char *)S_nsin,
- &free_ncos,
- &describe_nsin,
- &nsin_equalp,
- 0, 0, /* data */
- &ncos_n,
- &nsin_set_n,
- &ncos_freq,
- &ncos_set_freq,
- &ncos_phase,
- &ncos_set_phase,
- &ncos_scaler,
- &ncos_set_scaler,
- &ncos_increment,
- &ncos_set_increment,
- &run_nsin,
- MUS_NOT_SPECIAL,
- NULL,
- 0,
- 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &ncos_reset,
- 0,
- &cosp_copy
- };
-
-
- mus_any *mus_make_nsin(mus_float_t freq, int n)
- {
- cosp *gen;
- gen = (cosp *)mus_make_ncos(freq, n);
- gen->core = &NSIN_CLASS;
- gen->scaler = nsin_scaler(n);
- gen->cos5 = gen->n + 1.0;
- return((mus_any *)gen);
- }
-
-
- /* ---------------- asymmetric-fm ---------------- */
-
- /* changed from sin(sin) to cos(sin) and added amplitude normalization 6-Sep-07 */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t r;
- mus_float_t freq, phase;
- mus_float_t ratio;
- mus_float_t cosr, sinr;
- mus_float_t one;
- } asyfm;
-
-
- static void free_asymmetric_fm(mus_any *ptr) {free(ptr);}
- static void asyfm_reset(mus_any *ptr) {((asyfm *)ptr)->phase = 0.0;}
-
- static mus_any *asyfm_copy(mus_any *ptr)
- {
- asyfm *g;
- g = (asyfm *)malloc(sizeof(asyfm));
- memcpy((void *)g, (void *)ptr, sizeof(asyfm));
- return((mus_any *)g);
- }
-
- static mus_float_t asyfm_freq(mus_any *ptr) {return(mus_radians_to_hz(((asyfm *)ptr)->freq));}
- static mus_float_t asyfm_set_freq(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t asyfm_increment(mus_any *ptr) {return(((asyfm *)ptr)->freq);}
- static mus_float_t asyfm_set_increment(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->freq = val; return(val);}
-
- static mus_float_t asyfm_phase(mus_any *ptr) {return(fmod(((asyfm *)ptr)->phase, TWO_PI));}
- static mus_float_t asyfm_set_phase(mus_any *ptr, mus_float_t val) {((asyfm *)ptr)->phase = val; return(val);}
-
- static mus_float_t asyfm_ratio(mus_any *ptr) {return(((asyfm *)ptr)->ratio);}
-
- static mus_float_t asyfm_r(mus_any *ptr) {return(((asyfm *)ptr)->r);}
-
- static mus_float_t asyfm_set_r(mus_any *ptr, mus_float_t val)
- {
- asyfm *gen = (asyfm *)ptr;
- if (val != 0.0)
- {
- gen->r = val;
- gen->cosr = 0.5 * (val - (1.0 / val));
- gen->sinr = 0.5 * (val + (1.0 / val));
- if ((val > 1.0) ||
- ((val < 0.0) && (val > -1.0)))
- gen->one = -1.0;
- else gen->one = 1.0;
- }
- return(val);
- }
-
-
- static bool asyfm_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- (((p1->core)->type == (p2->core)->type) &&
- ((((asyfm *)p1)->freq) == (((asyfm *)p2)->freq)) &&
- ((((asyfm *)p1)->phase) == (((asyfm *)p2)->phase)) &&
- ((((asyfm *)p1)->ratio) == (((asyfm *)p2)->ratio)) &&
- ((((asyfm *)p1)->r) == (((asyfm *)p2)->r))));
- }
-
-
- static char *describe_asyfm(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, ratio: %.3f, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- ((asyfm *)ptr)->ratio,
- asyfm_r(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_asymmetric_fm(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ASYMMETRIC_FM));
- }
-
-
- mus_float_t mus_asymmetric_fm(mus_any *ptr, mus_float_t index, mus_float_t fm)
- {
- asyfm *gen = (asyfm *)ptr;
- mus_float_t result;
- mus_float_t mth;
- mth = gen->ratio * gen->phase;
- result = exp(index * gen->cosr * (gen->one + cos(mth))) * cos(gen->phase + index * gen->sinr * sin(mth));
- /* second index factor added 4-Mar-02 and (+/-)1.0 + cos to normalize amps 6-Sep-07 */
- gen->phase += (gen->freq + fm);
- return(result);
- }
-
-
- mus_float_t mus_asymmetric_fm_unmodulated(mus_any *ptr, mus_float_t index)
- {
- asyfm *gen = (asyfm *)ptr;
- mus_float_t result, mth;
- mth = gen->ratio * gen->phase;
- result = exp(index * gen->cosr * (gen->one + cos(mth))) * cos(gen->phase + index * gen->sinr * sin(mth));
- /* second index factor added 4-Mar-02 */
- gen->phase += gen->freq;
- return(result);
- }
-
- static mus_any_class ASYMMETRIC_FM_CLASS = {
- MUS_ASYMMETRIC_FM,
- (char *)S_asymmetric_fm,
- &free_asymmetric_fm,
- &describe_asyfm,
- &asyfm_equalp,
- 0, 0, 0, 0,
- &asyfm_freq,
- &asyfm_set_freq,
- &asyfm_phase,
- &asyfm_set_phase,
- &asyfm_r,
- &asyfm_set_r,
- &asyfm_increment,
- &asyfm_set_increment,
- &mus_asymmetric_fm,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &asyfm_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &asyfm_reset,
- 0,
- &asyfm_copy
- };
-
-
- mus_any *mus_make_asymmetric_fm(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 1.0, ratio 1.0 */
- {
- asyfm *gen = NULL;
- if (r == 0.0)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_asymmetric_fm ": r can't be 0.0");
- else
- {
- gen = (asyfm *)malloc(sizeof(asyfm));
- gen->core = &ASYMMETRIC_FM_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ratio = ratio;
- gen->cosr = 0.5 * (r - (1.0 / r)); /* 0.5 factor for I/2 */
- gen->sinr = 0.5 * (r + (1.0 / r));
- if ((r > 1.0) ||
- ((r < 0.0) && (r > -1.0)))
- gen->one = -1.0;
- else gen->one = 1.0;
- }
- return((mus_any *)gen);
- }
-
-
-
-
- /*---------------- nrxysin (sine-summation) and nrxycos ---------------- */
-
- /* the generator uses x and y (frequencies), but it's very common to start up with 0 freqs
- * and let the fm arg set the frequency, so it seems like we want to give the ratio between
- * the frequencies at make time, rather than two (possibly dummy) frequencies).
- * xy-ratio negative to build (via r) backwards.
- */
-
- #define MAX_R 0.999999
- #define MIN_R -0.999999
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase;
- int n;
- mus_float_t norm, r, r_to_n_plus_1, r_squared_plus_1, y_over_x;
- } nrxy;
-
-
- static void free_nrxy(mus_any *ptr) {free(ptr);}
- static void nrxy_reset(mus_any *ptr) {((nrxy *)ptr)->phase = 0.0;}
-
- static mus_any *nrxy_copy(mus_any *ptr)
- {
- nrxy *g;
- g = (nrxy *)malloc(sizeof(nrxy));
- memcpy((void *)g, (void *)ptr, sizeof(nrxy));
- return((mus_any *)g);
- }
-
- static mus_float_t nrxy_freq(mus_any *ptr) {return(mus_radians_to_hz(((nrxy *)ptr)->freq));}
- static mus_float_t nrxy_set_freq(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t nrxy_increment(mus_any *ptr) {return(((nrxy *)ptr)->freq);}
- static mus_float_t nrxy_set_increment(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->freq = val; return(val);}
-
- static mus_float_t nrxy_phase(mus_any *ptr) {return(fmod(((nrxy *)ptr)->phase, TWO_PI));}
- static mus_float_t nrxy_set_phase(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->phase = val; return(val);}
-
- static mus_long_t nrxy_n(mus_any *ptr) {return((mus_long_t)(((nrxy *)ptr)->n));}
-
- static mus_float_t nrxy_y_over_x(mus_any *ptr) {return(((nrxy *)ptr)->y_over_x);}
- static mus_float_t nrxy_set_y_over_x(mus_any *ptr, mus_float_t val) {((nrxy *)ptr)->y_over_x = val; return(val);}
-
- static mus_float_t nrxy_r(mus_any *ptr) {return(((nrxy *)ptr)->r);}
-
- static mus_float_t nrxy_set_r(mus_any *ptr, mus_float_t r)
- {
- nrxy *gen = (nrxy *)ptr;
- int n;
- n = gen->n;
- if (r > MAX_R) r = MAX_R;
- if (r < MIN_R) r = MIN_R;
- gen->r = r;
- gen->r_to_n_plus_1 = pow(r, n + 1);
- gen->r_squared_plus_1 = 1.0 + r * r;
- if (n == 0)
- gen->norm = 1.0;
- else gen->norm = (pow(fabs(r), n + 1) - 1.0) / (fabs(r) - 1.0);
- /* fabs here because if r<0.0, we line up at (2k-1)*pi rather than 2k*pi, but
- * otherwise the waveform is identical
- */
- return(r);
- }
-
- static bool nrxy_equalp(mus_any *p1, mus_any *p2)
- {
- nrxy *g1 = (nrxy *)p1;
- nrxy *g2 = (nrxy *)p2;
- return((p1 == p2) ||
- (((g1->core)->type == (g2->core)->type) &&
- (g1->freq == g2->freq) &&
- (g1->phase == g2->phase) &&
- (g1->n == g2->n) &&
- (g1->r == g2->r) &&
- (g1->y_over_x == g2->y_over_x)));
- }
-
-
- bool mus_is_nrxysin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NRXYSIN));
- }
-
-
- static char *describe_nrxysin(mus_any *ptr)
- {
- nrxy *gen = (nrxy *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, ratio: %.3f, phase: %.3f, n: %d, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- gen->y_over_x,
- mus_phase(ptr),
- gen->n,
- nrxy_r(ptr));
- return(describe_buffer);
- }
-
-
- mus_float_t mus_nrxysin(mus_any *ptr, mus_float_t fm)
- {
- /* Jolley 475 but 0..n rather than 0..n-1 */
- /* see also Durell and Robson "Advanced Trigonometry" p 175 */
-
- nrxy *gen = (nrxy *)ptr;
- mus_float_t x, y, r, divisor;
- int n;
-
- x = gen->phase;
- n = gen->n;
- r = gen->r;
- gen->phase += (gen->freq + fm);
-
-
- if (gen->y_over_x == 1.0)
- {
- #if (!HAVE_SINCOS)
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(x)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
- return((sin(x) - gen->r_to_n_plus_1 * (sin(x * (n + 2)) - r * sin(x * (n + 1)))) / divisor);
- #else
- double sx, cx, snx, cnx;
- sincos(x, &sx, &cx);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cx));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
- sincos((n + 1) * x, &snx, &cnx);
- return((sx - gen->r_to_n_plus_1 * (sx * cnx + (cx - r) * snx)) / divisor);
- #endif
- }
-
- #if HAVE_SINCOS
- {
- double xs, xc, ys, yc, nys, nyc, sin_x_y, sin_x_ny, sin_x_n1y, cos_x_ny;
-
- y = x * gen->y_over_x;
- sincos(y, &ys, &yc);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * yc));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
-
- sincos(x, &xs, &xc);
- sincos(n * y, &nys, &nyc);
- sin_x_y = (xs * yc - ys * xc);
- sin_x_ny = (xs * nyc + nys * xc);
- cos_x_ny = (xc * nyc - xs * nys);
- sin_x_n1y = (sin_x_ny * yc + cos_x_ny * ys);
-
- return((xs -
- r * sin_x_y -
- gen->r_to_n_plus_1 * (sin_x_n1y - r * sin_x_ny)) / divisor);
- }
- #else
- y = x * gen->y_over_x;
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(y)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(0.0);
-
- return((sin(x) -
- r * sin(x - y) -
- gen->r_to_n_plus_1 * (sin(x + (n + 1) * y) -
- r * sin(x + n * y))) /
- divisor);
- #endif
- }
-
-
- static mus_float_t run_nrxysin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nrxysin(ptr, fm));}
-
-
- static mus_any_class NRXYSIN_CLASS = {
- MUS_NRXYSIN,
- (char *)S_nrxysin,
- &free_nrxy,
- &describe_nrxysin,
- &nrxy_equalp,
- 0, 0,
- &nrxy_n, 0,
- &nrxy_freq,
- &nrxy_set_freq,
- &nrxy_phase,
- &nrxy_set_phase,
- &nrxy_r,
- &nrxy_set_r,
- &nrxy_increment,
- &nrxy_set_increment,
- &run_nrxysin,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &nrxy_y_over_x,
- &nrxy_set_y_over_x,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &nrxy_reset,
- 0,
- &nrxy_copy
- };
-
-
- mus_any *mus_make_nrxysin(mus_float_t frequency, mus_float_t y_over_x, int n, mus_float_t r)
- {
- nrxy *gen;
- gen = (nrxy *)malloc(sizeof(nrxy));
- gen->core = &NRXYSIN_CLASS;
- gen->freq = mus_hz_to_radians(frequency);
- gen->y_over_x = y_over_x;
- gen->phase = 0.0;
- gen->n = n;
- nrxy_set_r((mus_any *)gen, r);
- return((mus_any *)gen);
- }
-
-
- bool mus_is_nrxycos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NRXYCOS));
- }
-
-
- static char *describe_nrxycos(mus_any *ptr)
- {
- nrxy *gen = (nrxy *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, ratio: %.3f, phase: %.3f, n: %d, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- gen->y_over_x,
- mus_phase(ptr),
- gen->n,
- nrxy_r(ptr));
- return(describe_buffer);
- }
-
-
- mus_float_t mus_nrxycos(mus_any *ptr, mus_float_t fm)
- {
- nrxy *gen = (nrxy *)ptr;
- mus_float_t x, y, r, divisor;
- int n;
-
- x = gen->phase;
- y = x * gen->y_over_x;
- n = gen->n;
- r = gen->r;
-
- gen->phase += (gen->freq + fm);
-
- #if HAVE_SINCOS
- {
- double xs, xc, ys, yc, nys, nyc, cos_x_y, cos_x_ny, cos_x_n1y, sin_x_ny;
-
- sincos(y, &ys, &yc);
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * yc));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(1.0);
-
- sincos(x, &xs, &xc);
- sincos(n * y, &nys, &nyc);
- cos_x_y = (xc * yc + ys * xs);
- sin_x_ny = (xs * nyc + nys * xc);
- cos_x_ny = (xc * nyc - xs * nys);
- cos_x_n1y = (cos_x_ny * yc - sin_x_ny * ys);
- return((xc -
- r * cos_x_y -
- gen->r_to_n_plus_1 * (cos_x_n1y - r * cos_x_ny)) / divisor);
- }
- #else
- divisor = gen->norm * (gen->r_squared_plus_1 - (2 * r * cos(y)));
- if (DIVISOR_NEAR_ZERO(divisor))
- return(1.0);
- /* this can happen if r>0.9999999 or thereabouts;
- */
-
- return((cos(x) -
- r * cos(x - y) -
- gen->r_to_n_plus_1 * (cos(x + (n + 1) * y) -
- r * cos(x + n * y))) /
- divisor);
- #endif
- }
-
-
- static mus_float_t run_nrxycos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_nrxycos(ptr, fm));}
-
-
- static mus_any_class NRXYCOS_CLASS = {
- MUS_NRXYCOS,
- (char *)S_nrxycos,
- &free_nrxy,
- &describe_nrxycos,
- &nrxy_equalp,
- 0, 0,
- &nrxy_n, 0,
- &nrxy_freq,
- &nrxy_set_freq,
- &nrxy_phase,
- &nrxy_set_phase,
- &nrxy_r,
- &nrxy_set_r,
- &nrxy_increment,
- &nrxy_set_increment,
- &run_nrxycos,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &nrxy_y_over_x,
- &nrxy_set_y_over_x,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &nrxy_reset,
- 0,
- &nrxy_copy
- };
-
-
- mus_any *mus_make_nrxycos(mus_float_t frequency, mus_float_t y_over_x, int n, mus_float_t r)
- {
- nrxy *gen;
- gen = (nrxy *)mus_make_nrxysin(frequency, y_over_x, n, r);
- gen->core = &NRXYCOS_CLASS;
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- rxykcos/sin ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t r, ar;
- mus_float_t freq, phase;
- mus_float_t ratio;
- } rxyk;
-
-
- static void free_rxykcos(mus_any *ptr) {free(ptr);}
- static void rxyk_reset(mus_any *ptr) {((rxyk *)ptr)->phase = 0.0;}
-
- static mus_any *rxyk_copy(mus_any *ptr)
- {
- rxyk *g;
- g = (rxyk *)malloc(sizeof(rxyk));
- memcpy((void *)g, (void *)ptr, sizeof(rxyk));
- return((mus_any *)g);
- }
-
- static mus_float_t rxyk_freq(mus_any *ptr) {return(mus_radians_to_hz(((rxyk *)ptr)->freq));}
- static mus_float_t rxyk_set_freq(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t rxyk_increment(mus_any *ptr) {return(((rxyk *)ptr)->freq);}
- static mus_float_t rxyk_set_increment(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->freq = val; return(val);}
-
- static mus_float_t rxyk_phase(mus_any *ptr) {return(fmod(((rxyk *)ptr)->phase, TWO_PI));}
- static mus_float_t rxyk_set_phase(mus_any *ptr, mus_float_t val) {((rxyk *)ptr)->phase = val; return(val);}
-
- static mus_float_t rxyk_ratio(mus_any *ptr) {return(((rxyk *)ptr)->ratio);}
-
- static mus_float_t rxyk_r(mus_any *ptr) {return(((rxyk *)ptr)->r);}
-
- static mus_float_t rxyk_set_r(mus_any *ptr, mus_float_t val)
- {
- rxyk *gen = (rxyk *)ptr;
- gen->r = val;
- gen->ar = 1.0 / exp(fabs(val));
- return(val);
- }
-
- static mus_float_t run_rxykcos(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rxykcos(ptr, fm));}
- static mus_float_t run_rxyksin(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rxyksin(ptr, fm));}
-
- static bool rxyk_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- (((p1->core)->type == (p2->core)->type) &&
- ((((rxyk *)p1)->freq) == (((rxyk *)p2)->freq)) &&
- ((((rxyk *)p1)->phase) == (((rxyk *)p2)->phase)) &&
- ((((rxyk *)p1)->ratio) == (((rxyk *)p2)->ratio)) &&
- ((((rxyk *)p1)->r) == (((rxyk *)p2)->r))));
- }
-
-
- static char *describe_rxyk(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, ratio: %.3f, r: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- ((rxyk *)ptr)->ratio,
- rxyk_r(ptr));
- return(describe_buffer);
- }
-
-
- bool mus_is_rxykcos(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RXYKCOS));
- }
-
-
- mus_float_t mus_rxykcos(mus_any *ptr, mus_float_t fm)
- {
- rxyk *gen = (rxyk *)ptr;
- mus_float_t result, rx;
-
- rx = gen->ratio * gen->phase;
- result = gen->ar * exp(gen->r * cos(rx)) * cos(gen->phase + (gen->r * sin(rx)));
- gen->phase += (fm + gen->freq);
-
- return(result);
- }
-
-
- static mus_any_class RXYKCOS_CLASS = {
- MUS_RXYKCOS,
- (char *)S_rxykcos,
- &free_rxykcos,
- &describe_rxyk,
- &rxyk_equalp,
- 0, 0, 0, 0,
- &rxyk_freq,
- &rxyk_set_freq,
- &rxyk_phase,
- &rxyk_set_phase,
- &rxyk_r,
- &rxyk_set_r,
- &rxyk_increment,
- &rxyk_set_increment,
- &run_rxykcos,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &rxyk_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &rxyk_reset,
- 0,
- &rxyk_copy
- };
-
-
- mus_any *mus_make_rxykcos(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 0.5, ratio 1.0 */
- {
- rxyk *gen = NULL;
- gen = (rxyk *)malloc(sizeof(rxyk));
- gen->core = &RXYKCOS_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ar = 1.0 / exp(fabs(r));
- gen->ratio = ratio;
- return((mus_any *)gen);
- }
-
-
-
- bool mus_is_rxyksin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RXYKSIN));
- }
-
-
- mus_float_t mus_rxyksin(mus_any *ptr, mus_float_t fm)
- {
- rxyk *gen = (rxyk *)ptr;
- mus_float_t result, rx;
-
- rx = gen->ratio * gen->phase;
- result = gen->ar * exp(gen->r * cos(rx)) * sin(gen->phase + (gen->r * sin(rx)));
- gen->phase += (fm + gen->freq);
-
- return(result);
- }
-
-
- static mus_any_class RXYKSIN_CLASS = {
- MUS_RXYKSIN,
- (char *)S_rxyksin,
- &free_rxykcos,
- &describe_rxyk,
- &rxyk_equalp,
- 0, 0, 0, 0,
- &rxyk_freq,
- &rxyk_set_freq,
- &rxyk_phase,
- &rxyk_set_phase,
- &rxyk_r,
- &rxyk_set_r,
- &rxyk_increment,
- &rxyk_set_increment,
- &run_rxyksin,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &rxyk_ratio,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &rxyk_reset,
- 0,
- &rxyk_copy
- };
-
-
- mus_any *mus_make_rxyksin(mus_float_t freq, mus_float_t phase, mus_float_t r, mus_float_t ratio) /* r default 0.5, ratio 1.0 */
- {
- rxyk *gen = NULL;
- gen = (rxyk *)malloc(sizeof(rxyk));
- gen->core = &RXYKSIN_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->phase = phase;
- gen->r = r;
- gen->ar = 1.0 / exp(fabs(r));
- gen->ratio = ratio;
- return((mus_any *)gen);
- }
-
-
-
-
- /* ---------------- table lookup ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, internal_mag, phase;
- mus_float_t *table;
- mus_long_t table_size;
- mus_interp_t type;
- bool table_allocated;
- mus_float_t yn1;
- mus_float_t (*tbl_look)(mus_any *ptr, mus_float_t fm);
- mus_float_t (*tbl_look_unmod)(mus_any *ptr);
- } tbl;
-
-
- mus_float_t *mus_partials_to_wave(mus_float_t *partial_data, int partials, mus_float_t *table, mus_long_t table_size, bool normalize)
- {
- int partial, k;
- if (!table) return(NULL);
- memset((void *)table, 0, table_size * sizeof(mus_float_t));
- for (partial = 0, k = 1; partial < partials; partial++, k += 2)
- {
- mus_float_t amp;
- amp = partial_data[k];
- if (amp != 0.0)
- {
- mus_long_t i;
- mus_float_t freq, angle;
- freq = (partial_data[partial * 2] * TWO_PI) / (mus_float_t)table_size;
- for (i = 0, angle = 0.0; i < table_size; i++, angle += freq)
- table[i] += amp * sin(angle);
- }
- }
- if (normalize)
- return(array_normalize(table, table_size));
- return(table);
- }
-
-
- mus_float_t *mus_phase_partials_to_wave(mus_float_t *partial_data, int partials, mus_float_t *table, mus_long_t table_size, bool normalize)
- {
- int partial, k, n;
- if (!table) return(NULL);
- memset((void *)table, 0, table_size * sizeof(mus_float_t));
- for (partial = 0, k = 1, n = 2; partial < partials; partial++, k += 3, n += 3)
- {
- mus_float_t amp;
- amp = partial_data[k];
- if (amp != 0.0)
- {
- mus_long_t i;
- mus_float_t freq, angle;
- freq = (partial_data[partial * 3] * TWO_PI) / (mus_float_t)table_size;
- for (i = 0, angle = partial_data[n]; i < table_size; i++, angle += freq)
- table[i] += amp * sin(angle);
- }
- }
- if (normalize)
- return(array_normalize(table, table_size));
- return(table);
- }
-
-
- mus_float_t mus_table_lookup(mus_any *ptr, mus_float_t fm)
- {
- return(((tbl *)ptr)->tbl_look(ptr, fm));
- }
-
- static mus_float_t table_look_linear(mus_any *ptr, mus_float_t fm)
- {
- tbl *gen = (tbl *)ptr;
-
- /* we're checking already for out-of-range indices, so mus_array_interp is more than we need */
- mus_long_t int_part;
- mus_float_t frac_part, f1;
-
- int_part = (mus_long_t)(gen->phase); /* floor(gen->phase) -- slow! modf is even worse */
- frac_part = gen->phase - int_part;
- f1 = gen->table[int_part];
- int_part++;
-
- if (int_part == gen->table_size)
- gen->yn1 = f1 + frac_part * (gen->table[0] - f1);
- else gen->yn1 = f1 + frac_part * (gen->table[int_part] - f1);
-
- gen->phase += (gen->freq + (fm * gen->internal_mag));
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- static mus_float_t table_look_any(mus_any *ptr, mus_float_t fm)
- {
- tbl *gen = (tbl *)ptr;
-
- gen->yn1 = mus_interpolate(gen->type, gen->phase, gen->table, gen->table_size, gen->yn1);
- gen->phase += (gen->freq + (fm * gen->internal_mag));
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- mus_float_t mus_table_lookup_unmodulated(mus_any *ptr)
- {
- return(((tbl *)ptr)->tbl_look_unmod(ptr));
- }
-
- static mus_float_t table_look_unmodulated_linear(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
- mus_long_t int_part;
- mus_float_t frac_part, f1;
-
- int_part = (mus_long_t)(gen->phase);
- frac_part = gen->phase - int_part;
- f1 = gen->table[int_part];
- int_part++;
-
- if (int_part == gen->table_size)
- f1 += frac_part * (gen->table[0] - f1);
- else f1 += frac_part * (gen->table[int_part] - f1);
-
- gen->phase += gen->freq;
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(f1);
- }
-
-
- static mus_float_t table_look_unmodulated_any(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
-
- gen->yn1 = mus_interpolate(gen->type, gen->phase, gen->table, gen->table_size, gen->yn1);
- gen->phase += gen->freq;
- if ((gen->phase >= gen->table_size) ||
- (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, gen->table_size);
- if (gen->phase < 0.0)
- gen->phase += gen->table_size;
- }
- return(gen->yn1);
- }
-
-
- static mus_float_t run_table_lookup(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(((tbl *)ptr)->tbl_look(ptr, fm)); }
-
- bool mus_is_table_lookup(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TABLE_LOOKUP));
- }
-
- static mus_long_t table_lookup_length(mus_any *ptr) {return(((tbl *)ptr)->table_size);}
- static mus_float_t *table_lookup_data(mus_any *ptr) {return(((tbl *)ptr)->table);}
-
- static mus_float_t table_lookup_freq(mus_any *ptr) {return((((tbl *)ptr)->freq * sampling_rate) / (((tbl *)ptr)->table_size));}
- static mus_float_t table_lookup_set_freq(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->freq = (val * ((tbl *)ptr)->table_size) / sampling_rate; return(val);}
-
- static mus_float_t table_lookup_increment(mus_any *ptr) {return(((tbl *)ptr)->freq);}
- static mus_float_t table_lookup_set_increment(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->freq = val; return(val);}
-
- static mus_float_t table_lookup_phase(mus_any *ptr) {return(fmod(((TWO_PI * ((tbl *)ptr)->phase) / ((tbl *)ptr)->table_size), TWO_PI));}
- static mus_float_t table_lookup_set_phase(mus_any *ptr, mus_float_t val) {((tbl *)ptr)->phase = (val * ((tbl *)ptr)->table_size) / TWO_PI; return(val);}
-
- static int table_lookup_interp_type(mus_any *ptr) {return((int)(((tbl *)ptr)->type));} /* ints here and elsewhere to fit mus_channels method = interp-type */
-
- static void table_lookup_reset(mus_any *ptr) {((tbl *)ptr)->phase = 0.0;}
-
-
- static char *describe_table_lookup(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, length: %d, interp: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_length(ptr),
- interp_type_to_string(table_lookup_interp_type(ptr)));
- return(describe_buffer);
- }
-
-
- static bool table_lookup_equalp(mus_any *p1, mus_any *p2)
- {
- tbl *t1 = (tbl *)p1;
- tbl *t2 = (tbl *)p2;
- if (p1 == p2) return(true);
- return((t1) && (t2) &&
- (t1->core->type == t2->core->type) &&
- (t1->table_size == t2->table_size) &&
- (t1->freq == t2->freq) &&
- (t1->phase == t2->phase) &&
- (t1->type == t2->type) &&
- (t1->internal_mag == t2->internal_mag) &&
- (clm_arrays_are_equal(t1->table, t2->table, t1->table_size)));
- }
-
-
- static void free_table_lookup(mus_any *ptr)
- {
- tbl *gen = (tbl *)ptr;
- if ((gen->table) && (gen->table_allocated)) free(gen->table);
- free(gen);
- }
-
- static mus_any *tbl_copy(mus_any *ptr)
- {
- mus_long_t bytes;
- tbl *g, *p;
-
- p = (tbl *)ptr;
- g = (tbl *)malloc(sizeof(tbl));
- memcpy((void *)g, (void *)ptr, sizeof(tbl));
-
- bytes = g->table_size * sizeof(mus_float_t);
- g->table = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->table), (void *)(p->table), bytes);
- g->table_allocated = true;
-
- return((mus_any *)g);
- }
-
- static mus_float_t *table_set_data(mus_any *ptr, mus_float_t *val)
- {
- tbl *gen = (tbl *)ptr;
- if (gen->table_allocated) {free(gen->table); gen->table_allocated = false;}
- gen->table = val;
- return(val);
- }
-
-
- static mus_any_class TABLE_LOOKUP_CLASS = {
- MUS_TABLE_LOOKUP,
- (char *)S_table_lookup,
- &free_table_lookup,
- &describe_table_lookup,
- &table_lookup_equalp,
- &table_lookup_data,
- &table_set_data,
- &table_lookup_length,
- 0,
- &table_lookup_freq,
- &table_lookup_set_freq,
- &table_lookup_phase,
- &table_lookup_set_phase,
- &fallback_scaler, 0,
- &table_lookup_increment,
- &table_lookup_set_increment,
- &run_table_lookup,
- MUS_NOT_SPECIAL,
- NULL,
- &table_lookup_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &table_lookup_reset,
- 0, &tbl_copy
- };
-
-
- mus_any *mus_make_table_lookup(mus_float_t freq, mus_float_t phase, mus_float_t *table, mus_long_t table_size, mus_interp_t type)
- {
- tbl *gen;
- gen = (tbl *)malloc(sizeof(tbl));
- gen->core = &TABLE_LOOKUP_CLASS;
- gen->table_size = table_size;
- gen->internal_mag = table_size / TWO_PI;
- gen->freq = (freq * table_size) / sampling_rate;
- gen->phase = (fmod(phase, TWO_PI) * table_size) / TWO_PI;
- gen->type = type;
- if (type == MUS_INTERP_LINEAR)
- {
- gen->tbl_look = table_look_linear;
- gen->tbl_look_unmod = table_look_unmodulated_linear;
- }
- else
- {
- gen->tbl_look = table_look_any;
- gen->tbl_look_unmod = table_look_unmodulated_any;
- }
- gen->yn1 = 0.0;
- if (table)
- {
- gen->table = table;
- gen->table_allocated = false;
- }
- else
- {
- gen->table = (mus_float_t *)calloc(table_size, sizeof(mus_float_t));
- gen->table_allocated = true;
- }
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- polywave ---------------- */
-
- mus_float_t *mus_partials_to_polynomial(int npartials, mus_float_t *partials, mus_polynomial_t kind)
- {
- /* coeffs returned in partials */
- int i;
- mus_long_t *T0, *T1, *Tn;
- mus_float_t *Cc1;
-
- T0 = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- T1 = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- Tn = (mus_long_t *)calloc(npartials + 1, sizeof(mus_long_t));
- Cc1 = (mus_float_t *)calloc(npartials + 1, sizeof(mus_float_t));
-
- if (kind == MUS_CHEBYSHEV_FIRST_KIND)
- T0[0] = 1;
- else T0[0] = 0;
- T1[1] = 1;
-
- Cc1[0] = partials[0]; /* DC requested? */
-
- for (i = 1; i < npartials; i++)
- {
- int k;
- mus_float_t amp;
- amp = partials[i];
- if (amp != 0.0)
- {
- if (kind == MUS_CHEBYSHEV_FIRST_KIND)
- for (k = 0; k <= i; k++)
- Cc1[k] += (amp * T1[k]);
- else
- for (k = 1; k <= i; k++)
- Cc1[k - 1] += (amp * T1[k]);
- }
- for (k = i + 1; k > 0; k--)
- Tn[k] = (2 * T1[k - 1]) - T0[k];
- Tn[0] = -T0[0];
- for (k = i + 1; k >= 0; k--)
- {
- T0[k] = T1[k];
- T1[k] = Tn[k];
- }
- }
-
- for (i = 0; i < npartials; i++)
- partials[i] = Cc1[i];
-
- free(T0);
- free(T1);
- free(Tn);
- free(Cc1);
- return(partials);
- }
-
-
- mus_float_t *mus_normalize_partials(int num_partials, mus_float_t *partials)
- {
- int i;
- mus_float_t sum = 0.0;
- for (i = 0; i < num_partials; i++)
- sum += fabs(partials[2 * i + 1]);
- if ((sum != 0.0) &&
- (sum != 1.0))
- {
- sum = 1.0 / sum;
- for (i = 0; i < num_partials; i++)
- partials[2 * i + 1] *= sum;
- }
- return(partials);
- }
-
-
- typedef struct {
- mus_any_class *core;
- mus_float_t phase, freq;
- mus_float_t *coeffs, *ucoeffs;
- int n, cheby_choice;
- mus_float_t index;
- mus_float_t (*polyw)(mus_any *ptr, mus_float_t fm);
- } pw;
-
-
- mus_float_t (*mus_polywave_function(mus_any *g))(mus_any *gen, mus_float_t fm)
- {
- if (mus_is_polywave(g))
- return(((pw *)g)->polyw);
- return(NULL);
- }
-
- static void free_pw(mus_any *pt) {free(pt);}
-
- static mus_any *pw_copy(mus_any *ptr)
- {
- pw *g;
- g = (pw *)malloc(sizeof(pw));
- memcpy((void *)g, (void *)ptr, sizeof(pw));
- return((mus_any *)g);
- }
-
- static void pw_reset(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- gen->phase = 0.0;
- }
-
-
- static bool pw_equalp(mus_any *p1, mus_any *p2)
- {
- pw *w1 = (pw *)p1;
- pw *w2 = (pw *)p2;
- if (p1 == p2) return(true);
- return((w1) && (w2) &&
- (w1->core->type == w2->core->type) &&
- (w1->freq == w2->freq) &&
- (w1->phase == w2->phase) &&
- (w1->n == w2->n) &&
- (w1->index == w2->index) &&
- (w1->cheby_choice == w2->cheby_choice) &&
- (clm_arrays_are_equal(w1->coeffs, w2->coeffs, w1->n)));
- }
-
-
- static mus_float_t pw_freq(mus_any *ptr) {return(mus_radians_to_hz(((pw *)ptr)->freq));}
- static mus_float_t pw_set_freq(mus_any *ptr, mus_float_t val) {((pw *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t pw_increment(mus_any *ptr) {return(((pw *)ptr)->freq);}
- static mus_float_t pw_set_increment(mus_any *ptr, mus_float_t val) {((pw *)ptr)->freq = val; return(val);}
-
- static mus_float_t pw_phase(mus_any *ptr) {return(fmod(((pw *)ptr)->phase, TWO_PI));}
- static mus_float_t pw_set_phase(mus_any *ptr, mus_float_t val) {((pw *)ptr)->phase = val; return(val);}
-
- static mus_long_t pw_n(mus_any *ptr) {return(((pw *)ptr)->n);}
- static mus_long_t pw_set_n(mus_any *ptr, mus_long_t val) {((pw *)ptr)->n = (int)val; return(val);}
-
- static mus_float_t *pw_data(mus_any *ptr) {return(((pw *)ptr)->coeffs);}
- static mus_float_t *pw_udata(mus_any *ptr) {return(((pw *)ptr)->ucoeffs);}
- static mus_float_t *pw_set_data(mus_any *ptr, mus_float_t *val) {((pw *)ptr)->coeffs = val; return(val);}
-
- static mus_float_t pw_xcoeff(mus_any *ptr, int index) {return(((pw *)ptr)->coeffs[index]);}
- static mus_float_t pw_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {((pw *)ptr)->coeffs[index] = val; return(val);}
-
- static mus_float_t pw_ycoeff(mus_any *ptr, int index) {if (((pw *)ptr)->ucoeffs) return(((pw *)ptr)->ucoeffs[index]); return(0.0);}
- static mus_float_t pw_set_ycoeff(mus_any *ptr, int index, mus_float_t val) {if (((pw *)ptr)->ucoeffs) ((pw *)ptr)->ucoeffs[index] = val; return(val);}
-
- static mus_float_t pw_index(mus_any *ptr) {return(((pw *)ptr)->index);}
- static mus_float_t pw_set_index(mus_any *ptr, mus_float_t val) {((pw *)ptr)->index = val; return(val);}
-
- static int pw_choice(mus_any *ptr) {return(((pw *)ptr)->cheby_choice);}
-
-
- mus_float_t mus_chebyshev_tu_sum(mus_float_t x, int n, mus_float_t *tn, mus_float_t *un)
- {
- /* the Clenshaw algorithm -- beware of -cos(nx) where you'd expect cos(nx) */
- mus_float_t x2, tb, tb1 = 0.0, tb2, cx, ub, ub1 = 0.0;
- mus_float_t *tp, *up;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- tp = (mus_float_t *)(tn + n - 1);
- up = (mus_float_t *)(un + n - 1);
- tb = (*tp--);
- ub = (*up--);
-
- while (up != un)
- {
- mus_float_t ub2;
- tb2 = tb1;
- tb1 = tb;
- tb = x2 * tb1 - tb2 + (*tp--);
-
- ub2 = ub1;
- ub1 = ub;
- ub = x2 * ub1 - ub2 + (*up--);
- }
-
- tb2 = tb1;
- tb1 = tb;
- tb = x2 * tb1 - tb2 + tn[0];
-
- return((mus_float_t)((tb - tb1 * cx) + (sin(x) * ub)));
- }
-
-
- mus_float_t mus_chebyshev_t_sum(mus_float_t x, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i >= 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
- #if 0
- /* here is the trick to do odd Tn without doing the intervening evens: */
- (define (mus-chebyshev-odd-t-sum x n t2n)
- (let* ((b1 0.0)
- (b2 0.0)
- (cx1 (cos x))
- (cx (- (* 2 cx1 cx1) 1))
- (x2 (* 2.0 cx))
- (b (vct-ref t2n (- n 1))))
- (do ((i (- n 2) (1- i)))
- ((< i 0))
- (set! b2 b1)
- (set! b1 b)
- (set! b (- (+ (* b1 x2) (vct-ref t2n i)) b2)))
- (* cx1 (- b b1))))
-
- (with-sound ()
- (let ((t2n (vct 0.5 0.25 0.25))
- (x 0.0)
- (dx (hz->radians 10.0)))
- (do ((i 0 (+ i 1)))
- ((= i 22050))
- (outa i (mus-chebyshev-odd-t-sum x 3 t2n))
- (set! x (+ x dx)))))
- #endif
-
-
- mus_float_t mus_chebyshev_u_sum(mus_float_t x, int n, mus_float_t *un)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = cos(x);
- x2 = 2.0 * cx;
-
- /* Un calc */
- b = un[n - 1];
- for (i = n - 2; i > 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + un[i];
- }
-
- return((mus_float_t)(sin(x) * b));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, b2, cx;
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- i = n - 2;
- while (i >= 4)
- {
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- for (; i >= 0; i--)
- {
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_2(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_3(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_t_sum_with_index_5(mus_float_t x, mus_float_t index, int n, mus_float_t *tn)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Tn calc */
- b = tn[n - 1];
- for (i = n - 2; i > 0;) /* this was >= ?? (also cases above) -- presumably a copy-and-paste typo? */
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
-
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + tn[i--];
- }
- return((mus_float_t)(b - b1 * cx));
- }
-
-
- static mus_float_t mus_chebyshev_u_sum_with_index(mus_float_t x, mus_float_t index, int n, mus_float_t *un)
- {
- int i;
- mus_float_t x2, b, b1 = 0.0, cx;
-
- cx = index * cos(x);
- x2 = 2.0 * cx;
-
- /* Un calc */
- b = un[n - 1];
- for (i = n - 2; i > 0; i--)
- {
- mus_float_t b2;
- b2 = b1;
- b1 = b;
- b = x2 * b1 - b2 + un[i];
- }
-
- return((mus_float_t)(sin(x) * b + un[0])); /* don't drop the constant, 16-Jan-14 */
- }
-
- /* (with-sound () (let ((p (make-polywave 100 (list 0 0.5 1 -.2) mus-chebyshev-second-kind))) (do ((i 0 (+ i 1))) ((= i 1000)) (outa i (polywave p)))))
- */
-
- static mus_float_t polyw_second_2(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
-
- x = gen->phase; /* this order (as opposed to saving the full expr below) is much faster?! */
- gen->phase += (gen->freq + fm);
- return(gen->coeffs[1] * sin(x) + gen->coeffs[0]);
- }
-
-
- static mus_float_t polyw_first_1(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
-
- x = gen->phase;
- gen->phase += (gen->freq + fm);
- return(gen->index * cos(x));
- }
-
-
- static mus_float_t polyw_first_3(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x, cx;
- mus_float_t *tn;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- return((2.0 * cx * tn[2] + tn[1]) * cx - tn[2]);
-
- /* b = x2 * b1 - b2;, then return(b - b1 * cx)
- * but x2 = 2 * cx, so b1*(x2 - cx) -> b1 * cx
- * and the final recursion unrolls. The old code
- * (which thought tn[0] might not be 0.0) was:
- * cx = cos(x);
- * x2 = 2.0 * cx;
- * b = tn[2];
- * b2 = b1; -- but b1 is 0
- * b1 = b; -- b not used so this is tn[2]
- * b = x2 * b1 - b2 + tn[1]; -- b2 is 0.0
- * b2 = b1;
- * b1 = b;
- * b = x2 * b1 - b2 + tn[0];
- * return(b - b1 * cx);
- */
- }
-
- /* (with-sound () (let ((p (make-polywave 100 (list 1 .5 2 .25)))) (do ((i 0 (+ i 1))) ((= i 30000)) (outa i (polywave p))))) */
-
-
- static mus_float_t polyw_first_4(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x, x2, b, cx;
- mus_float_t *tn;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b = x2 * tn[3] + tn[2]; /* was -tn[2]! 19-Feb-14 */
- return((x2 * b - tn[3] + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[4];
- b = x2 * b1 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_6(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[5];
- b = x2 * b1 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_8(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[7];
- b = x2 * b1 + tn[6];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[5];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first_11(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t x;
- mus_float_t *tn;
- mus_float_t x2, b, b1, b2, cx;
-
- x = gen->phase;
- tn = gen->coeffs;
- gen->phase += (gen->freq + fm);
-
- cx = cos(x);
- x2 = 2.0 * cx;
- b1 = tn[10];
- b = x2 * b1 + tn[9];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[8];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[7];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[6];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[5];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[4];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[3];
- b2 = b1; b1 = b; b = x2 * b1 - b2 + tn[2];
-
- return((x2 * b - b1 + tn[1]) * cx - b);
- }
-
-
- static mus_float_t polyw_first(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f1(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t cx;
- cx = gen->index * cos(gen->phase);
- gen->phase += (gen->freq + fm);
- return(cx * gen->coeffs[1] + gen->coeffs[0]);
- }
-
-
- static mus_float_t polyw_f2(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_2(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f3(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_3(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_f5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_t_sum_with_index_5(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_second(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_u_sum_with_index(ph, gen->index, gen->n, gen->coeffs));
- }
-
-
- static mus_float_t polyw_second_5(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t *un;
- mus_float_t x, b, b1, cx;
-
- x = gen->phase;
- gen->phase += (gen->freq + fm);
- /* gen->n is 5 */
- un = gen->coeffs;
-
- /* this is a candidate for sincos, but gcc is already using it here! */
- cx = 2.0 * cos(x);
- b1 = cx * un[4] + un[3];
- b = cx * b1 + gen->index;
-
- return(sin(x) * (cx * b - b1 + un[1]));
- }
-
-
- static mus_float_t polyw_third(mus_any *ptr, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t ph;
- ph = gen->phase;
- gen->phase += (gen->freq + fm);
- return(mus_chebyshev_tu_sum(ph, gen->n, gen->coeffs, gen->ucoeffs));
- }
-
-
- mus_float_t mus_polywave(mus_any *ptr, mus_float_t fm)
- {
- /* changed to use recursion, rather than polynomial in x, 25-May-08
- * this algorithm taken from Mason and Handscomb, "Chebyshev Polynomials" p27
- */
- return((((pw *)ptr)->polyw)(ptr, fm));
- }
-
-
- mus_float_t mus_polywave_unmodulated(mus_any *ptr)
- {
- return(mus_polywave(ptr, 0.0));
- }
-
-
- static mus_float_t run_polywave(mus_any *ptr, mus_float_t fm, mus_float_t ignored) {return(mus_polywave(ptr, fm));}
-
-
- static char *describe_polywave(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- char *str;
- char *describe_buffer;
- str = float_array_to_string(gen->coeffs, gen->n, 0);
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, coeffs[%d]: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- gen->n,
- str);
- free(str);
- return(describe_buffer);
- }
-
-
- static mus_float_t pw_set_index_and_func(mus_any *ptr, mus_float_t val)
- {
- pw *gen = (pw *)ptr;
- gen->index = val;
- if (gen->cheby_choice == MUS_CHEBYSHEV_FIRST_KIND)
- gen->polyw = polyw_first;
- else gen->polyw = polyw_second;
- return(val);
- }
-
-
- static mus_any_class POLYWAVE_CLASS = {
- MUS_POLYWAVE,
- (char *)S_polywave,
- &free_pw,
- &describe_polywave,
- &pw_equalp,
- &pw_data,
- &pw_set_data,
- &pw_n,
- &pw_set_n,
- &pw_freq,
- &pw_set_freq,
- &pw_phase,
- &pw_set_phase,
- &pw_index,
- &pw_set_index_and_func,
- &pw_increment,
- &pw_set_increment,
- &run_polywave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- &pw_xcoeff, &pw_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
- &pw_choice,
- &pw_ycoeff, &pw_set_ycoeff,
- &pw_data, &pw_udata,
- &pw_reset,
- 0, &pw_copy
- };
-
-
- mus_any *mus_make_polywave(mus_float_t frequency, mus_float_t *coeffs, int n, int cheby_choice)
- {
- pw *gen;
- gen = (pw *)malloc(sizeof(pw));
- gen->core = &POLYWAVE_CLASS;
- gen->phase = 0.0; /* cos used in cheby funcs above */
- gen->freq = mus_hz_to_radians(frequency);
- gen->coeffs = coeffs;
- gen->ucoeffs = NULL;
- gen->n = n;
- gen->index = 1.0;
- gen->cheby_choice = cheby_choice;
- if (cheby_choice != MUS_CHEBYSHEV_SECOND_KIND)
- {
- if (coeffs[0] == 0.0)
- {
- /* these also ignore gen->index (assumed to be 1.0) (leaving aside the first_1 case)
- * pw_set_index_and_func protects against that case
- */
- if (n == 2)
- {
- gen->polyw = polyw_first_1;
- gen->index = coeffs[1];
- }
- else
- {
- if (n == 3)
- gen->polyw = polyw_first_3;
- else
- {
- if (n == 4)
- gen->polyw = polyw_first_4;
- else
- {
- if (n == 5)
- gen->polyw = polyw_first_5;
- else
- {
- if (n == 6)
- gen->polyw = polyw_first_6;
- else
- {
- if (n == 8)
- gen->polyw = polyw_first_8;
- else
- {
- if (n == 11) /* a common case oddly enough */
- gen->polyw = polyw_first_11;
- else
- {
- if (((n - 1) % 5) == 0)
- gen->polyw = polyw_f5;
- else
- {
- if (((n - 1) % 3) == 0)
- gen->polyw = polyw_f3;
- else
- {
- if (((n - 1) % 2) == 0)
- gen->polyw = polyw_f2;
- else
- {
- /* lots of n=8 here */
- gen->polyw = polyw_first;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- else
- {
- if (n == 2)
- gen->polyw = polyw_f1;
- else
- {
- if (((n - 1) % 3) == 0)
- gen->polyw = polyw_f3;
- else
- {
- if (((n - 1) % 2) == 0)
- gen->polyw = polyw_f2;
- else gen->polyw = polyw_first;
- }
- }
- }
- }
- else
- {
- if ((n == 5) &&
- (coeffs[0] == 0.0))
- {
- gen->polyw = polyw_second_5;
- gen->index = coeffs[2] - coeffs[4];
- }
- else
- {
- if (n == 2)
- gen->polyw = polyw_second_2;
- else gen->polyw = polyw_second;
- }
- }
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_polywave_tu(mus_float_t frequency, mus_float_t *tcoeffs, mus_float_t *ucoeffs, int n)
- {
- pw *gen;
- gen = (pw *)malloc(sizeof(pw));
- gen->core = &POLYWAVE_CLASS;
- gen->phase = 0.0; /* cos used in cheby funcs above */
- gen->freq = mus_hz_to_radians(frequency);
- gen->coeffs = tcoeffs;
- gen->ucoeffs = ucoeffs;
- gen->n = n;
- gen->index = 1.0;
- gen->cheby_choice = MUS_CHEBYSHEV_BOTH_KINDS;
- gen->polyw = polyw_third;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_polywave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_POLYWAVE));
- }
-
-
-
- /* ---------------- polyshape ---------------- */
-
- static char *describe_polyshape(mus_any *ptr)
- {
- pw *gen = (pw *)ptr;
- char *str;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- str = float_array_to_string(gen->coeffs, gen->n, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, coeffs[%d]: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- gen->n,
- str);
- free(str);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_polyshape(mus_any *ptr, mus_float_t index, mus_float_t fm)
- {
- pw *gen = (pw *)ptr;
- mus_float_t result;
- gen->index = index;
- result = mus_polynomial(gen->coeffs,
- index * cos(gen->phase),
- gen->n);
-
- if (gen->cheby_choice == MUS_CHEBYSHEV_SECOND_KIND)
- result *= sin(gen->phase);
-
- gen->phase += (gen->freq + fm);
- return(result);
- }
-
-
- mus_float_t mus_polyshape_unmodulated(mus_any *ptr, mus_float_t index)
- {
- pw *gen = (pw *)ptr;
- mus_float_t result;
- gen->index = index;
- result = mus_polynomial(gen->coeffs,
- index * cos(gen->phase),
- gen->n);
-
- if (gen->cheby_choice == MUS_CHEBYSHEV_SECOND_KIND)
- result *= sin(gen->phase);
-
- gen->phase += gen->freq;
- return(result);
- }
-
-
- static mus_any_class POLYSHAPE_CLASS = {
- MUS_POLYSHAPE,
- (char *)S_polyshape,
- &free_pw,
- &describe_polyshape,
- &pw_equalp,
- &pw_data,
- &pw_set_data,
- &pw_n,
- &pw_set_n,
- &pw_freq,
- &pw_set_freq,
- &pw_phase,
- &pw_set_phase,
- &pw_index, &pw_set_index,
- &pw_increment,
- &pw_set_increment,
- &mus_polyshape,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pw_reset,
- 0, &pw_copy
- };
-
-
- mus_any *mus_make_polyshape(mus_float_t frequency, mus_float_t phase, mus_float_t *coeffs, int size, int cheby_choice)
- {
- mus_any *gen;
- gen = mus_make_polywave(frequency, coeffs, size, cheby_choice);
- gen->core = &POLYSHAPE_CLASS;
- pw_set_phase(gen, phase);
- return(gen);
- }
-
-
- bool mus_is_polyshape(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_POLYSHAPE));
- }
-
-
-
-
-
- /* ---------------- wave-train ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase;
- mus_float_t *wave; /* passed in from caller */
- mus_long_t wave_size;
- mus_float_t *out_data;
- mus_long_t out_data_size;
- mus_interp_t interp_type; /* "type" field exists in core -- avoid confusion */
- mus_float_t next_wave_time;
- mus_long_t out_pos;
- bool first_time;
- mus_float_t yn1;
- } wt;
-
-
- static mus_float_t wt_freq(mus_any *ptr) {return(((wt *)ptr)->freq);}
- static mus_float_t wt_set_freq(mus_any *ptr, mus_float_t val) {((wt *)ptr)->freq = val; return(val);}
-
- static mus_float_t wt_phase(mus_any *ptr) {return(fmod(((TWO_PI * ((wt *)ptr)->phase) / ((mus_float_t)((wt *)ptr)->wave_size)), TWO_PI));}
- static mus_float_t wt_set_phase(mus_any *ptr, mus_float_t val) {((wt *)ptr)->phase = (fmod(val, TWO_PI) * ((wt *)ptr)->wave_size) / TWO_PI; return(val);}
-
- static mus_long_t wt_length(mus_any *ptr) {return(((wt *)ptr)->wave_size);}
- static mus_long_t wt_set_length(mus_any *ptr, mus_long_t val) {if (val > 0) ((wt *)ptr)->wave_size = val; return(((wt *)ptr)->wave_size);}
-
- static int wt_interp_type(mus_any *ptr) {return((int)(((wt *)ptr)->interp_type));}
-
- static mus_float_t *wt_data(mus_any *ptr) {return(((wt *)ptr)->wave);}
- static mus_float_t *wt_set_data(mus_any *ptr, mus_float_t *data) {((wt *)ptr)->wave = data; return(data);}
-
- static mus_any *wt_copy(mus_any *ptr)
- {
- wt *g, *p;
- int bytes;
- p = (wt *)ptr;
- g = (wt *)malloc(sizeof(wt));
- memcpy((void *)g, (void *)ptr, sizeof(wt));
- bytes = g->out_data_size * sizeof(mus_float_t);
- g->out_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->out_data), (void *)(p->out_data), bytes);
- /* g->wave is caller's data */
- return((mus_any *)g);
- }
-
- static bool wt_equalp(mus_any *p1, mus_any *p2)
- {
- wt *w1 = (wt *)p1;
- wt *w2 = (wt *)p2;
- if (p1 == p2) return(true);
- return((w1) && (w2) &&
- (w1->core->type == w2->core->type) &&
- (w1->freq == w2->freq) &&
- (w1->phase == w2->phase) &&
- (w1->interp_type == w2->interp_type) &&
- (w1->wave_size == w2->wave_size) &&
- (w1->out_data_size == w2->out_data_size) &&
- (w1->out_pos == w2->out_pos) &&
- (clm_arrays_are_equal(w1->wave, w2->wave, w1->wave_size)) &&
- (clm_arrays_are_equal(w1->out_data, w2->out_data, w1->out_data_size)));
- }
-
- static char *describe_wt(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, size: %lld, interp: %s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_length(ptr),
- interp_type_to_string(wt_interp_type(ptr)));
- return(describe_buffer);
- }
-
-
- static mus_float_t mus_wave_train_any(mus_any *ptr, mus_float_t fm)
- {
- wt *gen = (wt *)ptr;
- mus_float_t result = 0.0;
-
- if (gen->out_pos < gen->out_data_size)
- result = gen->out_data[gen->out_pos];
- gen->out_pos++;
- if (gen->out_pos >= gen->next_wave_time)
- {
- mus_long_t i;
- mus_float_t *wave, *out_data;
- mus_long_t wave_size;
-
- wave = gen->wave;
- wave_size = gen->wave_size;
- out_data = gen->out_data;
-
- if (gen->out_pos < gen->out_data_size)
- {
- mus_long_t good_samps;
- good_samps = gen->out_data_size - gen->out_pos;
- memmove((void *)out_data, (void *)(out_data + gen->out_pos), good_samps * sizeof(mus_float_t));
- memset((void *)(out_data + good_samps), 0, gen->out_pos * sizeof(mus_float_t));
- }
- else memset((void *)out_data, 0, gen->out_data_size * sizeof(mus_float_t));
- if (gen->interp_type == MUS_INTERP_LINEAR)
- {
- /* gen->phase doesn't change, and i is an int, so we can precalculate the fractional part, etc
- */
- mus_float_t phase, frac_part;
- mus_long_t int_part;
-
- phase = gen->phase;
- if ((phase < 0.0) || (phase > wave_size))
- {
- phase = fmod((mus_float_t)phase, (mus_float_t)wave_size);
- if (phase < 0.0) phase += wave_size;
- }
-
- int_part = (mus_long_t)floor(phase);
- frac_part = phase - int_part;
- if (int_part == wave_size) int_part = 0;
-
- if (frac_part == 0.0)
- {
- mus_long_t p;
- for (i = 0, p = int_part; i < wave_size; i++, p++)
- {
- if (p == wave_size) p = 0;
- out_data[i] += wave[p];
- }
- }
- else
- {
- mus_long_t p, p1;
- for (i = 0, p = int_part, p1 = int_part + 1; i < wave_size; i++, p1++)
- {
- if (p1 == wave_size) p1 = 0;
- out_data[i] += (wave[p] + frac_part * (wave[p1] - wave[p]));
- p = p1;
- }
- }
- }
- else
- {
- for (i = 0; i < wave_size; i++)
- {
- gen->yn1 = mus_interpolate(gen->interp_type, gen->phase + i, wave, wave_size, gen->yn1);
- out_data[i] += gen->yn1;
- }
- }
- if (gen->first_time)
- {
- gen->first_time = false;
- gen->out_pos = (mus_long_t)(gen->phase); /* initial phase, but as an integer in terms of wave table size (gad...) */
- if (gen->out_pos >= wave_size)
- gen->out_pos = gen->out_pos % wave_size;
- result = out_data[gen->out_pos++];
- gen->next_wave_time = ((mus_float_t)sampling_rate / (gen->freq + fm));
- }
- else
- {
- gen->next_wave_time += (((mus_float_t)sampling_rate / (gen->freq + fm)) - gen->out_pos);
- gen->out_pos = 0;
- }
- }
- return(result);
- }
-
-
- mus_float_t mus_wave_train(mus_any *ptr, mus_float_t fm) {return(mus_wave_train_any(ptr, fm / w_rate));}
-
- mus_float_t mus_wave_train_unmodulated(mus_any *ptr) {return(mus_wave_train(ptr, 0.0));}
-
- static mus_float_t run_wave_train(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_wave_train_any(ptr, fm / w_rate));}
-
- static void free_wt(mus_any *p)
- {
- wt *ptr = (wt *)p;
- if (ptr->out_data)
- {
- free(ptr->out_data);
- ptr->out_data = NULL;
- }
- free(ptr);
- }
-
-
- static void wt_reset(mus_any *ptr)
- {
- wt *gen = (wt *)ptr;
- gen->phase = 0.0;
- memset((void *)(gen->out_data), 0, gen->out_data_size * sizeof(mus_float_t));
- gen->out_pos = gen->out_data_size;
- gen->next_wave_time = 0.0;
- gen->first_time = true;
- }
-
-
- static mus_any_class WAVE_TRAIN_CLASS = {
- MUS_WAVE_TRAIN,
- (char *)S_wave_train,
- &free_wt,
- &describe_wt,
- &wt_equalp,
- &wt_data,
- &wt_set_data,
- &wt_length,
- &wt_set_length,
- &wt_freq,
- &wt_set_freq,
- &wt_phase,
- &wt_set_phase,
- &fallback_scaler, 0,
- 0, 0,
- &run_wave_train,
- MUS_NOT_SPECIAL,
- NULL,
- &wt_interp_type,
- 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &wt_reset,
- 0, &wt_copy
- };
-
-
- mus_any *mus_make_wave_train(mus_float_t freq, mus_float_t phase, mus_float_t *wave, mus_long_t wave_size, mus_interp_t type)
- {
- wt *gen;
- gen = (wt *)malloc(sizeof(wt));
- gen->core = &WAVE_TRAIN_CLASS;
- gen->freq = freq;
- gen->phase = (wave_size * fmod(phase, TWO_PI)) / TWO_PI;
- gen->wave = wave;
- gen->wave_size = wave_size;
- gen->interp_type = type;
- gen->out_data_size = wave_size + 2;
- gen->out_data = (mus_float_t *)calloc(gen->out_data_size, sizeof(mus_float_t));
- gen->out_pos = gen->out_data_size;
- gen->next_wave_time = 0.0;
- gen->first_time = true;
- gen->yn1 = 0.0;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_wave_train(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_WAVE_TRAIN));
- }
-
-
-
-
- /* ---------------- delay, comb, notch, all-pass, moving-average, filtered-comb ---------------- */
-
- typedef struct dly {
- mus_any_class *core;
- unsigned int loc, size;
- bool zdly, line_allocated, filt_allocated;
- mus_float_t *line;
- unsigned int zloc, zsize;
- mus_float_t xscl, yscl, yn1, y1, norm;
- mus_interp_t type;
- mus_any *filt;
- struct dly *next;
- mus_float_t (*runf)(mus_any *gen, mus_float_t arg1, mus_float_t arg2);
- mus_float_t (*del)(mus_any *ptr, mus_float_t input); /* zdelay or normal tap */
- mus_float_t (*delt)(mus_any *ptr, mus_float_t input); /* just tick */
- mus_float_t (*delu)(mus_any *ptr, mus_float_t input); /* unmodulated */
- } dly;
-
-
-
- mus_float_t mus_delay_tick(mus_any *ptr, mus_float_t input)
- {
- return(((dly *)ptr)->delt(ptr, input));
- }
-
-
- mus_float_t mus_tap(mus_any *ptr, mus_float_t loc)
- {
- return(((dly *)ptr)->del(ptr, loc));
- }
-
-
- mus_float_t mus_delay_unmodulated(mus_any *ptr, mus_float_t input)
- {
- return(((dly *)ptr)->delu(ptr, input));
- }
-
-
- static mus_float_t ztap(mus_any *ptr, mus_float_t loc)
- {
- dly *gen = (dly *)ptr;
- /* this is almost always linear */
- if (gen->type == MUS_INTERP_LINEAR)
- return(mus_array_interp(gen->line, gen->zloc - loc, gen->zsize));
- gen->yn1 = mus_interpolate(gen->type, gen->zloc - loc, gen->line, gen->zsize, gen->yn1);
- return(gen->yn1);
- }
-
-
- static mus_float_t dtap(mus_any *ptr, mus_float_t loc)
- {
- dly *gen = (dly *)ptr;
- int taploc;
- if (gen->size == 0) return(gen->line[0]);
- if ((int)loc == 0) return(gen->line[gen->loc]);
- taploc = (int)(gen->loc - (int)loc) % gen->size;
- if (taploc < 0) taploc += gen->size;
- return(gen->line[taploc]);
- }
-
-
- mus_float_t mus_tap_unmodulated(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- return(gen->line[gen->loc]);
- }
-
-
- static mus_float_t zdelt(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->zsize) gen->loc = 0;
- gen->zloc++;
- if (gen->zloc >= gen->zsize) gen->zloc = 0;
- return(input);
- }
-
-
- static mus_float_t delt(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size) gen->loc = 0;
- return(input);
- }
-
-
- mus_float_t mus_delay(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- mus_float_t result;
- dly *gen = (dly *)ptr;
- if ((gen->size == 0) && (pm < 1.0))
- result = pm * gen->line[0] + (1.0 - pm) * input;
- else result = mus_tap(ptr, pm);
- mus_delay_tick(ptr, input);
- return(result);
- }
-
-
- static mus_float_t zdelay_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->zloc];
- mus_delay_tick(ptr, input);
- return(result);
- }
-
-
- static mus_float_t delay_unmodulated_zero(mus_any *ptr, mus_float_t input)
- {
- return(input);
- }
-
-
- mus_float_t mus_delay_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
- static dly *dly_free_list = NULL;
-
- static void free_delay(mus_any *gen)
- {
- dly *ptr = (dly *)gen;
- if ((ptr->line) && (ptr->line_allocated)) free(ptr->line);
- if ((ptr->filt) && (ptr->filt_allocated)) mus_free(ptr->filt);
- /* free(ptr); */
- ptr->next = dly_free_list;
- dly_free_list = ptr;
- }
-
-
- static mus_any *dly_copy(mus_any *ptr)
- {
- dly *g, *p;
- mus_long_t bytes;
- p = (dly *)ptr;
- if (dly_free_list)
- {
- g = dly_free_list;
- dly_free_list = g->next;
- }
- else g = (dly *)malloc(sizeof(dly));
- memcpy((void *)g, (void *)ptr, sizeof(dly));
-
- bytes = g->size * sizeof(mus_float_t);
- g->line = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->line), (void *)(p->line), bytes);
- g->line_allocated = true;
-
- if (p->filt)
- {
- g->filt = mus_copy(p->filt);
- g->filt_allocated = true;
- }
- return((mus_any *)g);
- }
-
-
- static char *describe_delay(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s line[%u, %s]: %s",
- mus_name(ptr),
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static bool delay_equalp(mus_any *p1, mus_any *p2)
- {
- dly *d1 = (dly *)p1;
- dly *d2 = (dly *)p2;
- if (p1 == p2) return(true);
- return((d1) && (d2) &&
- (d1->core->type == d2->core->type) &&
- (d1->size == d2->size) &&
- (d1->loc == d2->loc) &&
- (d1->zdly == d2->zdly) &&
- (d1->zloc == d2->zloc) &&
- (d1->zsize == d2->zsize) &&
- (d1->xscl == d2->xscl) &&
- (d1->yscl == d2->yscl) &&
- (d1->yn1 == d2->yn1) &&
- (d1->type == d2->type) &&
- (clm_arrays_are_equal(d1->line, d2->line, d1->size)));
- }
-
-
- static mus_long_t delay_length(mus_any *ptr)
- {
- dly *d = (dly *)ptr;
- if (d->size > 0) /* this is possible (not sure it's a good idea...) */
- return(d->size);
- return(d->zsize); /* maybe always use this? */
- }
-
-
- static mus_float_t delay_scaler(mus_any *ptr) {return(((dly *)ptr)->xscl);}
- static mus_float_t delay_set_scaler(mus_any *ptr, mus_float_t val) {((dly *)ptr)->xscl = val; return(val);}
-
- static mus_float_t delay_fb(mus_any *ptr) {return(((dly *)ptr)->yscl);}
- static mus_float_t delay_set_fb(mus_any *ptr, mus_float_t val) {((dly *)ptr)->yscl = val; return(val);}
-
- static int delay_interp_type(mus_any *ptr) {return((int)(((dly *)ptr)->type));}
- static mus_long_t delay_loc(mus_any *ptr){return((mus_long_t)(((dly *)ptr)->loc));}
- static mus_float_t *delay_data(mus_any *ptr) {return(((dly *)ptr)->line);}
- static mus_float_t *delay_set_data(mus_any *ptr, mus_float_t *val)
- {
- dly *gen = (dly *)ptr;
- if (gen->line_allocated) {free(gen->line); gen->line_allocated = false;}
- gen->line = val;
- return(val);
- }
-
-
- static mus_long_t delay_set_length(mus_any *ptr, mus_long_t val)
- {
- dly *gen = (dly *)ptr;
- if (val > 0)
- {
- unsigned int old_size;
- old_size = gen->size;
- gen->size = (unsigned int)val;
- if (gen->size < old_size)
- {
- if (gen->loc > gen->size) gen->loc = 0;
- gen->zdly = false; /* otherwise too many ways to screw up */
- }
- }
- return((mus_long_t)(gen->size));
- }
-
-
- bool mus_is_tap(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_DELAY_LINE));
- }
-
-
- static void delay_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- gen->loc = 0;
- gen->zloc = 0;
- gen->yn1 = 0.0;
- memset((void *)(gen->line), 0, gen->zsize * sizeof(mus_float_t));
- }
-
-
- static mus_any_class DELAY_CLASS = {
- MUS_DELAY,
- (char *)S_delay,
- &free_delay,
- &describe_delay,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_delay,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_delay(int size, mus_float_t *preloaded_line, int line_size, mus_interp_t type)
- {
- /* if preloaded_line null, allocated locally.
- * if size == line_size, normal (non-interpolating) delay
- * in clm2xen.c, if size=0 and max-size unset, max-size=1 (line_size here)
- */
- dly *gen;
- if (dly_free_list)
- {
- gen = dly_free_list;
- dly_free_list = gen->next;
- }
- else gen = (dly *)malloc(sizeof(dly));
- gen->core = &DELAY_CLASS;
- gen->loc = 0;
- gen->size = size;
- gen->zsize = line_size;
- gen->zdly = ((line_size != size) || (type != MUS_INTERP_NONE));
- if (gen->zdly)
- {
- gen->del = ztap;
- gen->delt = zdelt;
- if (gen->size == 0)
- gen->delu = delay_unmodulated_zero;
- else gen->delu = zdelay_unmodulated;
- }
- else
- {
- gen->del = dtap;
- gen->delt = delt;
- if (gen->size == 0)
- gen->delu = delay_unmodulated_zero;
- else gen->delu = mus_delay_unmodulated_noz;
- }
- gen->type = type;
- if (preloaded_line)
- {
- gen->line = preloaded_line;
- gen->line_allocated = false;
- }
- else
- {
- gen->line = (mus_float_t *)calloc((line_size <= 0) ? 1 : line_size, sizeof(mus_float_t));
- gen->line_allocated = true;
- }
- gen->zloc = line_size - size;
- gen->filt = NULL;
- gen->filt_allocated = false;
- gen->xscl = 0.0;
- gen->yscl = 0.0;
- gen->yn1 = 0.0;
- gen->runf = NULL;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_delay(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_DELAY));
- }
-
-
- /* ---------------- comb ---------------- */
-
- mus_float_t mus_comb(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- return(mus_delay(ptr, input + (gen->yscl * mus_tap(ptr, pm)), pm));
- /* mus.lisp has 0 in place of the final pm -- the question is whether the delay
- should interpolate as well as the tap. There is a subtle difference in
- output (the pm case is low-passed by the interpolation ("average")),
- but I don't know if there's a standard here, or what people expect.
- We're doing the outer-level interpolation in notch and all-pass.
- Should mus.lisp be changed?
- */
- else return(mus_delay_unmodulated(ptr, input + (gen->line[gen->loc] * gen->yscl)));
- }
-
-
- mus_float_t mus_comb_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- return(mus_delay_unmodulated(ptr, input + (gen->line[gen->zloc] * gen->yscl)));
- return(mus_delay_unmodulated(ptr, input + (gen->line[gen->loc] * gen->yscl)));
- }
-
-
- mus_float_t mus_comb_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
-
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input + (result * gen->yscl);
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
-
- return(result);
- }
-
-
- static char *describe_comb(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->yscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u, %s]: %s",
- mus_name(ptr),
- gen->yscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class COMB_CLASS = {
- MUS_COMB,
- (char *)S_comb,
- &free_delay,
- &describe_comb,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_comb,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_comb(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &COMB_CLASS;
- gen->yscl = scaler;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- bool mus_is_comb(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_COMB));
- }
-
-
-
- /* ---------------- comb-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*cmbf)(mus_any *ptr, mus_float_t input);
- } cmb_bank;
-
-
- static void free_comb_bank(mus_any *ptr)
- {
- cmb_bank *f = (cmb_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *cmb_bank_copy(mus_any *ptr)
- {
- cmb_bank *g, *p;
- int i;
-
- p = (cmb_bank *)ptr;
- g = (cmb_bank *)malloc(sizeof(cmb_bank));
- memcpy((void *)g, (void *)ptr, sizeof(cmb_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_comb_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_comb_bank(ptr, input));
- }
-
-
- static mus_long_t comb_bank_length(mus_any *ptr)
- {
- return(((cmb_bank *)ptr)->size);
- }
-
-
- static void comb_bank_reset(mus_any *ptr)
- {
- cmb_bank *f = (cmb_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool comb_bank_equalp(mus_any *p1, mus_any *p2)
- {
- cmb_bank *f1 = (cmb_bank *)p1;
- cmb_bank *f2 = (cmb_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!delay_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- /* now check the locals... */
- return(true);
- }
-
-
- static char *describe_comb_bank(mus_any *ptr)
- {
- cmb_bank *gen = (cmb_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class COMB_BANK_CLASS = {
- MUS_COMB_BANK,
- (char *)S_comb_bank,
- &free_comb_bank,
- &describe_comb_bank,
- &comb_bank_equalp,
- 0, 0,
- &comb_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_comb_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &comb_bank_reset,
- 0, &cmb_bank_copy
- };
-
-
- static mus_float_t comb_bank_any(mus_any *combs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = 0.0;
- cmb_bank *c = (cmb_bank *)combs;
- for (i = 0; i < c->size; i++)
- sum += mus_comb_unmodulated_noz(c->gens[i], inval);
- return(sum);
- }
-
- static mus_float_t comb_bank_4(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *c = (cmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(mus_comb_unmodulated_noz(gs[0], inval) +
- mus_comb_unmodulated_noz(gs[1], inval) +
- mus_comb_unmodulated_noz(gs[2], inval) +
- mus_comb_unmodulated_noz(gs[3], inval));
- }
-
- static mus_float_t comb_bank_6(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *c = (cmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(mus_comb_unmodulated_noz(gs[0], inval) +
- mus_comb_unmodulated_noz(gs[1], inval) +
- mus_comb_unmodulated_noz(gs[2], inval) +
- mus_comb_unmodulated_noz(gs[3], inval) +
- mus_comb_unmodulated_noz(gs[4], inval) +
- mus_comb_unmodulated_noz(gs[5], inval));
- }
-
-
- mus_any *mus_make_comb_bank(int size, mus_any **combs)
- {
- cmb_bank *gen;
- int i;
-
- gen = (cmb_bank *)malloc(sizeof(cmb_bank));
- gen->core = &COMB_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- gen->gens[i] = combs[i];
-
- if (size == 4)
- gen->cmbf = comb_bank_4;
- else
- {
- if (size == 6)
- gen->cmbf = comb_bank_6;
- else gen->cmbf = comb_bank_any;
- }
-
- return((mus_any *)gen);
- }
-
- bool mus_is_comb_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_COMB_BANK));
- }
-
- mus_float_t mus_comb_bank(mus_any *combs, mus_float_t inval)
- {
- cmb_bank *gen = (cmb_bank *)combs;
- return((gen->cmbf)(combs, inval));
- }
-
-
-
-
- /* ---------------- notch ---------------- */
-
- static char *describe_notch(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u,%u, %s]: %s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s scaler: %.3f, line[%u, %s]: %s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class NOTCH_CLASS = {
- MUS_NOTCH,
- (char *)S_notch,
- &free_delay,
- &describe_notch,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- 0, 0,
- &mus_notch,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_float_t mus_notch(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *gen = (dly *)ptr;
- return((input * gen->xscl) + mus_delay(ptr, input, pm));
- }
-
-
- mus_float_t mus_notch_unmodulated(mus_any *ptr, mus_float_t input)
- {
- return((input * ((dly *)ptr)->xscl) + mus_delay_unmodulated(ptr, input));
- }
-
- #if 0
- static mus_float_t mus_notch_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc] + (input * gen->xscl);
- gen->line[gen->loc] = input;
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
- #endif
-
- bool mus_is_notch(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_NOTCH));
- }
-
-
- mus_any *mus_make_notch(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &NOTCH_CLASS;
- gen->xscl = scaler;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_float_t mus_all_pass(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- mus_float_t din;
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- din = input + (gen->yscl * mus_tap(ptr, pm));
- else din = input + (gen->yscl * gen->line[gen->loc]);
- return(mus_delay(ptr, din, pm) + (gen->xscl * din));
- }
-
-
- mus_float_t mus_all_pass_unmodulated(mus_any *ptr, mus_float_t input)
- {
- mus_float_t din;
- dly *gen = (dly *)ptr;
- if (gen->zdly)
- din = input + (gen->yscl * gen->line[gen->zloc]);
- else din = input + (gen->yscl * gen->line[gen->loc]);
- return(mus_delay_unmodulated(ptr, din) + (gen->xscl * din));
- }
-
-
- mus_float_t mus_all_pass_unmodulated_noz(mus_any *ptr, mus_float_t input)
- {
- mus_float_t result, din;
- dly *gen = (dly *)ptr;
- unsigned int loc;
- loc = gen->loc++;
- din = input + (gen->yscl * gen->line[loc]);
- result = gen->line[loc] + (gen->xscl * din);
- gen->line[loc] = din;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
-
- bool mus_is_all_pass(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ALL_PASS));
- }
-
-
- static char *describe_all_pass(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (gen->zdly)
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s feedback: %.3f, feedforward: %.3f, line[%u,%u, %s]:%s",
- mus_name(ptr),
- gen->yscl,
- gen->xscl,
- gen->size,
- gen->zsize,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->zloc));
- else snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s feedback: %.3f, feedforward: %.3f, line[%u, %s]:%s",
- mus_name(ptr),
- gen->yscl,
- gen->xscl,
- gen->size,
- interp_type_to_string(gen->type),
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class ALL_PASS_CLASS = {
- MUS_ALL_PASS,
- (char *)S_all_pass,
- &free_delay,
- &describe_all_pass,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_all_pass,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &delay_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_all_pass(mus_float_t backward, mus_float_t forward, int size, mus_float_t *line, int line_size, mus_interp_t type)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, line_size, type);
- if (gen)
- {
- gen->core = &ALL_PASS_CLASS;
- gen->xscl = forward;
- gen->yscl = backward;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* ---------------- all_pass-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*apf)(mus_any *ptr, mus_float_t input);
- } allp_bank;
-
-
- static void free_all_pass_bank(mus_any *ptr)
- {
- allp_bank *f = (allp_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *allp_bank_copy(mus_any *ptr)
- {
- allp_bank *g, *p;
- int i;
-
- p = (allp_bank *)ptr;
- g = (allp_bank *)malloc(sizeof(allp_bank));
- memcpy((void *)g, (void *)ptr, sizeof(allp_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_all_pass_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_all_pass_bank(ptr, input));
- }
-
-
- static mus_long_t all_pass_bank_length(mus_any *ptr)
- {
- return(((allp_bank *)ptr)->size);
- }
-
-
- static void all_pass_bank_reset(mus_any *ptr)
- {
- allp_bank *f = (allp_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool all_pass_bank_equalp(mus_any *p1, mus_any *p2)
- {
- allp_bank *f1 = (allp_bank *)p1;
- allp_bank *f2 = (allp_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!delay_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- return(true);
- }
-
-
- static char *describe_all_pass_bank(mus_any *ptr)
- {
- allp_bank *gen = (allp_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class ALL_PASS_BANK_CLASS = {
- MUS_ALL_PASS_BANK,
- (char *)S_all_pass_bank,
- &free_all_pass_bank,
- &describe_all_pass_bank,
- &all_pass_bank_equalp,
- 0, 0,
- &all_pass_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_all_pass_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &all_pass_bank_reset,
- 0, &allp_bank_copy
- };
-
-
- static mus_float_t all_pass_bank_3(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *c = (allp_bank *)all_passes;
- mus_any **gs;
- gs = c->gens;
- return(mus_all_pass_unmodulated_noz(gs[2], mus_all_pass_unmodulated_noz(gs[1], mus_all_pass_unmodulated_noz(gs[0], inval))));
- }
-
- static mus_float_t all_pass_bank_4(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *c = (allp_bank *)all_passes;
- mus_any **gs;
- gs = c->gens;
- return(mus_all_pass_unmodulated_noz(gs[3], mus_all_pass_unmodulated_noz(gs[2], mus_all_pass_unmodulated_noz(gs[1], mus_all_pass_unmodulated_noz(gs[0], inval)))));
- }
-
- static mus_float_t all_pass_bank_any(mus_any *all_passs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = inval;
- allp_bank *c = (allp_bank *)all_passs;
- for (i = 0; i < c->size; i++)
- sum = mus_all_pass_unmodulated_noz(c->gens[i], sum);
- return(sum);
- }
-
-
- mus_any *mus_make_all_pass_bank(int size, mus_any **all_passs)
- {
- allp_bank *gen;
- int i;
-
- gen = (allp_bank *)malloc(sizeof(allp_bank));
- gen->core = &ALL_PASS_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- gen->gens[i] = all_passs[i];
-
- if (size == 3)
- gen->apf = all_pass_bank_3;
- else
- {
- if (size == 4)
- gen->apf = all_pass_bank_4;
- else gen->apf = all_pass_bank_any;
- }
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_all_pass_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ALL_PASS_BANK));
- }
-
-
- mus_float_t mus_all_pass_bank(mus_any *all_passes, mus_float_t inval)
- {
- allp_bank *gen = (allp_bank *)all_passes;
- return((gen->apf)(all_passes, inval));
- }
-
-
-
-
- /* ---------------- moving-average ---------------- */
-
- bool mus_is_moving_average(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_AVERAGE));
- }
-
-
- mus_float_t mus_moving_average(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output;
- output = mus_delay_unmodulated_noz(ptr, input);
- gen->xscl += (input - output);
- return(gen->xscl * gen->yscl); /* xscl=sum, yscl=1/n */
- }
-
-
- static mus_float_t run_mus_moving_average(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_average(ptr, input));}
-
-
- static void moving_average_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- }
-
-
- static char *describe_moving_average(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl * gen->yscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_AVERAGE_CLASS = {
- MUS_MOVING_AVERAGE,
- (char *)S_moving_average,
- &free_delay,
- &describe_moving_average,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_average,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_average_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_average(int size, mus_float_t *line)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- int i;
- gen->core = &MOVING_AVERAGE_CLASS;
- gen->xscl = 0.0;
- for (i = 0; i < size; i++)
- gen->xscl += gen->line[i];
- gen->yscl = 1.0 / (mus_float_t)size;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
- mus_any *mus_make_moving_average_with_initial_sum(int size, mus_float_t *line, mus_float_t sum)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- gen->core = &MOVING_AVERAGE_CLASS;
- gen->xscl = sum;
- gen->yscl = 1.0 / (mus_float_t)size;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* -------- moving-max -------- */
-
- bool mus_is_moving_max(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_MAX));
- }
-
-
- mus_float_t mus_moving_max(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output, abs_input;
-
- abs_input = fabs(input);
- output = mus_delay_unmodulated_noz(ptr, abs_input);
- if (abs_input >= gen->xscl)
- gen->xscl = abs_input;
- else
- {
- if (output >= gen->xscl)
- {
- unsigned int i;
- for (i = 0; i < gen->size; i++)
- if (gen->line[i] > abs_input)
- abs_input = gen->line[i];
- gen->xscl = abs_input;
- }
- }
- return(gen->xscl);
- }
-
- static mus_float_t run_mus_moving_max(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_max(ptr, input));}
-
-
- static void moving_max_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- }
-
-
- static char *describe_moving_max(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_MAX_CLASS = {
- MUS_MOVING_MAX,
- (char *)S_moving_max,
- &free_delay,
- &describe_moving_max,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_max,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_max_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_max(int size, mus_float_t *line)
- {
- dly *gen;
- gen = (dly *)mus_make_delay(size, line, size, MUS_INTERP_NONE);
- if (gen)
- {
- int i;
- gen->core = &MOVING_MAX_CLASS;
- gen->xscl = 0.0;
- for (i = 0; i < size; i++)
- if (fabs(gen->line[i]) > gen->xscl)
- gen->xscl = fabs(gen->line[i]);
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- /* -------- moving-norm -------- */
-
- bool mus_is_moving_norm(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVING_NORM));
- }
-
-
- mus_float_t mus_moving_norm(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t output, abs_input;
-
- abs_input = fabs(input);
- if (abs_input < 0.01) abs_input = 0.01; /* 0.01 sets the max norm output (~100) -- maybe a parameter to make-norm? */
- output = mus_moving_max(ptr, abs_input);
- gen->y1 = output + (gen->yscl * gen->y1);
-
- return(gen->norm / gen->y1);
- }
-
-
- static mus_float_t run_mus_moving_norm(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_moving_norm(ptr, input));}
-
-
- static void moving_norm_reset(mus_any *ptr)
- {
- dly *gen = (dly *)ptr;
- delay_reset(ptr);
- gen->xscl = 0.0;
- gen->y1 = 0.0;
- }
-
-
- static char *describe_moving_norm(mus_any *ptr)
- {
- char *str = NULL;
- dly *gen = (dly *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s, max %.3f, y1 %.3f, weight %.3f, line[%u]:%s",
- mus_name(ptr),
- gen->xscl, gen->y1, gen->yscl,
- gen->size,
- str = float_array_to_string(gen->line, gen->size, gen->loc));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static mus_any_class MOVING_NORM_CLASS = {
- MUS_MOVING_NORM,
- (char *)S_moving_norm,
- &free_delay,
- &describe_moving_norm,
- &delay_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &run_mus_moving_norm,
- MUS_DELAY_LINE,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &moving_norm_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_moving_norm(int size, mus_float_t *line, mus_float_t norm)
- {
- dly *gen;
- gen = (dly *)mus_make_moving_max(size, line);
- if (gen)
- {
- gen->core = &MOVING_NORM_CLASS;
-
- gen->yscl = (mus_float_t)size / (size + 1.0); /* one-pole -b1 = -feedback so this is a lowpass filter */
- gen->norm = norm * (size + 1.0);
- gen->yn1 = 1.0 / size;
- gen->y1 = size + 1.0;
-
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
-
-
-
- /* ---------------------------------------- filtered-comb ---------------------------------------- */
-
- static void filtered_comb_reset(mus_any *ptr)
- {
- dly *fc = (dly *)ptr;
- delay_reset(ptr);
- mus_reset(fc->filt);
- }
-
-
- static bool filtered_comb_equalp(mus_any *p1, mus_any *p2)
- {
- return((delay_equalp(p1, p2)) &&
- (mus_equalp(((dly *)p1)->filt,
- ((dly *)p2)->filt)));
- }
-
-
- static char *describe_filtered_comb(mus_any *ptr)
- {
- char *comb_str, *filter_str, *res;
- int len;
- comb_str = describe_comb(ptr);
- filter_str = mus_describe(((dly *)ptr)->filt);
- len = strlen(comb_str) + strlen(filter_str) + 64;
- res = (char *)malloc(len * sizeof(char));
- snprintf(res, len, "%s, filter: [%s]", comb_str, filter_str);
- if (comb_str) free(comb_str);
- if (filter_str) free(filter_str);
- return(res);
- }
-
-
- bool mus_is_filtered_comb(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILTERED_COMB));
- }
-
-
- mus_float_t mus_filtered_comb(mus_any *ptr, mus_float_t input, mus_float_t pm)
- {
- dly *fc = (dly *)ptr;
- if (fc->zdly)
- return(mus_delay(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt,
- mus_tap(ptr, pm),
- 0.0)),
- pm));
- return(mus_delay_unmodulated(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt, fc->line[fc->loc], 0.0))));
- }
-
-
- mus_float_t mus_filtered_comb_unmodulated(mus_any *ptr, mus_float_t input)
- {
- dly *fc = (dly *)ptr;
- return(mus_delay_unmodulated(ptr,
- input + (fc->yscl *
- fc->runf(fc->filt, fc->line[fc->loc], 0.0))));
- }
-
-
- static mus_any_class FILTERED_COMB_CLASS = {
- MUS_FILTERED_COMB,
- (char *)S_filtered_comb,
- &free_delay,
- &describe_filtered_comb,
- &filtered_comb_equalp,
- &delay_data,
- &delay_set_data,
- &delay_length,
- &delay_set_length,
- 0, 0, 0, 0, /* freq phase */
- &delay_scaler,
- &delay_set_scaler,
- &delay_fb,
- &delay_set_fb,
- &mus_filtered_comb,
- MUS_DELAY_LINE,
- NULL,
- &delay_interp_type,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &delay_loc,
- 0, 0,
- 0, 0, 0, 0,
- &filtered_comb_reset,
- 0, &dly_copy
- };
-
-
- mus_any *mus_make_filtered_comb(mus_float_t scaler, int size, mus_float_t *line, int line_size, mus_interp_t type, mus_any *filt)
- {
- dly *fc;
- fc = (dly *)mus_make_comb(scaler, size, line, line_size, type);
- if (fc)
- {
- fc->core = &FILTERED_COMB_CLASS;
- if (filt)
- fc->filt = filt;
- else
- {
- fc->filt = mus_make_one_zero(1.0, 0.0);
- fc->filt_allocated = true;
- }
- fc->runf = mus_run_function(fc->filt);
- return((mus_any *)fc);
- }
- else return(NULL);
- }
-
-
- /* ---------------- filtered-comb-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_any **gens;
- mus_float_t (*cmbf)(mus_any *ptr, mus_float_t input);
- } fltcmb_bank;
-
-
- static void free_filtered_comb_bank(mus_any *ptr)
- {
- fltcmb_bank *f = (fltcmb_bank *)ptr;
- if (f->gens) {free(f->gens); f->gens = NULL;}
- free(ptr);
- }
-
-
- static mus_any *fltcmb_bank_copy(mus_any *ptr)
- {
- fltcmb_bank *g, *p;
- int i;
-
- p = (fltcmb_bank *)ptr;
- g = (fltcmb_bank *)malloc(sizeof(fltcmb_bank));
- memcpy((void *)g, (void *)ptr, sizeof(fltcmb_bank));
- g->gens = (mus_any **)malloc(p->size * sizeof(mus_any *));
- for (i = 0; i < p->size; i++)
- g->gens[i] = mus_copy(p->gens[i]);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_filtered_comb_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_filtered_comb_bank(ptr, input));
- }
-
-
- static mus_long_t filtered_comb_bank_length(mus_any *ptr)
- {
- return(((fltcmb_bank *)ptr)->size);
- }
-
-
- static void filtered_comb_bank_reset(mus_any *ptr)
- {
- fltcmb_bank *f = (fltcmb_bank *)ptr;
- int i;
- for (i = 0; i < f->size; i++)
- mus_reset(f->gens[i]);
- }
-
-
- static bool filtered_comb_bank_equalp(mus_any *p1, mus_any *p2)
- {
- fltcmb_bank *f1 = (fltcmb_bank *)p1;
- fltcmb_bank *f2 = (fltcmb_bank *)p2;
- int i, size;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- size = f1->size;
-
- for (i = 0; i < size; i++)
- if (!filtered_comb_equalp(f1->gens[i], f2->gens[i]))
- return(false);
-
- return(true);
- }
-
-
- static char *describe_filtered_comb_bank(mus_any *ptr)
- {
- fltcmb_bank *gen = (fltcmb_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d",
- mus_name(ptr),
- gen->size);
- return(describe_buffer);
- }
-
- static mus_any_class FILTERED_COMB_BANK_CLASS = {
- MUS_FILTERED_COMB_BANK,
- (char *)S_filtered_comb_bank,
- &free_filtered_comb_bank,
- &describe_filtered_comb_bank,
- &filtered_comb_bank_equalp,
- 0, 0,
- &filtered_comb_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_filtered_comb_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &filtered_comb_bank_reset,
- 0, &fltcmb_bank_copy
- };
-
-
- static mus_float_t filtered_comb_one_zero(mus_any *ptr, mus_float_t input)
- {
- dly *gen = (dly *)ptr;
- mus_float_t result;
- result = gen->line[gen->loc];
- gen->line[gen->loc] = input + mus_one_zero(gen->filt, result); /* gen->yscl folded into one_zero coeffs via smp_scl */
- gen->loc++;
- if (gen->loc >= gen->size)
- gen->loc = 0;
- return(result);
- }
-
-
- static mus_float_t filtered_comb_bank_8(mus_any *combs, mus_float_t inval)
- {
- fltcmb_bank *c = (fltcmb_bank *)combs;
- mus_any **gs;
- gs = c->gens;
- return(filtered_comb_one_zero(gs[0], inval) +
- filtered_comb_one_zero(gs[1], inval) +
- filtered_comb_one_zero(gs[2], inval) +
- filtered_comb_one_zero(gs[3], inval) +
- filtered_comb_one_zero(gs[4], inval) +
- filtered_comb_one_zero(gs[5], inval) +
- filtered_comb_one_zero(gs[6], inval) +
- filtered_comb_one_zero(gs[7], inval));
- }
-
- static mus_float_t filtered_comb_bank_any(mus_any *filtered_combs, mus_float_t inval)
- {
- int i;
- mus_float_t sum = 0.0;
- fltcmb_bank *c = (fltcmb_bank *)filtered_combs;
- for (i = 0; i < c->size; i++)
- sum += mus_filtered_comb_unmodulated(c->gens[i], inval);
- return(sum);
- }
-
- static void smp_scl(mus_any *ptr, mus_float_t scl);
-
- mus_any *mus_make_filtered_comb_bank(int size, mus_any **filtered_combs)
- {
- fltcmb_bank *gen;
- int i;
- bool zdly = false, oz = true;
-
- gen = (fltcmb_bank *)malloc(sizeof(fltcmb_bank));
- gen->core = &FILTERED_COMB_BANK_CLASS;
- gen->size = size;
-
- gen->gens = (mus_any **)malloc(size * sizeof(mus_any *));
- for (i = 0; i < size; i++)
- {
- gen->gens[i] = filtered_combs[i];
- zdly = (zdly) || (((dly *)(filtered_combs[i]))->zdly);
- oz = (oz) && (mus_is_one_zero(((dly *)(filtered_combs[i]))->filt));
- }
-
- if ((size == 8) &&
- (oz) &&
- (!zdly))
- {
- gen->cmbf = filtered_comb_bank_8;
- for (i = 0; i < 8; i++)
- {
- dly *d;
- d = (dly *)gen->gens[i];
- smp_scl(d->filt, d->yscl);
- }
- }
- else gen->cmbf = filtered_comb_bank_any;
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_filtered_comb_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILTERED_COMB_BANK));
- }
-
-
- mus_float_t mus_filtered_comb_bank(mus_any *filtered_combs, mus_float_t inval)
- {
- fltcmb_bank *gen = (fltcmb_bank *)filtered_combs;
- return((gen->cmbf)(filtered_combs, inval));
- }
-
-
- mus_any *mus_bank_generator(mus_any *g, int i)
- {
- if (mus_is_comb_bank(g))
- return(((cmb_bank *)g)->gens[i]);
- if (mus_is_all_pass_bank(g))
- return(((allp_bank *)g)->gens[i]);
- if (mus_is_filtered_comb_bank(g))
- return(((fltcmb_bank *)g)->gens[i]);
- return(NULL);
- }
-
-
-
-
- /* ---------------- sawtooth et al ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t current_value;
- mus_float_t freq, phase, base, width;
- } sw;
-
-
- static void free_sw(mus_any *ptr) {free(ptr);}
-
- static mus_any *sw_copy(mus_any *ptr)
- {
- sw *g;
- g = (sw *)malloc(sizeof(sw));
- memcpy((void *)g, (void *)ptr, sizeof(sw));
- return((mus_any *)g);
- }
-
-
- mus_float_t mus_sawtooth_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- gen->current_value = gen->base * (gen->phase - M_PI);
- return(result);
- }
-
-
- static mus_float_t run_sawtooth_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_sawtooth_wave(ptr, fm));}
-
- bool mus_is_sawtooth_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SAWTOOTH_WAVE));
- }
-
-
- static mus_float_t sw_freq(mus_any *ptr) {return(mus_radians_to_hz(((sw *)ptr)->freq));}
- static mus_float_t sw_set_freq(mus_any *ptr, mus_float_t val) {((sw *)ptr)->freq = mus_hz_to_radians(val); return(val);}
-
- static mus_float_t sw_increment(mus_any *ptr) {return(((sw *)ptr)->freq);}
- static mus_float_t sw_set_increment(mus_any *ptr, mus_float_t val) {((sw *)ptr)->freq = val; return(val);}
-
- static mus_float_t sw_phase(mus_any *ptr) {return(fmod(((sw *)ptr)->phase, TWO_PI));}
- static mus_float_t sw_set_phase(mus_any *ptr, mus_float_t val) {((sw *)ptr)->phase = val; return(val);}
-
- static mus_float_t sw_width(mus_any *ptr) {return((((sw *)ptr)->width) / ( 2 * M_PI));}
- static mus_float_t sw_set_width(mus_any *ptr, mus_float_t val) {((sw *)ptr)->width = (2 * M_PI * val); return(val);}
-
- static mus_float_t sawtooth_scaler(mus_any *ptr) {return(((sw *)ptr)->base * M_PI);}
- static mus_float_t sawtooth_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val / M_PI; return(val);}
-
-
- static bool sw_equalp(mus_any *p1, mus_any *p2)
- {
- sw *s1, *s2;
- s1 = (sw *)p1;
- s2 = (sw *)p2;
- return((p1 == p2) ||
- ((s1) && (s2) &&
- (s1->core->type == s2->core->type) &&
- (s1->freq == s2->freq) &&
- (s1->phase == s2->phase) &&
- (s1->base == s2->base) &&
- (s1->current_value == s2->current_value)));
- }
-
-
- static char *describe_sw(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr));
- return(describe_buffer);
- }
-
-
- static void sawtooth_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = M_PI;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class SAWTOOTH_WAVE_CLASS = {
- MUS_SAWTOOTH_WAVE,
- (char *)S_sawtooth_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &sawtooth_scaler,
- &sawtooth_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_sawtooth_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &sawtooth_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_sawtooth_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase) /* M_PI as initial phase, normally */
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &SAWTOOTH_WAVE_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = (amp / M_PI);
- gen->phase = phase;
- gen->current_value = gen->base * (gen->phase - M_PI);
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_square_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- if (gen->phase < gen->width)
- gen->current_value = gen->base;
- else gen->current_value = 0.0;
- return(result);
- }
-
-
- bool mus_is_square_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SQUARE_WAVE));
- }
-
-
- static mus_float_t run_square_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_square_wave(ptr, fm));}
-
- static mus_float_t square_wave_scaler(mus_any *ptr) {return(((sw *)ptr)->base);}
- static mus_float_t square_wave_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val; return(val);}
-
-
- static void square_wave_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = 0.0;
- gen->current_value = gen->base;
- }
-
-
- static mus_any_class SQUARE_WAVE_CLASS = {
- MUS_SQUARE_WAVE,
- (char *)S_square_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &square_wave_scaler,
- &square_wave_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_square_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0,
- &sw_width, &sw_set_width,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &square_wave_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_square_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase)
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &SQUARE_WAVE_CLASS;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = amp;
- gen->phase = phase;
- gen->width = M_PI;
- if (gen->phase < gen->width)
- gen->current_value = gen->base;
- else gen->current_value = 0.0;
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_triangle_wave(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
-
- result = gen->current_value;
- gen->phase += (gen->freq + fm);
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- }
- if (gen->phase < (M_PI / 2.0))
- gen->current_value = gen->base * gen->phase;
- else
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else gen->current_value = gen->base * (gen->phase - TWO_PI);
- return(result);
- }
-
-
- mus_float_t mus_triangle_wave_unmodulated(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- mus_float_t result;
-
- result = gen->current_value;
- gen->phase += gen->freq;
- TRY_AGAIN:
- if (gen->phase < (M_PI / 2.0))
- gen->current_value = gen->base * gen->phase;
- else
- {
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else
- {
- if (gen->phase < TWO_PI)
- gen->current_value = gen->base * (gen->phase - TWO_PI);
- else
- {
- gen->phase -= TWO_PI;
- goto TRY_AGAIN;
- }
- }
- }
- return(result);
- }
-
-
- bool mus_is_triangle_wave(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TRIANGLE_WAVE));
- }
-
-
- static mus_float_t run_triangle_wave(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_triangle_wave(ptr, fm));}
-
- static mus_float_t triangle_wave_scaler(mus_any *ptr) {return(((sw *)ptr)->base * M_PI_2);}
- static mus_float_t triangle_wave_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = (val * 2.0 / M_PI); return(val);}
-
-
- static void triangle_wave_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = 0.0;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class TRIANGLE_WAVE_CLASS = {
- MUS_TRIANGLE_WAVE,
- (char *)S_triangle_wave,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &triangle_wave_scaler,
- &triangle_wave_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_triangle_wave,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &triangle_wave_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_triangle_wave(mus_float_t freq, mus_float_t amp, mus_float_t phase)
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &TRIANGLE_WAVE_CLASS;
- if (freq < 0.0)
- {
- freq = -freq;
- phase += M_PI;
- if (phase > TWO_PI) phase -= TWO_PI;
- }
- gen->freq = mus_hz_to_radians(freq);
- gen->base = (2.0 * amp / M_PI);
- gen->phase = phase;
- if (gen->phase < M_PI_2)
- gen->current_value = gen->base * gen->phase;
- else
- if (gen->phase < (M_PI * 1.5))
- gen->current_value = gen->base * (M_PI - gen->phase);
- else gen->current_value = gen->base * (gen->phase - TWO_PI);
- return((mus_any *)gen);
- }
-
-
- mus_float_t mus_pulse_train(mus_any *ptr, mus_float_t fm)
- {
- sw *gen = (sw *)ptr;
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->current_value = gen->base;
- }
- else gen->current_value = 0.0;
- gen->phase += (gen->freq + fm);
- return(gen->current_value);
- }
-
-
- mus_float_t mus_pulse_train_unmodulated(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- /* here unfortunately, we might get any phase: (pulse-train p (+ (pulse-train p) -1.0))
- */
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->current_value = gen->base;
- }
- else gen->current_value = 0.0;
- gen->phase += gen->freq;
- return(gen->current_value);
- }
-
-
- bool mus_is_pulse_train(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PULSE_TRAIN));
- }
-
-
- static mus_float_t run_pulse_train(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_pulse_train(ptr, fm));}
-
- static mus_float_t pulse_train_scaler(mus_any *ptr) {return(((sw *)ptr)->base);}
- static mus_float_t pulse_train_set_scaler(mus_any *ptr, mus_float_t val) {((sw *)ptr)->base = val; return(val);}
-
-
- static void pulse_train_reset(mus_any *ptr)
- {
- sw *gen = (sw *)ptr;
- gen->phase = TWO_PI;
- gen->current_value = 0.0;
- }
-
-
- static mus_any_class PULSE_TRAIN_CLASS = {
- MUS_PULSE_TRAIN,
- (char *)S_pulse_train,
- &free_sw,
- &describe_sw,
- &sw_equalp,
- 0, 0, 0, 0,
- &sw_freq,
- &sw_set_freq,
- &sw_phase,
- &sw_set_phase,
- &pulse_train_scaler,
- &pulse_train_set_scaler,
- &sw_increment,
- &sw_set_increment,
- &run_pulse_train,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pulse_train_reset,
- 0, &sw_copy
- };
-
-
- mus_any *mus_make_pulse_train(mus_float_t freq, mus_float_t amp, mus_float_t phase) /* TWO_PI initial phase, normally */
- {
- sw *gen;
- gen = (sw *)malloc(sizeof(sw));
- gen->core = &PULSE_TRAIN_CLASS;
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = amp;
- gen->phase = phase;
- gen->current_value = 0.0;
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- rand, rand_interp ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t freq, phase, base, incr, norm;
- mus_float_t output;
- mus_float_t *distribution;
- int distribution_size;
- mus_float_t (*ran_unmod)(mus_any *ptr);
- } noi;
-
-
- /* rand taken from the ANSI C standard (essentially the same as the Cmix form used earlier) */
-
- static unsigned long randx = 1;
- #define INVERSE_MAX_RAND 0.0000610351563
- #define INVERSE_MAX_RAND2 0.000030517579
-
-
- void mus_set_rand_seed(unsigned long val) {randx = val;}
-
- unsigned long mus_rand_seed(void) {return(randx);}
-
-
- static mus_float_t next_random(void)
- {
- randx = randx * 1103515245 + 12345;
- return((mus_float_t)((unsigned int)(randx >> 16) & 32767));
- }
-
-
- mus_float_t mus_random(mus_float_t amp) /* -amp to amp as mus_float_t */
- {
- return(amp * (next_random() * INVERSE_MAX_RAND - 1.0));
- }
-
-
- mus_float_t mus_frandom(mus_float_t amp) /* 0.0 to amp as mus_float_t */
- {
- return(amp * next_random() * INVERSE_MAX_RAND2);
- }
-
-
- int mus_irandom(int amp)
- {
- return((int)(amp * next_random() * INVERSE_MAX_RAND2));
- }
-
-
- static mus_float_t random_any(noi *gen) /* -amp to amp possibly through distribution */
- {
- if (gen->distribution)
- return(gen->base * mus_array_interp(gen->distribution,
- next_random() * INVERSE_MAX_RAND2 * gen->distribution_size,
- gen->distribution_size));
- return(gen->base * (next_random() * INVERSE_MAX_RAND - 1.0));
- }
-
-
- mus_float_t mus_rand(mus_any *ptr, mus_float_t fm)
- {
- noi *gen = (noi *)ptr;
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->output = random_any(gen);
- }
- gen->phase += (gen->freq + fm);
- return(gen->output);
- }
-
-
- static mus_float_t zero_unmodulated(mus_any *ptr) {return(0.0);}
-
- mus_float_t mus_rand_unmodulated(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- gen->output = random_any(gen);
- }
- gen->phase += gen->freq;
- return(gen->output);
- }
-
-
- mus_float_t mus_rand_interp(mus_any *ptr, mus_float_t fm)
- {
- /* fm can change the increment step during a ramp */
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- if (gen->output > gen->base)
- gen->output = gen->base;
- else
- {
- if (gen->output < -gen->base)
- gen->output = -gen->base;
- }
- if ((gen->phase >= TWO_PI) || (gen->phase < 0.0))
- {
- gen->phase = fmod(gen->phase, TWO_PI);
- if (gen->phase < 0.0) gen->phase += TWO_PI;
- gen->incr = (random_any(gen) - gen->output) / (ceil(TWO_PI / (gen->freq + fm)));
- }
- gen->phase += (gen->freq + fm);
- return(gen->output);
- }
-
-
- mus_float_t mus_rand_interp_unmodulated(mus_any *ptr)
- {
- return(((noi *)ptr)->ran_unmod(ptr));
- }
-
-
- mus_float_t (*mus_rand_interp_unmodulated_function(mus_any *g))(mus_any *gen);
- mus_float_t (*mus_rand_interp_unmodulated_function(mus_any *g))(mus_any *gen)
- {
- if (mus_is_rand_interp(g))
- return(((noi *)g)->ran_unmod);
- return(NULL);
- }
-
- static mus_float_t rand_interp_unmodulated_with_distribution(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- gen->incr = (random_any(gen) - gen->output) / (ceil(TWO_PI / gen->freq));
- }
- gen->phase += gen->freq;
- return(gen->output);
- }
-
-
- static mus_float_t rand_interp_unmodulated(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->output += gen->incr;
- gen->phase += gen->freq;
- if (gen->phase >= TWO_PI)
- {
- gen->phase -= TWO_PI;
- randx = randx * 1103515245 + 12345;
- gen->incr = ((gen->base * ((mus_float_t)((unsigned int)(randx >> 16) & 32767) * INVERSE_MAX_RAND - 1.0)) - gen->output) * gen->norm;
- }
- return(gen->output);
- }
-
-
- static mus_float_t run_rand(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rand(ptr, fm));}
- static mus_float_t run_rand_interp(mus_any *ptr, mus_float_t fm, mus_float_t unused) {return(mus_rand_interp(ptr, fm));}
-
-
- bool mus_is_rand(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RAND));
- }
-
- bool mus_is_rand_interp(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_RAND_INTERP));
- }
-
-
- static void free_noi(mus_any *ptr) {free(ptr);}
-
- static mus_any *noi_copy(mus_any *ptr)
- {
- noi *g;
- g = (noi *)malloc(sizeof(noi));
- memcpy((void *)g, (void *)ptr, sizeof(noi));
- /* if ptr->distribution, it comes from elsewhere -- we don't touch it here,
- * and in clm2xen, we merely wrap it.
- */
- return((mus_any *)g);
- }
-
- static mus_float_t noi_freq(mus_any *ptr) {return(mus_radians_to_hz(((noi *)ptr)->freq));}
- static mus_float_t noi_set_freq(mus_any *ptr, mus_float_t val)
- {
- if (val < 0.0) val = -val;
- ((noi *)ptr)->freq = mus_hz_to_radians(val);
- return(val);
- }
-
- static mus_float_t interp_noi_set_freq(mus_any *ptr, mus_float_t val)
- {
- noi *gen = (noi *)ptr;
- if (val < 0.0) val = -val;
- gen->freq = mus_hz_to_radians(val);
- if (gen->freq != 0.0)
- gen->norm = 1.0 / (ceil(TWO_PI / gen->freq));
- return(val);
- }
-
- static mus_float_t noi_increment(mus_any *ptr) {return(((noi *)ptr)->freq);}
- static mus_float_t noi_set_increment(mus_any *ptr, mus_float_t val) {((noi *)ptr)->freq = val; return(val);}
-
- static mus_float_t noi_incr(mus_any *ptr) {return(((noi *)ptr)->incr);}
- static mus_float_t noi_set_incr(mus_any *ptr, mus_float_t val) {((noi *)ptr)->incr = val; return(val);}
-
- static mus_float_t noi_phase(mus_any *ptr) {return(fmod(((noi *)ptr)->phase, TWO_PI));}
- static mus_float_t noi_set_phase(mus_any *ptr, mus_float_t val) {((noi *)ptr)->phase = val; return(val);}
-
- static mus_float_t noi_scaler(mus_any *ptr) {return(((noi *)ptr)->base);}
- static mus_float_t noi_set_scaler(mus_any *ptr, mus_float_t val) {((noi *)ptr)->base = val; return(val);} /* rand, not rand-interp */
-
- static mus_float_t *noi_data(mus_any *ptr) {return(((noi *)ptr)->distribution);}
- static mus_long_t noi_length(mus_any *ptr) {return(((noi *)ptr)->distribution_size);}
-
-
- static mus_float_t randi_set_scaler(mus_any *ptr, mus_float_t val)
- {
- noi *gen = (noi *)ptr;
- if (val == 0.0)
- gen->ran_unmod = zero_unmodulated;
- else
- {
- if (gen->base == 0.0)
- {
- if (gen->distribution)
- gen->ran_unmod = rand_interp_unmodulated_with_distribution;
- else gen->ran_unmod = rand_interp_unmodulated;
- }
- }
- gen->base = val;
- return(val);
- }
-
- static void noi_reset(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- gen->phase = 0.0;
- gen->output = 0.0;
- }
-
-
- static bool noi_equalp(mus_any *p1, mus_any *p2)
- {
- noi *g1 = (noi *)p1;
- noi *g2 = (noi *)p2;
- return((p1 == p2) ||
- ((g1) && (g2) &&
- (g1->core->type == g2->core->type) &&
- (g1->freq == g2->freq) &&
- (g1->phase == g2->phase) &&
- (g1->output == g2->output) &&
- (g1->incr == g2->incr) &&
- (g1->base == g2->base) &&
- (g1->distribution_size == g2->distribution_size) &&
- (g1->distribution == g2->distribution)));
- }
-
-
- static char *describe_noi(mus_any *ptr)
- {
- noi *gen = (noi *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- if (mus_is_rand(ptr))
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f%s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr),
- (gen->distribution) ? ", with distribution envelope" : "");
- else
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s freq: %.3fHz, phase: %.3f, amp: %.3f, incr: %.3f, curval: %.3f%s",
- mus_name(ptr),
- mus_frequency(ptr),
- mus_phase(ptr),
- mus_scaler(ptr),
- gen->incr,
- gen->output,
- (gen->distribution) ? ", with distribution envelope" : "");
- return(describe_buffer);
- }
-
-
- static mus_any_class RAND_CLASS = {
- MUS_RAND,
- (char *)S_rand,
- &free_noi,
- &describe_noi,
- &noi_equalp,
- &noi_data, 0,
- &noi_length, 0,
- &noi_freq,
- &noi_set_freq,
- &noi_phase,
- &noi_set_phase,
- &noi_scaler,
- &noi_set_scaler,
- &noi_increment, /* this is the phase increment, not the incr field */
- &noi_set_increment,
- &run_rand,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &noi_incr, &noi_set_incr,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &noi_reset,
- 0, &noi_copy
- };
-
-
- static mus_any_class RAND_INTERP_CLASS = {
- MUS_RAND_INTERP,
- (char *)S_rand_interp,
- &free_noi,
- &describe_noi,
- &noi_equalp,
- &noi_data, 0,
- &noi_length, 0,
- &noi_freq,
- &interp_noi_set_freq,
- &noi_phase,
- &noi_set_phase,
- &noi_scaler,
- &randi_set_scaler,
- &noi_increment, /* phase increment, not incr field */
- &noi_set_increment,
- &run_rand_interp,
- MUS_NOT_SPECIAL,
- NULL, 0,
- &noi_incr, &noi_set_incr, /* incr field == mus_offset method */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &noi_reset,
- 0, &noi_copy
- };
-
-
- mus_any *mus_make_rand(mus_float_t freq, mus_float_t base)
- {
- noi *gen;
- gen = (noi *)calloc(1, sizeof(noi));
- gen->core = &RAND_CLASS;
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = base;
- gen->incr = 0.0;
- gen->output = random_any(gen); /* this was always starting at 0.0 (changed 23-Dec-06) */
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_with_distribution(mus_float_t freq, mus_float_t base, mus_float_t *distribution, int distribution_size)
- {
- noi *gen;
- gen = (noi *)mus_make_rand(freq, base);
- gen->distribution = distribution;
- gen->distribution_size = distribution_size;
- gen->output = random_any(gen);
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_interp(mus_float_t freq, mus_float_t base)
- {
- noi *gen;
- gen = (noi *)calloc(1, sizeof(noi));
- gen->core = &RAND_INTERP_CLASS;
- /* gen->distribution = NULL; */
- if (freq < 0.0) freq = -freq;
- gen->freq = mus_hz_to_radians(freq);
- gen->base = base;
- gen->incr = mus_random(base) * freq / sampling_rate;
- gen->output = 0.0;
- if (gen->freq != 0.0)
- gen->norm = 1.0 / (ceil(TWO_PI / gen->freq));
- else gen->norm = 1.0;
- gen->ran_unmod = ((base == 0.0) ? zero_unmodulated : rand_interp_unmodulated);
- return((mus_any *)gen);
- }
-
-
- mus_any *mus_make_rand_interp_with_distribution(mus_float_t freq, mus_float_t base, mus_float_t *distribution, int distribution_size)
- {
- noi *gen;
- gen = (noi *)mus_make_rand_interp(freq, base);
- gen->distribution = distribution;
- gen->distribution_size = distribution_size;
- gen->ran_unmod = ((base == 0.0) ? zero_unmodulated : rand_interp_unmodulated_with_distribution);
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- simple filters ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t xs[3];
- mus_float_t ys[3];
- mus_float_t x1, x2, y1, y2;
- } smpflt;
-
-
- static void free_smpflt(mus_any *ptr) {free(ptr);}
-
- static mus_any *smpflt_copy(mus_any *ptr)
- {
- smpflt *g;
- g = (smpflt *)malloc(sizeof(smpflt));
- memcpy((void *)g, (void *)ptr, sizeof(smpflt));
- return((mus_any *)g);
- }
-
-
- static bool smpflt_equalp(mus_any *p1, mus_any *p2)
- {
- smpflt *g1 = (smpflt *)p1;
- smpflt *g2 = (smpflt *)p2;
- return((p1 == p2) ||
- ((g1->core->type == g2->core->type) &&
- (g1->xs[0] == g2->xs[0]) &&
- (g1->xs[1] == g2->xs[1]) &&
- (g1->xs[2] == g2->xs[2]) &&
- (g1->ys[1] == g2->ys[1]) &&
- (g1->ys[2] == g2->ys[2]) &&
- (g1->x1 == g2->x1) &&
- (g1->x2 == g2->x2) &&
- (g1->y1 == g2->y1) &&
- (g1->y2 == g2->y2)));
- }
-
-
- static char *describe_smpflt(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- switch (gen->core->type)
- {
- case MUS_ONE_ZERO:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, a1: %.3f, x1: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->xs[1], gen->x1);
- break;
-
- case MUS_ONE_POLE:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, b1: %.3f, y1: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->ys[1], gen->y1);
- break;
-
- case MUS_TWO_ZERO:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, a1: %.3f, a2: %.3f, x1: %.3f, x2: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->xs[1], gen->xs[2], gen->x1, gen->x2);
- break;
-
- case MUS_TWO_POLE:
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s a0: %.3f, b1: %.3f, b2: %.3f, y1: %.3f, y2: %.3f",
- mus_name(ptr),
- gen->xs[0], gen->ys[1], gen->ys[2], gen->y1, gen->y2);
- break;
- }
- return(describe_buffer);
- }
-
-
- mus_float_t mus_one_zero(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) + (gen->xs[1] * gen->x1);
- gen->x1 = input;
- return(result);
- }
-
-
- static mus_float_t run_one_zero(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_one_zero(ptr, input));}
-
- static mus_long_t one_length(mus_any *ptr) {return(1);}
- static mus_long_t two_length(mus_any *ptr) {return(2);}
-
- static mus_float_t smp_xcoeff(mus_any *ptr, int index) {return(((smpflt *)ptr)->xs[index]);}
- static mus_float_t smp_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {((smpflt *)ptr)->xs[index] = val; return(val);}
-
- static mus_float_t smp_ycoeff(mus_any *ptr, int index) {return(((smpflt *)ptr)->ys[index]);}
- static mus_float_t smp_set_ycoeff(mus_any *ptr, int index, mus_float_t val) {((smpflt *)ptr)->ys[index] = val; return(val);}
-
- static mus_float_t *smp_xcoeffs(mus_any *ptr) {return(((smpflt *)ptr)->xs);}
- static mus_float_t *smp_ycoeffs(mus_any *ptr) {return(((smpflt *)ptr)->ys);}
-
- static void smp_scl(mus_any *ptr, mus_float_t scl) {smpflt *g = (smpflt *)ptr; g->xs[0] *= scl; g->xs[1] *= scl;}
-
- static void smpflt_reset(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->x1 = 0.0;
- gen->x2 = 0.0;
- gen->y1 = 0.0;
- gen->y2 = 0.0;
- }
-
-
- static mus_any_class ONE_ZERO_CLASS = {
- MUS_ONE_ZERO,
- (char *)S_one_zero,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &one_length, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_one_zero,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0,
- 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_one_zero(mus_float_t a0, mus_float_t a1)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &ONE_ZERO_CLASS;
- gen->xs[0] = a0;
- gen->xs[1] = a1;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_zero(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_ZERO));
- }
-
-
- mus_float_t mus_one_pole(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->y1 = (gen->xs[0] * input) - (gen->ys[1] * gen->y1);
- return(gen->y1);
- }
-
- /* incrementer: (make-one-pole 1.0 -1.0) */
-
- static mus_float_t run_one_pole(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_one_pole(ptr, input));}
-
-
- static mus_any_class ONE_POLE_CLASS = {
- MUS_ONE_POLE,
- (char *)S_one_pole,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &one_length, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- &run_one_pole,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &smp_ycoeff, &smp_set_ycoeff,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_one_pole(mus_float_t a0, mus_float_t b1)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &ONE_POLE_CLASS;
- gen->xs[0] = a0;
- gen->ys[1] = b1;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_pole(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_POLE));
- }
-
-
- mus_float_t mus_two_zero(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) + (gen->xs[1] * gen->x1) + (gen->xs[2] * gen->x2);
- gen->x2 = gen->x1;
- gen->x1 = input;
- return(result);
- }
-
-
- static mus_float_t run_two_zero(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_two_zero(ptr, input));}
-
-
- static mus_float_t two_zero_radius(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(sqrt(gen->xs[2]));
- }
-
-
- static mus_float_t two_zero_set_radius(mus_any *ptr, mus_float_t new_radius)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->xs[1] = -2.0 * new_radius * cos(mus_hz_to_radians(mus_frequency(ptr)));
- gen->xs[2] = new_radius * new_radius;
- return(new_radius);
- }
-
-
- static mus_float_t two_zero_frequency(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(mus_radians_to_hz(acos(gen->xs[1] / (-2.0 * two_zero_radius(ptr)))));
- }
-
-
- static mus_float_t two_zero_set_frequency(mus_any *ptr, mus_float_t new_freq)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->xs[1] = -2.0 * mus_scaler(ptr) * cos(mus_hz_to_radians(new_freq));
- return(new_freq);
- }
-
-
- static mus_any_class TWO_ZERO_CLASS = {
- MUS_TWO_ZERO,
- (char *)S_two_zero,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &two_length, 0,
- &two_zero_frequency, &two_zero_set_frequency,
- 0, 0,
- &two_zero_radius, &two_zero_set_radius,
- 0, 0,
- &run_two_zero,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_two_zero(mus_float_t a0, mus_float_t a1, mus_float_t a2)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &TWO_ZERO_CLASS;
- gen->xs[0] = a0;
- gen->xs[1] = a1;
- gen->xs[2] = a2;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_two_zero(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TWO_ZERO));
- }
-
-
- mus_any *mus_make_two_zero_from_frequency_and_radius(mus_float_t frequency, mus_float_t radius)
- {
- return(mus_make_two_zero(1.0, -2.0 * radius * cos(mus_hz_to_radians(frequency)), radius * radius));
- }
-
-
- mus_float_t mus_two_pole(mus_any *ptr, mus_float_t input)
- {
- smpflt *gen = (smpflt *)ptr;
- mus_float_t result;
- result = (gen->xs[0] * input) - (gen->ys[1] * gen->y1) - (gen->ys[2] * gen->y2);
- gen->y2 = gen->y1;
- gen->y1 = result;
- return(result);
- }
-
-
- static mus_float_t run_two_pole(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_two_pole(ptr, input));}
-
-
- static mus_float_t two_pole_radius(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(sqrt(gen->ys[2]));
- }
-
-
- static mus_float_t two_pole_set_radius(mus_any *ptr, mus_float_t new_radius)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->ys[1] = -2.0 * new_radius * cos(mus_hz_to_radians(mus_frequency(ptr)));
- gen->ys[2] = new_radius * new_radius;
- return(new_radius);
- }
-
-
- static mus_float_t two_pole_frequency(mus_any *ptr)
- {
- smpflt *gen = (smpflt *)ptr;
- return(mus_radians_to_hz(acos(gen->ys[1] / (-2.0 * two_pole_radius(ptr)))));
- }
-
-
- static mus_float_t two_pole_set_frequency(mus_any *ptr, mus_float_t new_freq)
- {
- smpflt *gen = (smpflt *)ptr;
- gen->ys[1] = -2.0 * mus_scaler(ptr) * cos(mus_hz_to_radians(new_freq));
- return(new_freq);
- }
-
-
- static mus_any_class TWO_POLE_CLASS = {
- MUS_TWO_POLE,
- (char *)S_two_pole,
- &free_smpflt,
- &describe_smpflt,
- &smpflt_equalp,
- 0, 0,
- &two_length, 0,
- &two_pole_frequency, &two_pole_set_frequency,
- 0, 0,
- &two_pole_radius, &two_pole_set_radius,
- 0, 0,
- &run_two_pole,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &smp_xcoeff, &smp_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &smp_ycoeff, &smp_set_ycoeff,
- &smp_xcoeffs, &smp_ycoeffs,
- &smpflt_reset,
- 0, &smpflt_copy
- };
-
-
- mus_any *mus_make_two_pole(mus_float_t a0, mus_float_t b1, mus_float_t b2)
- {
- smpflt *gen;
- gen = (smpflt *)calloc(1, sizeof(smpflt));
- gen->core = &TWO_POLE_CLASS;
- gen->xs[0] = a0;
- gen->ys[1] = b1;
- gen->ys[2] = b2;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_two_pole(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_TWO_POLE));
- }
-
-
- mus_any *mus_make_two_pole_from_frequency_and_radius(mus_float_t frequency, mus_float_t radius)
- {
- return(mus_make_two_pole(1.0, -2.0 * radius * cos(mus_hz_to_radians(frequency)), radius * radius));
- }
-
-
-
- /* ---------------- formant ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t frequency, radius;
- mus_float_t x1, x2, y1, y2;
- mus_float_t rr, gain, fdbk;
- } frm;
-
-
- static void free_frm(mus_any *ptr) {free(ptr);}
-
-
- static mus_any *frm_copy(mus_any *ptr)
- {
- frm *g;
- g = (frm *)malloc(sizeof(frm));
- memcpy((void *)g, (void *)ptr, sizeof(frm));
- return((mus_any *)g);
- }
-
-
- bool mus_is_formant(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FORMANT));
- }
-
-
- static void frm_reset(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- gen->x1 = 0.0;
- gen->x2 = 0.0;
- gen->y1 = 0.0;
- gen->y2 = 0.0;
- }
-
-
- static bool frm_equalp(mus_any *p1, mus_any *p2)
- {
- frm *g1 = (frm *)p1;
- frm *g2 = (frm *)p2;
- return((p1 == p2) ||
- ((g1->core->type == g2->core->type) &&
- (g1->radius == g2->radius) &&
- (g1->frequency == g2->frequency) &&
- (g1->x1 == g2->x1) &&
- (g1->x2 == g2->x2) &&
- (g1->y1 == g2->y1) &&
- (g1->y2 == g2->y2)));
- }
-
-
- static char *describe_formant(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, radius: %.3f",
- mus_name(ptr),
- mus_radians_to_hz(gen->frequency),
- gen->radius);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_formant(mus_any *ptr, mus_float_t input)
- {
- frm *gen = (frm *)ptr;
- mus_float_t x0, y0;
- x0 = gen->gain * input;
- y0 = x0 - gen->x2 + (gen->fdbk * gen->y1) - (gen->rr * gen->y2);
- gen->y2 = gen->y1;
- gen->y1 = y0;
- gen->x2 = gen->x1;
- gen->x1 = x0;
- return(y0);
- }
-
-
- static mus_float_t run_formant(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_formant(ptr, input));}
-
-
- static void mus_set_formant_radius_and_frequency_in_radians(mus_any *ptr, mus_float_t radius, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- gen->radius = radius;
- gen->frequency = freq_in_radians;
- gen->rr = radius * radius;
- gen->gain = (1.0 - gen->rr) * 0.5;
- gen->fdbk = 2.0 * radius * cos(freq_in_radians);
- }
-
-
- void mus_set_formant_radius_and_frequency(mus_any *ptr, mus_float_t radius, mus_float_t freq_in_hz)
- {
- mus_set_formant_radius_and_frequency_in_radians(ptr, radius, mus_hz_to_radians(freq_in_hz));
- }
-
-
- static mus_float_t formant_frequency(mus_any *ptr) {return(mus_radians_to_hz(((frm *)ptr)->frequency));}
-
- mus_float_t mus_set_formant_frequency(mus_any *ptr, mus_float_t freq_in_hz)
- {
- frm *gen = (frm *)ptr;
- mus_float_t fw;
- fw = mus_hz_to_radians(freq_in_hz);
- gen->frequency = fw;
- gen->fdbk = 2.0 * gen->radius * cos(fw);
- return(freq_in_hz);
- }
-
-
- mus_float_t mus_formant_with_frequency(mus_any *ptr, mus_float_t input, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- if (gen->frequency != freq_in_radians)
- {
- gen->frequency = freq_in_radians;
- gen->fdbk = 2.0 * gen->radius * cos(freq_in_radians);
- }
- return(mus_formant(ptr, input));
- }
-
-
- static mus_float_t formant_radius(mus_any *ptr) {return(((frm *)ptr)->radius);}
-
- static mus_float_t formant_set_radius(mus_any *ptr, mus_float_t val)
- {
- mus_set_formant_radius_and_frequency_in_radians(ptr, val, ((frm *)ptr)->frequency);
- return(val);
- }
-
-
- static mus_any_class FORMANT_CLASS = {
- MUS_FORMANT,
- (char *)S_formant,
- &free_frm,
- &describe_formant,
- &frm_equalp,
- 0, 0,
- &two_length, 0,
- &formant_frequency, &mus_set_formant_frequency,
- 0, 0,
- &formant_radius, &formant_set_radius,
- 0, 0,
- &run_formant,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &frm_reset,
- 0, &frm_copy
- };
-
-
- mus_any *mus_make_formant(mus_float_t frequency, mus_float_t radius)
- {
- frm *gen;
- gen = (frm *)calloc(1, sizeof(frm));
- gen->core = &FORMANT_CLASS;
- mus_set_formant_radius_and_frequency((mus_any *)gen, radius, frequency);
- return((mus_any *)gen);
- }
-
-
- /* ---------------- formant-bank ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size, mctr;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
- mus_float_t c1, c2;
- mus_float_t (*one_input)(mus_any *fbank, mus_float_t inval);
- mus_float_t (*many_inputs)(mus_any *fbank, mus_float_t *inval);
- } frm_bank;
-
-
- static void free_formant_bank(mus_any *ptr)
- {
- frm_bank *f = (frm_bank *)ptr;
- if (f->x0) {free(f->x0); f->x0 = NULL;}
- if (f->x1) {free(f->x1); f->x1 = NULL;}
- if (f->x2) {free(f->x2); f->x2 = NULL;}
- if (f->y0) {free(f->y0); f->y0 = NULL;}
- if (f->y1) {free(f->y1); f->y1 = NULL;}
- if (f->y2) {free(f->y2); f->y2 = NULL;}
- if (f->rr) {free(f->rr); f->rr = NULL;}
- if (f->fdbk) {free(f->fdbk); f->fdbk = NULL;}
- if (f->gain) {free(f->gain); f->gain = NULL;}
- free(ptr);
- }
-
- static mus_any *frm_bank_copy(mus_any *ptr)
- {
- frm_bank *g, *p;
- int bytes;
-
- p = (frm_bank *)ptr;
- g = (frm_bank *)malloc(sizeof(frm_bank));
- memcpy((void *)g, (void *)ptr, sizeof(frm_bank));
- bytes = g->size * sizeof(mus_float_t);
-
- g->x0 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x0), (void *)(p->x0), bytes);
- g->x1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x1), (void *)(p->x1), bytes);
- g->x2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x2), (void *)(p->x2), bytes);
- g->y0 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y0), (void *)(p->y0), bytes);
- g->y1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y1), (void *)(p->y1), bytes);
- g->y2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y2), (void *)(p->y2), bytes);
-
- g->rr = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rr), (void *)(p->rr), bytes);
- g->fdbk = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->fdbk), (void *)(p->fdbk), bytes);
- g->gain = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->gain), (void *)(p->gain), bytes);
-
- return((mus_any *)g);
- }
-
- static mus_float_t run_formant_bank(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_formant_bank(ptr, input));
- }
-
-
- static mus_long_t formant_bank_length(mus_any *ptr)
- {
- return(((frm_bank *)ptr)->size);
- }
-
-
- static void formant_bank_reset(mus_any *ptr)
- {
- frm_bank *f = (frm_bank *)ptr;
- int size;
- size = f->size * sizeof(mus_float_t);
- memset((void *)(f->x0), 0, size);
- memset((void *)(f->x1), 0, size);
- memset((void *)(f->x2), 0, size);
- memset((void *)(f->y0), 0, size);
- memset((void *)(f->y1), 0, size);
- memset((void *)(f->y2), 0, size);
- }
-
-
- static bool formant_bank_equalp(mus_any *p1, mus_any *p2)
- {
- frm_bank *f1 = (frm_bank *)p1;
- frm_bank *f2 = (frm_bank *)p2;
- #if 0
- int i, size;
- #endif
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- #if 0
- size = f1->size;
- for (i = 0; i < size; i++)
- if (!frm_equalp(f1->gens[i], f2->gens[i]))
- return(false);
- #endif
- /* now check the locals... */
- return(true);
- }
-
-
- static char *describe_formant_bank(mus_any *ptr)
- {
- frm_bank *gen = (frm_bank *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d", mus_name(ptr), gen->size);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_formant_bank(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- return(bank->one_input(fbank, inval));
- }
-
- mus_float_t mus_formant_bank_with_inputs(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- return(bank->many_inputs(fbank, inval));
- }
-
-
- static mus_float_t fb_one_with_amps(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_one_without_amps(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval;
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_with_amps(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
- amps = bank->amps;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_without_amps(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i;
- mus_float_t sum = 0.0;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *rr, *fdbk, *gain;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- rr = bank->rr;
- fdbk = bank->fdbk;
- gain = bank->gain;
-
- for (i = 0; i < bank->size; i++)
- {
- x0[i] = gain[i] * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr[i] * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_one_with_amps_c1_c2(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- bank->mctr++;
-
- rr = bank->c1;
- gain = (bank->c2 * inval);
- x0[0] = gain;
-
- if (bank->mctr < 3)
- {
- i = 0;
- while (i <= size4)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- /* in isolation this looks like the x0[i]-x2[i] business could be handled outside the loop
- * by a single float, but formant-bank can be called in the same do-loop both with and
- * without multiple inputs, so fb_one has to be completely compatible sample-by-sample
- * with fb_many. Since we can't predict here when we'll need bank->x2, we can't collapse
- * this calculation.
- *
- * If we know we've had 2 fb_one calls just before this one, then x2[i] are all the same,
- * x0[i] will all be the same in this loop, so x0[i] - x2[i] can be collapsed, but
- * we still need to set x0[0]=gain: enter mctr.
- *
- * So in the current case, we can save x0[0]=gain -> x1 -> x2, then in fm_many
- * mctr=1 -- x2 is ok, x1[0] needs to be propagated
- * mctr>1 -- x2 and x1 need propagation
- * On the other side, if mctr>=3, then x2[i] was not set, so don't access it.
- */
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
- }
- else
- {
- mus_float_t g2;
- g2 = gain - x2[0];
- i = 0;
- while (i <= size4)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
- static mus_float_t fb_many_with_amps_c1_c2(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *amps, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- amps = bank->amps;
- size4 = bank->size - 4;
-
- if (bank->mctr > 0)
- {
- if (bank->mctr == 1)
- {
- for (i = 1; i < bank->size; i++) x1[i] = x1[0];
- }
- else
- {
- for (i = 1; i < bank->size; i++) {x1[i] = x1[0]; x2[i] = x2[0];}
- }
- bank->mctr = 0;
- }
- rr = bank->c1;
- gain = bank->c2;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += amps[i] * y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_float_t fb_one_without_amps_c1_c2(mus_any *fbank, mus_float_t inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- size4 = bank->size - 4;
-
- bank->mctr++;
-
- rr = bank->c1;
- gain = (bank->c2 * inval);
- x0[0] = gain;
-
- if (bank->mctr < 3)
- {
- i = 0;
- while (i <= size4)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = gain - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
- }
- else
- {
- mus_float_t g2;
- g2 = gain - x2[0];
- i = 0;
- while (i <= size4)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- y0[i] = g2 + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_float_t fb_many_without_amps_c1_c2(mus_any *fbank, mus_float_t *inval)
- {
- frm_bank *bank = (frm_bank *)fbank;
- int i, size4;
- mus_float_t sum = 0.0, rr, gain;
- mus_float_t *x0, *x1, *x2, *y0, *y1, *y2, *fdbk;
-
- x0 = bank->x0;
- x1 = bank->x1;
- x2 = bank->x2;
- y0 = bank->y0;
- y1 = bank->y1;
- y2 = bank->y2;
- fdbk = bank->fdbk;
- size4 = bank->size - 4;
-
- if (bank->mctr > 0)
- {
- if (bank->mctr == 1)
- {
- for (i = 1; i < bank->size; i++) x1[i] = x1[0];
- }
- else
- {
- for (i = 1; i < bank->size; i++) {x1[i] = x1[0]; x2[i] = x2[0];}
- }
- bank->mctr = 0;
- }
-
- rr = bank->c1;
- gain = bank->c2;
-
- i = 0;
- while (i <= size4)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
-
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- i++;
- }
- for (; i < bank->size; i++)
- {
- x0[i] = gain * inval[i];
- y0[i] = x0[i] - x2[i] + (fdbk[i] * y1[i]) - (rr * y2[i]);
- sum += y0[i];
- }
-
- bank->x2 = x1;
- bank->x1 = x0;
- bank->x0 = x2;
-
- bank->y2 = y1;
- bank->y1 = y0;
- bank->y0 = y2;
-
- return(sum);
- }
-
-
- static mus_any_class FORMANT_BANK_CLASS = {
- MUS_FORMANT_BANK,
- (char *)S_formant_bank,
- &free_formant_bank,
- &describe_formant_bank,
- &formant_bank_equalp,
- 0, 0,
- &formant_bank_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_formant_bank,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &formant_bank_reset,
- 0, &frm_bank_copy
- };
-
-
- mus_any *mus_make_formant_bank(int size, mus_any **formants, mus_float_t *amps)
- {
- frm_bank *gen;
- int i;
-
- gen = (frm_bank *)malloc(sizeof(frm_bank));
- gen->core = &FORMANT_BANK_CLASS;
- gen->size = size;
- gen->mctr = 0;
-
- gen->x0 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->x1 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->x2 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y0 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y1 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y2 = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->amps = amps;
-
- gen->rr = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- gen->fdbk = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- gen->gain = (mus_float_t *)malloc(size * sizeof(mus_float_t));
-
- if (amps)
- {
- gen->one_input = fb_one_with_amps;
- gen->many_inputs = fb_many_with_amps;
- }
- else
- {
- gen->one_input = fb_one_without_amps;
- gen->many_inputs = fb_many_without_amps;
- }
-
- for (i = 0; i < size; i++)
- {
- frm *g;
- g = (frm *)formants[i];
- gen->rr[i] = g->rr;
- gen->fdbk[i] = g->fdbk;
- gen->gain[i] = g->gain;
- /* one case: 1.0 val 0.0 throughout
- * also c1 x c2
- */
- }
- gen->c1 = gen->rr[0];
- gen->c2 = gen->gain[0];
- for (i = 1; i < size; i++)
- if ((gen->rr[i] != gen->c1) ||
- (gen->gain[i] != gen->c2))
- return((mus_any *)gen);
-
- if (amps)
- {
- gen->one_input = fb_one_with_amps_c1_c2;
- gen->many_inputs = fb_many_with_amps_c1_c2;
- }
- else
- {
- gen->one_input = fb_one_without_amps_c1_c2;
- gen->many_inputs = fb_many_without_amps_c1_c2;
- }
-
- return((mus_any *)gen);
- }
-
- bool mus_is_formant_bank(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FORMANT_BANK));
- }
-
-
-
- /* ---------------- firmant ---------------- */
-
- static char *describe_firmant(mus_any *ptr)
- {
- frm *gen = (frm *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s frequency: %.3f, radius: %.3f",
- mus_name(ptr),
- mus_radians_to_hz(gen->frequency),
- gen->radius);
- return(describe_buffer);
- }
-
- static mus_float_t firmant_frequency(mus_any *ptr) {return(mus_radians_to_hz(((frm *)ptr)->frequency));}
-
- static mus_float_t firmant_set_frequency(mus_any *ptr, mus_float_t freq_in_hz)
- {
- frm *gen = (frm *)ptr;
- mus_float_t fw;
- fw = mus_hz_to_radians(freq_in_hz);
- gen->frequency = fw;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- return(freq_in_hz);
- }
-
- static mus_float_t firmant_radius(mus_any *ptr) {return(((frm *)ptr)->radius);}
-
- static mus_float_t firmant_set_radius(mus_any *ptr, mus_float_t radius)
- {
- frm *gen = (frm *)ptr;
- gen->radius = radius;
- gen->gain = 1.0 - radius * radius;
- return(radius);
- }
-
-
- bool mus_is_firmant(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FIRMANT));
- }
-
-
- mus_float_t mus_firmant(mus_any *ptr, mus_float_t input)
- {
- frm *gen = (frm *)ptr;
- mus_float_t xn1, yn1;
- xn1 = gen->gain * input + gen->radius * (gen->x1 - gen->fdbk * gen->y1);
- yn1 = gen->radius * (gen->fdbk * xn1 + gen->y1);
- gen->x1 = xn1;
- gen->y1 = yn1;
- return(yn1);
- }
-
-
- mus_float_t mus_firmant_with_frequency(mus_any *ptr, mus_float_t input, mus_float_t freq_in_radians)
- {
- frm *gen = (frm *)ptr;
- gen->frequency = freq_in_radians;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- return(mus_firmant(ptr, input));
- }
-
-
- static mus_float_t run_firmant(mus_any *ptr, mus_float_t input, mus_float_t unused) {return(mus_firmant(ptr, input));}
-
-
- static mus_any_class FIRMANT_CLASS = {
- MUS_FIRMANT,
- (char *)S_firmant,
- &free_frm,
- &describe_firmant,
- &frm_equalp,
- 0, 0,
- &two_length, 0,
- &firmant_frequency, &firmant_set_frequency,
- 0, 0,
- &firmant_radius, &firmant_set_radius,
- 0, 0,
- &run_firmant,
- MUS_SIMPLE_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &frm_reset,
- 0, &frm_copy
- };
-
-
- mus_any *mus_make_firmant(mus_float_t frequency, mus_float_t radius)
- {
- frm *gen;
- gen = (frm *)calloc(1, sizeof(frm));
- gen->core = &FIRMANT_CLASS;
- gen->frequency = mus_hz_to_radians(frequency);
- gen->radius = radius;
- gen->fdbk = 2.0 * sin(gen->frequency * 0.5);
- gen->gain = 1.0 - radius * radius;
- return((mus_any *)gen);
- }
-
-
-
-
- /* ---------------- filter ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int order, allocated_size, loc;
- bool state_allocated;
- mus_float_t *x, *y, *state;
- mus_float_t (*filtw)(mus_any *ptr, mus_float_t fm);
- } flt;
-
-
- mus_float_t mus_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t filter_eight(mus_any *ptr, mus_float_t input)
- {
- /* oddly enough, this separated form is faster than the interleaved version below, or is valgrind confused?
- */
- flt *gen = (flt *)ptr;
- mus_float_t xout;
- mus_float_t *state, *ts, *ts1, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
- ts1 = (mus_float_t *)(state + gen->order);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- xout = (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- return(xout + ((*ts1) * (*x)));
-
- /*
- * flt *gen = (flt *)ptr;
- * mus_float_t xout;
- * mus_float_t *state, *ts, *y, *x;
- *
- * x = (mus_float_t *)(gen->x + 1);
- * y = (mus_float_t *)(gen->y + 1);
- * state = (mus_float_t *)(gen->state + gen->loc);
- * ts = (mus_float_t *)(state + gen->order - 1);
- *
- * gen->loc++;
- * if (gen->loc == gen->order)
- * gen->loc = 0;
- *
- * xout = (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x);
- * input -= ((*ts--) * (*y));
- *
- * state[0] = input;
- * state[gen->order] = input;
- * return(xout + ((*ts) * gen->x[0]));
- */
- }
-
-
- static mus_float_t filter_four(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout;
- mus_float_t *state, *ts, *ts1, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
- ts1 = (mus_float_t *)(state + gen->order);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- xout = (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- xout += (*ts1--) * (*x++);
- return(xout + ((*ts1) * (*x)));
-
- /*
- * flt *gen = (flt *)ptr;
- * mus_float_t xout;
- * mus_float_t *state, *ts, *y, *x;
- *
- * x = (mus_float_t *)(gen->x + 1);
- * y = (mus_float_t *)(gen->y + 1);
- * state = (mus_float_t *)(gen->state + gen->loc);
- * ts = (mus_float_t *)(state + gen->order - 1);
- *
- * gen->loc++;
- * if (gen->loc == gen->order)
- * gen->loc = 0;
- *
- * xout = (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- * xout += (*ts) * (*x++);
- * input -= ((*ts--) * (*y++));
- *
- * state[0] = input;
- * state[gen->order] = input;
- * return(xout + ((*ts) * gen->x[0]));
- */
- }
-
-
- static mus_float_t filter_two(mus_any *ptr, mus_float_t input)
- {
- /* here the mus_float_t-delay form is not faster, but use it for consistency */
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *y, *x;
-
- x = gen->x;
- y = gen->y;
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 2);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- state[0] = input - ((ts[1] * y[1]) + (ts[0] * y[2]));
- state[gen->order] = state[0];
-
- return((ts[0] * x[2]) + (ts[1] * x[1]) + (ts[2] * x[0]));
- }
-
-
- static mus_float_t filter_lt_10(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout = 0.0;
- mus_float_t *state, *state1, *ts, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- state1 = (mus_float_t *)(state + 1);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts > state1)
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- ts = (mus_float_t *)(state + gen->order);
-
- while (ts > state1)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- static mus_float_t filter_ge_10(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t xout = 0.0;
- mus_float_t *state, *state1, *state11, *ts, *y, *x;
-
- x = (mus_float_t *)(gen->x);
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- state1 = (mus_float_t *)(state + 1);
- state11 = (mus_float_t *)(state + 11);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts >= state11)
- {
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- input -= ((*ts--) * (*y++));
- }
- while (ts > state1)
- input -= ((*ts--) * (*y++));
- input -= ((*ts) * (*y));
-
- state[0] = input;
- state[gen->order] = input;
-
- ts = (mus_float_t *)(state + gen->order);
- while (ts >= state11)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state1)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- mus_float_t mus_fir_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t fir_n(mus_any *ptr, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
-
- (*state) = input;
- (*ts) = input;
- state++;
- end = (mus_float_t *)(state + 4);
-
- while (ts > end)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- }
-
-
- static mus_float_t fir_ge_20(mus_any *ptr, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
- end = (mus_float_t *)(state + 20);
-
- (*state) = input;
- (*ts) = input;
- state++;
-
- while (ts >= end)
- {
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- xout += (*ts--) * (*x++);
- }
- while (ts > state)
- xout += (*ts--) * (*x++);
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return((ts == state) ? (xout + ((*ts) * (*x))) : xout);
- }
-
-
- mus_float_t mus_iir_filter(mus_any *ptr, mus_float_t input)
- {
- return((((flt *)ptr)->filtw)(ptr, input));
- }
-
-
- static mus_float_t iir_n(mus_any *ptr, mus_float_t input)
- {
- flt *gen = (flt *)ptr;
- mus_float_t *state, *ts, *y;
-
- y = (mus_float_t *)(gen->y + 1); /* assume y[0] = 1.0 I think */
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order - 1);
-
- while (ts > state)
- input -= ((*ts--) * (*y++));
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- state[0] = input;
- state[gen->order] = input;
-
- return(input);
- }
-
-
- static mus_float_t run_filter(mus_any *ptr, mus_float_t input, mus_float_t unused) {return((((flt *)ptr)->filtw)(ptr, input));}
-
- bool mus_is_filter(mus_any *ptr)
- {
- return((ptr) &&
- ((ptr->core->type == MUS_FILTER) ||
- (ptr->core->type == MUS_FIR_FILTER) ||
- (ptr->core->type == MUS_IIR_FILTER)));
- }
-
-
- bool mus_is_fir_filter(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FIR_FILTER));
- }
-
- bool mus_is_iir_filter(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_IIR_FILTER));
- }
-
-
- static mus_float_t *filter_data(mus_any *ptr) {return(((flt *)ptr)->state);}
- static mus_long_t filter_length(mus_any *ptr) {return(((flt *)ptr)->order);}
-
- static mus_float_t *filter_xcoeffs(mus_any *ptr) {return(((flt *)ptr)->x);}
- static mus_float_t *filter_ycoeffs(mus_any *ptr) {return(((flt *)ptr)->y);}
-
-
- mus_float_t *mus_filter_set_xcoeffs(mus_any *ptr, mus_float_t *new_data)
- {
- /* needed by Snd if filter order increased during play */
- flt *gen = (flt *)ptr;
- mus_float_t *old_data;
- old_data = gen->x;
- gen->x = new_data;
- return(old_data);
- }
-
-
- mus_float_t *mus_filter_set_ycoeffs(mus_any *ptr, mus_float_t *new_data)
- {
- flt *gen = (flt *)ptr;
- mus_float_t *old_data;
- old_data = gen->y;
- gen->y = new_data;
- return(old_data);
- }
-
-
- static mus_long_t filter_set_length(mus_any *ptr, mus_long_t val)
- {
- /* just resets order if order < allocated size */
- flt *gen = (flt *)ptr;
- if ((val > 0) && (val <= gen->allocated_size))
- gen->order = (int)val;
- return((mus_long_t)(gen->order));
- }
-
-
- static void set_filter_function(flt *gen);
-
- int mus_filter_set_order(mus_any *ptr, int order)
- {
- /* resets order and fixes state array if needed (coeffs arrays should be handled separately by set_x|ycoeffs above) */
- /* returns either old order or -1 if state array can't be reallocated */
- flt *gen = (flt *)ptr;
- int old_order;
- if ((order > gen->allocated_size) &&
- (!(gen->state_allocated)))
- return(-1);
- old_order = gen->order;
- gen->order = order;
- if (order > gen->allocated_size)
- {
- int i;
- gen->allocated_size = order;
- gen->state = (mus_float_t *)realloc(gen->state, order * 2 * sizeof(mus_float_t));
- for (i = old_order; i < order; i++)
- {
- gen->state[i] = 0.0; /* try to minimize click */
- gen->state[i + order] = 0.0; /* just a guess */
- }
- }
- set_filter_function(gen);
- return(old_order);
- }
-
-
- static mus_float_t filter_xcoeff(mus_any *ptr, int index)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->x)) return((mus_float_t)mus_error(MUS_NO_XCOEFFS, S_mus_xcoeff ": no xcoeffs"));
- if ((index >= 0) && (index < gen->order))
- return(gen->x[index]);
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_mus_xcoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_set_xcoeff(mus_any *ptr, int index, mus_float_t val)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->x)) return((mus_float_t)mus_error(MUS_NO_XCOEFFS, S_set S_mus_xcoeff ": no xcoeffs"));
- if ((index >= 0) && (index < gen->order))
- {
- gen->x[index] = val;
- return(val);
- }
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_set S_mus_xcoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_ycoeff(mus_any *ptr, int index)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->y)) return((mus_float_t)mus_error(MUS_NO_YCOEFFS, S_mus_ycoeff ": no ycoeffs"));
- if ((index >= 0) && (index < gen->order))
- return(gen->y[index]);
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_mus_ycoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static mus_float_t filter_set_ycoeff(mus_any *ptr, int index, mus_float_t val)
- {
- flt *gen = (flt *)ptr;
- if (!(gen->y)) return((mus_float_t)mus_error(MUS_NO_YCOEFFS, S_set S_mus_ycoeff ": no ycoeffs"));
- if ((index >= 0) && (index < gen->order))
- {
- gen->y[index] = val;
- return(val);
- }
- return((mus_float_t)mus_error(MUS_ARG_OUT_OF_RANGE, S_set S_mus_ycoeff ": invalid index %d, order = %d?", index, gen->order));
- }
-
-
- static void free_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- if ((gen->state) && (gen->state_allocated)) free(gen->state);
- free(gen);
- }
-
- static mus_any *flt_copy(mus_any *ptr)
- {
- flt *g, *p;
- int bytes;
-
- p = (flt *)ptr;
- g = (flt *)malloc(sizeof(flt));
- memcpy((void *)g, (void *)ptr, sizeof(flt));
-
- /* we have to make a new state array -- otherwise the original and copy step on each other */
- bytes = p->order * 2 * sizeof(mus_float_t);
- g->state_allocated = true;
- g->state = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->state), (void *)(p->state), bytes);
- return((mus_any *)g);
- }
-
-
- static bool filter_equalp(mus_any *p1, mus_any *p2)
- {
- flt *f1, *f2;
- f1 = (flt *)p1;
- f2 = (flt *)p2;
- if (p1 == p2) return(true);
- return(((p1->core)->type == (p2->core)->type) &&
- ((mus_is_filter(p1)) || (mus_is_fir_filter(p1)) || (mus_is_iir_filter(p1))) &&
- (f1->order == f2->order) &&
- ((!(f1->x)) || (!(f2->x)) || (clm_arrays_are_equal(f1->x, f2->x, f1->order))) &&
- ((!(f1->y)) || (!(f2->y)) || (clm_arrays_are_equal(f1->y, f2->y, f1->order))) &&
- (clm_arrays_are_equal(f1->state, f2->state, f1->order)));
- }
-
-
- static char *describe_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *xstr = NULL, *ystr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- xstr = float_array_to_string(gen->x, gen->order, 0);
- ystr = float_array_to_string(gen->y, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, xs: %s, ys: %s",
- mus_name(ptr),
- gen->order,
- xstr, ystr);
- if (xstr) free(xstr);
- if (ystr) free(ystr);
- return(describe_buffer);
- }
-
-
- static char *describe_fir_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *xstr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- xstr = float_array_to_string(gen->x, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, xs: %s",
- mus_name(ptr),
- gen->order,
- xstr);
- if (xstr) free(xstr);
- return(describe_buffer);
- }
-
-
- static char *describe_iir_filter(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- char *ystr = NULL;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- ystr = float_array_to_string(gen->y, gen->order, 0);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s order: %d, ys: %s",
- mus_name(ptr),
- gen->order,
- ystr);
- if (ystr) free(ystr);
- return(describe_buffer);
- }
-
-
- static void filter_reset(mus_any *ptr)
- {
- flt *gen = (flt *)ptr;
- memset((void *)(gen->state), 0, gen->allocated_size * 2 * sizeof(mus_float_t));
- }
-
-
- static mus_any_class FILTER_CLASS = {
- MUS_FILTER,
- (char *)S_filter,
- &free_filter,
- &describe_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &filter_xcoeff, &filter_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &filter_ycoeff, &filter_set_ycoeff,
- &filter_xcoeffs, &filter_ycoeffs,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static mus_any_class FIR_FILTER_CLASS = {
- MUS_FIR_FILTER,
- (char *)S_fir_filter,
- &free_filter,
- &describe_fir_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- &filter_xcoeff, &filter_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &filter_xcoeffs, 0,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static mus_any_class IIR_FILTER_CLASS = {
- MUS_IIR_FILTER,
- (char *)S_iir_filter,
- &free_filter,
- &describe_iir_filter,
- &filter_equalp,
- &filter_data, 0,
- &filter_length,
- &filter_set_length,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_filter,
- MUS_FULL_FILTER,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- &filter_ycoeff, &filter_set_ycoeff,
- 0, &filter_ycoeffs,
- &filter_reset,
- 0, &flt_copy
- };
-
-
- static void set_filter_function(flt *gen)
- {
- /* choose the run-time function based on the current filter order and type */
- int order;
- order = gen->order - 1;
- if (gen->core == &FILTER_CLASS)
- {
- if (order == 2)
- gen->filtw = filter_two;
- else
- {
- if (order == 8)
- gen->filtw = filter_eight;
- else
- {
- if (order == 4)
- gen->filtw = filter_four;
- else
- {
- if (order >= 10)
- gen->filtw = filter_ge_10;
- else gen->filtw = filter_lt_10;
- }
- }
- }
- }
- else
- {
- if (gen->core == &FIR_FILTER_CLASS)
- {
- if (order >= 20)
- gen->filtw = fir_ge_20;
- else gen->filtw = fir_n;
- }
- else gen->filtw = iir_n;
- }
- }
-
-
- static mus_any *make_filter(mus_any_class *cls, const char *name, int order, mus_float_t *xcoeffs, mus_float_t *ycoeffs, mus_float_t *state)
- {
- /* if state is null, it is allocated locally, otherwise it's size should be at least 2 * order.
- */
- if (order <= 0)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_filter ": %s order = %d?", name, order);
- else
- {
- flt *gen;
- gen = (flt *)malloc(sizeof(flt));
- if (state)
- {
- gen->state = state;
- gen->state_allocated = false;
- }
- else
- {
- gen->state = (mus_float_t *)calloc(order * 2, sizeof(mus_float_t));
- gen->state_allocated = true;
- }
- gen->loc = 0;
-
- if (cls == &FILTER_CLASS)
- {
- if (!ycoeffs)
- cls = &FIR_FILTER_CLASS;
- else
- {
- if (!xcoeffs)
- cls = &IIR_FILTER_CLASS;
- }
- }
- gen->core = cls;
- gen->order = order;
- gen->allocated_size = order;
- gen->x = xcoeffs;
- gen->y = ycoeffs;
- gen->filtw = NULL;
- set_filter_function(gen);
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_filter(int order, mus_float_t *xcoeffs, mus_float_t *ycoeffs, mus_float_t *state)
- {
- return(make_filter(&FILTER_CLASS, S_make_filter, order, xcoeffs, ycoeffs, state));
- }
-
-
- mus_any *mus_make_fir_filter(int order, mus_float_t *xcoeffs, mus_float_t *state)
- {
- return(make_filter(&FIR_FILTER_CLASS, S_make_fir_filter, order, xcoeffs, NULL, state));
- }
-
-
- mus_any *mus_make_iir_filter(int order, mus_float_t *ycoeffs, mus_float_t *state)
- {
- return(make_filter(&IIR_FILTER_CLASS, S_make_iir_filter, order, NULL, ycoeffs, state));
- }
-
-
- mus_float_t *mus_make_fir_coeffs(int order, mus_float_t *envl, mus_float_t *aa)
- {
- /* envl = evenly sampled freq response, has order samples */
- int n, i, j, jj;
- mus_float_t scl;
- mus_float_t *a;
-
- n = order;
- if (n <= 0) return(aa);
- if (aa)
- a = aa;
- else a = (mus_float_t *)calloc(order + 1, sizeof(mus_float_t));
- if (!a) return(NULL);
- if (!(is_power_of_2(order)))
- {
- int m;
- mus_float_t am, q, xt0, x;
- m = (n + 1) / 2;
- am = 0.5 * (n + 1) - 1.0;
- scl = 2.0 / (mus_float_t)n;
- q = TWO_PI / (mus_float_t)n;
- xt0 = envl[0] * 0.5;
- for (j = 0, jj = n - 1; j < m; j++, jj--)
- {
- mus_float_t xt, qj;
- #if HAVE_SINCOS
- double s1, c1, s2, c2, qj1;
- xt = xt0;
- qj = q * (am - j);
- sincos(qj, &s1, &c1);
- qj1 = qj * 2.0;
- for (i = 1, x = qj; i < m; i += 2, x += qj1)
- {
- sincos(x, &s2, &c2);
- xt += (envl[i] * c2);
- if (i < (m - 1))
- xt += (envl[i + 1] * (c1 * c2 - s1 * s2));
- }
- #else
- xt = xt0;
- qj = q * (am - j);
- for (i = 1, x = qj; i < m; i++, x += qj)
- xt += (envl[i] * cos(x));
- #endif
- a[j] = xt * scl;
- a[jj] = a[j];
- }
- }
- else /* use fft if it's easy to match -- there must be a way to handle non-power-of-2 orders here
- * stretch envl to a power of 2, fft, subsample?
- */
- {
- mus_float_t *rl, *im;
- mus_long_t fsize;
- int lim;
- mus_float_t offset;
-
- fsize = 2 * order; /* checked power of 2 above */
- rl = (mus_float_t *)calloc(fsize, sizeof(mus_float_t));
- im = (mus_float_t *)calloc(fsize, sizeof(mus_float_t));
- lim = order / 2;
- memcpy((void *)rl, (void *)envl, lim * sizeof(mus_float_t));
-
- mus_fft(rl, im, fsize, 1);
-
- scl = 4.0 / fsize;
- offset = -2.0 * envl[0] / fsize;
- for (i = 0; i < fsize; i++)
- rl[i] = rl[i] * scl + offset;
- for (i = 1, j = lim - 1, jj = lim; i < order; i += 2, j--, jj++)
- {
- a[j] = rl[i];
- a[jj] = rl[i];
- }
- free(rl);
- free(im);
- }
-
- return(a);
- }
-
-
-
- /* ---------------- one-pole-all-pass ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int size;
- mus_float_t coeff;
- mus_float_t *x, *y;
- mus_float_t (*f)(mus_any *ptr, mus_float_t input);
- } onepall;
-
-
- static void free_onepall(mus_any *ptr)
- {
- onepall *f = (onepall *)ptr;
- if (f->x) {free(f->x); f->x = NULL;}
- if (f->y) {free(f->y); f->y = NULL;}
- free(ptr);
- }
-
- static mus_any *onepall_copy(mus_any *ptr)
- {
- onepall *g, *p;
- int bytes;
-
- p = (onepall *)ptr;
- g = (onepall *)malloc(sizeof(onepall));
- memcpy((void *)g, (void *)ptr, sizeof(onepall));
-
- bytes = g->size * sizeof(mus_float_t);
- g->x = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->x), (void *)(p->x), bytes);
- g->y = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->y), (void *)(p->y), bytes);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_onepall(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return((((onepall *)ptr)->f)(ptr, input));
- }
-
-
- static mus_long_t onepall_length(mus_any *ptr)
- {
- return(((onepall *)ptr)->size);
- }
-
-
- static void onepall_reset(mus_any *ptr)
- {
- onepall *f = (onepall *)ptr;
- int size;
- size = f->size;
- memset((void *)(f->x), 0, size * sizeof(mus_float_t));
- memset((void *)(f->y), 0, size * sizeof(mus_float_t));
- }
-
-
- static bool onepall_equalp(mus_any *p1, mus_any *p2)
- {
- onepall *f1 = (onepall *)p1;
- onepall *f2 = (onepall *)p2;
-
- if (f1 == f2) return(true);
- if (f1->size != f2->size) return(false);
- if (f1->coeff != f2->coeff) return(false);
-
- return((mus_arrays_are_equal(f1->x, f2->x, float_equal_fudge_factor, f1->size)) &&
- (mus_arrays_are_equal(f1->y, f2->y, float_equal_fudge_factor, f1->size)));
- }
-
-
- static char *describe_onepall(mus_any *ptr)
- {
- onepall *gen = (onepall *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %d, coeff: %f",
- mus_name(ptr),
- gen->size,
- gen->coeff);
- return(describe_buffer);
- }
-
-
- mus_float_t mus_one_pole_all_pass(mus_any *ptr, mus_float_t input)
- {
- return((((onepall *)ptr)->f)(ptr, input));
- }
-
- static mus_float_t one_pole_all_pass_n(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
- int i;
- mus_float_t coeff, y0;
- mus_float_t *x, *y;
-
- x = p->x;
- y = p->y;
- coeff = p->coeff;
-
- y0 = input;
- for (i = 0; i < p->size; i++)
- {
- y[i] = x[i] + (coeff * (y0 - y[i]));
- x[i] = y0;
- y0 = y[i];
- }
- return(y0);
- }
-
- static mus_float_t one_pole_all_pass_8(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
- mus_float_t coeff;
- mus_float_t *x, *y;
-
- x = p->x;
- y = p->y;
- coeff = p->coeff;
-
- y[0] = x[0] + (coeff * (input - y[0])); x[0] = input;
- y[1] = x[1] + (coeff * (y[0] - y[1])); x[1] = y[0];
- y[2] = x[2] + (coeff * (y[1] - y[2])); x[2] = y[1];
- y[3] = x[3] + (coeff * (y[2] - y[3])); x[3] = y[2];
- y[4] = x[4] + (coeff * (y[3] - y[4])); x[4] = y[3];
- y[5] = x[5] + (coeff * (y[4] - y[5])); x[5] = y[4];
- y[6] = x[6] + (coeff * (y[5] - y[6])); x[6] = y[5];
- y[7] = x[7] + (coeff * (y[6] - y[7])); x[7] = y[6];
-
- return(y[7]);
- }
-
- static mus_float_t one_pole_all_pass_1(mus_any *f, mus_float_t input)
- {
- onepall *p = (onepall *)f;
-
- p->y[0] = p->x[0] + (p->coeff * (input - p->y[0]));
- p->x[0] = input;
- return(p->y[0]);
- }
-
-
- static mus_any_class ONE_POLE_ALL_PASS_CLASS = {
- MUS_ONE_POLE_ALL_PASS,
- (char *)S_one_pole_all_pass,
- &free_onepall,
- &describe_onepall,
- &onepall_equalp,
- 0, 0,
- &onepall_length, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_onepall,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &onepall_reset,
- 0, &onepall_copy
- };
-
-
- mus_any *mus_make_one_pole_all_pass(int size, mus_float_t coeff)
- {
- onepall *gen;
-
- gen = (onepall *)malloc(sizeof(onepall));
- gen->core = &ONE_POLE_ALL_PASS_CLASS;
- gen->size = size;
-
- gen->x = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->y = (mus_float_t *)calloc(size, sizeof(mus_float_t));
- gen->coeff = coeff;
-
- if (size == 1)
- gen->f = one_pole_all_pass_1;
- else
- {
- if (size == 8)
- gen->f = one_pole_all_pass_8;
- else gen->f = one_pole_all_pass_n;
- }
-
- return((mus_any *)gen);
- }
-
-
- bool mus_is_one_pole_all_pass(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ONE_POLE_ALL_PASS));
- }
-
-
-
- /* ---------------- env ---------------- */
-
- typedef enum {MUS_ENV_LINEAR, MUS_ENV_EXPONENTIAL, MUS_ENV_STEP} mus_env_t;
-
- typedef struct {
- mus_any_class *core;
- mus_float_t rate, current_value, base, offset, scaler, power, init_y, init_power, original_scaler, original_offset;
- mus_long_t loc, end;
- mus_env_t style;
- int index, size;
- mus_float_t *original_data;
- mus_float_t *rates;
- mus_long_t *locs;
- mus_float_t (*env_func)(mus_any *g);
- void *next;
- void (*free_env)(mus_any *ptr);
- } seg;
-
- /* I used to use exp directly, but:
-
- (define (texp1 start end num)
- (let* ((ls (log start))
- (le (log end))
- (cf (exp (/ (- le ls) (1- num))))
- (max-diff 0.0)
- (xstart start))
- (do ((i 0 (+ i 1)))
- ((= i num)
- max-diff)
- (let ((val1 (* start (exp (* (/ i (1- num)) (- le ls)))))
- (val2 xstart))
- (set! xstart (* xstart cf))
- (set! max-diff (max max-diff (abs (- val1 val2))))))))
-
- returns:
-
- :(texp1 1.0 3.0 1000000)
- 2.65991229042584e-10
- :(texp1 1.0 10.0 100000000)
- 2.24604939091932e-8
- :(texp1 10.0 1000.0 100000000)
- 4.11786902532185e-6
- :(texp1 1.0 1.1 100000000)
- 1.28246036013024e-9
- :(texp1 10.0 1000.0 1000000000)
- 4.39423240550241e-5
-
- so the repeated multiply version is more than accurate enough
- */
-
-
- bool mus_is_env(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_ENV));
- }
-
-
- mus_float_t mus_env(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return((*(gen->env_func))(ptr));
- }
-
-
- mus_float_t (*mus_env_function(mus_any *g))(mus_any *gen)
- {
- if (mus_is_env(g))
- return(((seg *)g)->env_func);
- return(NULL);
- }
-
-
- static mus_float_t mus_env_step(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
- val = gen->current_value;
- if (gen->loc == 0)
- {
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- gen->current_value = gen->rate;
- }
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t mus_env_line(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return(gen->current_value);
- }
-
-
- static mus_float_t mus_env_linear(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
-
- val = gen->current_value;
- if (gen->loc == 0)
- {
- /* we can save about 10% total env time by checking here that we're on the last segment,
- * and setting gen->env_func to a version of mus_env_linear that does not watch gen->loc.
- * In any case, this code is strange -- change anything and it is 20% slower, sez callgrind.
- */
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- }
- gen->current_value += gen->rate;
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t mus_env_exponential(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- mus_float_t val;
- val = gen->current_value;
- if (gen->loc == 0)
- {
- gen->index++;
- gen->loc = gen->locs[gen->index] - gen->locs[gen->index - 1];
- gen->rate = gen->rates[gen->index];
- }
- gen->power *= gen->rate;
- gen->current_value = gen->offset + (gen->scaler * gen->power);
- gen->loc--;
- return(val);
- }
-
-
- static mus_float_t run_env(mus_any *ptr, mus_float_t unused1, mus_float_t unused2)
- {
- return(mus_env(ptr));
- }
-
-
- static void canonicalize_env(seg *e, const mus_float_t *data, int pts, mus_long_t dur, mus_float_t scaler)
- {
- int i, j, pts2;
- mus_float_t xscl, cur_loc, x1, y1, xdur;
- mus_long_t samps, pre_loc;
-
- /* pts > 1 if we get here, so the loop below is always exercised */
-
- pts2 = pts * 2;
- xdur = data[pts2 - 2] - data[0];
- if (xdur > 0.0)
- xscl = (mus_float_t)(dur - 1) / xdur;
- else xscl = 1.0;
- e->locs[pts - 2] = e->end;
-
- x1 = data[0];
- y1 = data[1];
- pre_loc = 0;
-
- for (j = 0, i = 2, cur_loc = 0.0; i < pts2; i += 2, j++)
- {
- mus_float_t cur_dx, x0, y0;
- x0 = x1;
- x1 = data[i];
- y0 = y1;
- y1 = data[i + 1];
-
- cur_dx = xscl * (x1 - x0);
- if (cur_dx < 1.0)
- cur_loc += 1.0;
- else cur_loc += cur_dx;
-
- switch (e->style)
- {
- case MUS_ENV_LINEAR:
- e->locs[j] = (mus_long_t)(cur_loc + 0.5);
- samps = e->locs[j] - pre_loc;
- pre_loc = e->locs[j];
-
- if (samps == 0)
- e->rates[j] = 0.0;
- else e->rates[j] = scaler * (y1 - y0) / (mus_float_t)samps;
- break;
-
- case MUS_ENV_EXPONENTIAL:
- e->locs[j] = (mus_long_t)(cur_loc + 0.5);
- samps = e->locs[j] - pre_loc;
- pre_loc = e->locs[j];
-
- if (samps == 0)
- e->rates[j] = 1.0;
- else e->rates[j] = exp((y1 - y0) / (mus_float_t)samps);
- break;
-
- case MUS_ENV_STEP:
- e->locs[j] = (mus_long_t)cur_loc; /* this is the change boundary (confusing...) */
- e->rates[j] = e->offset + (scaler * y0);
- break;
- }
- }
-
- e->locs[pts - 1] = 1000000000;
- e->locs[pts] = 1000000000; /* guard cell at end to make bounds check simpler */
- }
-
-
- static mus_float_t *fixup_exp_env(seg *e, const mus_float_t *data, int pts, mus_float_t offset, mus_float_t scaler, mus_float_t base)
- {
- mus_float_t min_y, max_y, val = 0.0, tmp = 0.0, b1;
- int len, i;
- bool flat;
- mus_float_t *result = NULL;
-
- if ((base <= 0.0) ||
- (base == 1.0))
- return(NULL);
-
- min_y = offset + scaler * data[1];
- max_y = min_y;
- len = pts * 2;
-
- /* fill "result" with x and (offset+scaler*y) */
-
- result = (mus_float_t *)malloc(len * sizeof(mus_float_t));
- result[0] = data[0];
- result[1] = min_y;
-
- for (i = 2; i < len; i += 2)
- {
- tmp = offset + scaler * data[i + 1];
- result[i] = data[i];
- result[i + 1] = tmp;
- if (tmp < min_y) min_y = tmp;
- if (tmp > max_y) max_y = tmp;
- }
-
- b1 = base - 1.0;
- flat = (min_y == max_y);
- if (!flat)
- val = 1.0 / (max_y - min_y);
-
- /* now logify result */
- for (i = 1; i < len; i += 2)
- {
- if (flat)
- tmp = 1.0;
- else tmp = val * (result[i] - min_y);
- result[i] = log(1.0 + (tmp * b1));
- }
-
- e->scaler = (max_y - min_y) / b1;
- e->offset = min_y;
- return(result);
- }
-
-
- static bool env_equalp(mus_any *p1, mus_any *p2)
- {
- seg *e1 = (seg *)p1;
- seg *e2 = (seg *)p2;
- if (p1 == p2) return(true);
- return((e1) && (e2) &&
- (e1->core->type == e2->core->type) &&
- (e1->loc == e2->loc) &&
- (e1->end == e2->end) &&
- (e1->style == e2->style) &&
- (e1->index == e2->index) &&
- (e1->size == e2->size) &&
-
- (e1->rate == e2->rate) &&
- (e1->base == e2->base) &&
- (e1->power == e2->power) &&
- (e1->current_value == e2->current_value) &&
- (e1->scaler == e2->scaler) &&
- (e1->offset == e2->offset) &&
- (e1->init_y == e2->init_y) &&
- (e1->init_power == e2->init_power) &&
- (clm_arrays_are_equal(e1->original_data, e2->original_data, e1->size * 2)));
- }
-
-
- static char *describe_env(mus_any *ptr)
- {
- char *str = NULL;
- seg *e = (seg *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s, pass: %lld (dur: %lld), index: %d, scaler: %.4f, offset: %.4f, data: %s",
- mus_name(ptr),
- ((e->style == MUS_ENV_LINEAR) ? "linear" : ((e->style == MUS_ENV_EXPONENTIAL) ? "exponential" : "step")),
- (e->locs) ? (e->locs[e->index] - e->loc) : -1,
- e->end + 1,
- e->index,
- e->original_scaler,
- e->original_offset,
- str = float_array_to_string(e->original_data, e->size * 2, 0));
- if (str) free(str);
- return(describe_buffer);
- }
-
-
- static seg *e2_free_list = NULL, *e3_free_list = NULL, *e4_free_list = NULL;
-
- static void free_env_gen(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- (*(ptr->free_env))(pt);
- }
-
- static void fe2(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e2_free_list;
- e2_free_list = ptr;
- }
-
- static void fe3(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e3_free_list;
- e3_free_list = ptr;
- }
-
- static void fe4(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- ptr->next = e4_free_list;
- e4_free_list = ptr;
- }
-
- static void ferest(mus_any *pt)
- {
- seg *ptr = (seg *)pt;
- if (ptr->locs) {free(ptr->locs); ptr->locs = NULL;}
- if (ptr->rates) {free(ptr->rates); ptr->rates = NULL;}
- free(ptr);
- }
-
- static mus_any *seg_copy(mus_any *ptr)
- {
- seg *e = NULL, *p;
- p = (seg *)ptr;
-
- switch (p->size) /* "npts" */
- {
- case 1:
- e = (seg *)malloc(sizeof(seg));
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- return((mus_any *)e);
-
- case 2: if (e2_free_list) {e = e2_free_list; e2_free_list = (seg *)(e->next);} break;
- case 3: if (e3_free_list) {e = e3_free_list; e3_free_list = (seg *)(e->next);} break;
- case 4: if (e4_free_list) {e = e4_free_list; e4_free_list = (seg *)(e->next);} break;
- default: break;
- }
-
- if (!e)
- {
- e = (seg *)malloc(sizeof(seg));
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- if (p->rates)
- {
- int bytes;
- bytes = p->size * sizeof(mus_float_t);
- e->rates = (mus_float_t *)malloc(bytes);
- memcpy((void *)(e->rates), (void *)(p->rates), bytes);
-
- bytes = (p->size + 1) * sizeof(mus_long_t);
- e->locs = (mus_long_t *)malloc(bytes);
- memcpy((void *)(e->locs), (void *)(p->locs), bytes);
- }
- }
- else
- {
- mus_float_t *r;
- mus_long_t *l;
- int bytes;
-
- bytes = p->size * sizeof(mus_float_t);
- r = e->rates;
- memcpy((void *)r, (void *)(p->rates), bytes);
-
- bytes = (p->size + 1) * sizeof(mus_long_t);
- l = e->locs;
- memcpy((void *)l, (void *)(p->locs), bytes);
-
- memcpy((void *)e, (void *)ptr, sizeof(seg));
- e->rates = r;
- e->locs = l;
- }
- return((mus_any *)e);
- }
-
- static mus_float_t *env_data(mus_any *ptr) {return(((seg *)ptr)->original_data);} /* mus-data */
-
- static mus_float_t env_scaler(mus_any *ptr) {return(((seg *)ptr)->original_scaler);} /* "mus_float_t" for mus-scaler */
-
- static mus_float_t env_offset(mus_any *ptr) {return(((seg *)ptr)->original_offset);}
-
- int mus_env_breakpoints(mus_any *ptr) {return(((seg *)ptr)->size);}
-
- static mus_long_t env_length(mus_any *ptr) {return((((seg *)ptr)->end + 1));} /* this needs to match the :length arg to make-env (changed to +1, 20-Feb-08) */
-
- static mus_float_t env_current_value(mus_any *ptr) {return(((seg *)ptr)->current_value);}
-
- mus_long_t *mus_env_passes(mus_any *gen) {return(((seg *)gen)->locs);}
-
- mus_float_t *mus_env_rates(mus_any *gen) {return(((seg *)gen)->rates);}
-
- static int env_position(mus_any *ptr) {return(((seg *)ptr)->index);}
-
- mus_float_t mus_env_offset(mus_any *gen) {return(((seg *)gen)->offset);}
-
- mus_float_t mus_env_scaler(mus_any *gen) {return(((seg *)gen)->scaler);}
-
- mus_float_t mus_env_initial_power(mus_any *gen) {return(((seg *)gen)->init_power);}
-
- static void env_set_location(mus_any *ptr, mus_long_t val);
-
- static mus_long_t seg_set_pass(mus_any *ptr, mus_long_t val) {env_set_location(ptr, val); return(val);}
-
- static mus_long_t seg_pass(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- return(gen->locs[gen->index] - gen->loc);
- }
-
-
- static mus_float_t env_increment(mus_any *rd)
- {
- if (((seg *)rd)->style == MUS_ENV_STEP)
- return(0.0);
- return(((seg *)rd)->base);
- }
-
-
- static void env_reset(mus_any *ptr)
- {
- seg *gen = (seg *)ptr;
- gen->current_value = gen->init_y;
- gen->index = 0;
- gen->loc = gen->locs[0];
- gen->rate = gen->rates[0];
- gen->power = gen->init_power;
- }
-
-
- static void rebuild_env(seg *e, mus_float_t scl, mus_float_t off, mus_long_t end)
- {
- seg *new_e;
-
- new_e = (seg *)mus_make_env(e->original_data, e->size, scl, off, e->base, 0.0, end, NULL);
- if (e->locs) free(e->locs);
- if (e->rates) free(e->rates);
- e->locs = new_e->locs;
- e->rates = new_e->rates;
-
- e->init_y = new_e->init_y;
- e->init_power = new_e->init_power;
- env_reset((mus_any *)e);
-
- free(new_e);
- }
-
-
- static mus_float_t env_set_scaler(mus_any *ptr, mus_float_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, val, e->original_offset, e->end);
- e->original_scaler = val;
- return(val);
- }
-
-
- static mus_float_t env_set_offset(mus_any *ptr, mus_float_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, e->original_scaler, val, e->end);
- e->original_offset = val;
- return(val);
- }
-
-
- static mus_long_t env_set_length(mus_any *ptr, mus_long_t val)
- {
- seg *e;
- e = (seg *)ptr;
- rebuild_env(e, e->original_scaler, e->original_offset, val - 1);
- e->end = val - 1;
- return(val);
- }
-
-
- static mus_any_class ENV_CLASS = {
- MUS_ENV,
- (char *)S_env,
- &free_env_gen,
- &describe_env,
- &env_equalp,
- &env_data, /* mus-data -> original breakpoints */
- 0,
- &env_length, &env_set_length,
- 0, 0,
- &env_current_value, 0, /* mus-phase?? -- used in snd-sig.c, but this needs a better access point */
- &env_scaler, &env_set_scaler,
- &env_increment,
- 0,
- &run_env,
- MUS_NOT_SPECIAL,
- NULL,
- &env_position,
- &env_offset, &env_set_offset,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &seg_pass, &seg_set_pass,
- 0,
- 0, 0, 0, 0,
- &env_reset,
- 0, &seg_copy
- };
-
-
- mus_any *mus_make_env(mus_float_t *brkpts, int npts, mus_float_t scaler, mus_float_t offset, mus_float_t base, mus_float_t duration, mus_long_t end, mus_float_t *ignored)
- {
- /* brkpts are not freed by the new env gen when it is freed, but should be protected during its existence */
- int i;
- mus_long_t dur_in_samples;
- mus_float_t *edata;
- seg *e = NULL;
- void (*fe_release)(mus_any *ptr);
-
- for (i = 2; i < npts * 2; i += 2)
- if (brkpts[i - 2] >= brkpts[i])
- {
- char *temp = NULL;
- mus_error(MUS_BAD_ENVELOPE, S_make_env ": env at breakpoint %d: x axis value: %f <= previous x value: %f (env: %s)",
- i / 2, brkpts[i], brkpts[i - 2],
- temp = float_array_to_string(brkpts, npts * 2, 0)); /* minor memleak here */
- if (temp) free(temp);
- return(NULL);
- }
-
- switch (npts)
- {
- case 1:
- e = (seg *)calloc(1, sizeof(seg));
- e->core = &ENV_CLASS;
- e->current_value = offset + scaler * brkpts[1];
- e->env_func = mus_env_line;
- e->original_data = brkpts;
- e->free_env = ferest;
- return((mus_any *)e);
-
- case 2:
- if (e2_free_list)
- {
- e = e2_free_list;
- e2_free_list = (seg *)(e->next);
- }
- fe_release = fe2;
- break;
-
- case 3:
- if (e3_free_list)
- {
- e = e3_free_list;
- e3_free_list = (seg *)(e->next);
- }
- fe_release = fe3;
- break;
-
- case 4:
- if (e4_free_list)
- {
- e = e4_free_list;
- e4_free_list = (seg *)(e->next);
- }
- fe_release = fe4;
- break;
-
- default:
- fe_release = ferest;
- break;
- }
-
- if (!e)
- {
- e = (seg *)malloc(sizeof(seg));
- e->core = &ENV_CLASS;
- e->size = npts;
- e->rates = (mus_float_t *)malloc(npts * sizeof(mus_float_t));
- e->locs = (mus_long_t *)malloc((npts + 1) * sizeof(mus_long_t));
- }
-
- e->free_env = fe_release;
- e->original_data = brkpts;
-
- if (duration != 0.0)
- dur_in_samples = (mus_long_t)(duration * sampling_rate);
- else dur_in_samples = (end + 1);
-
- e->init_y = offset + scaler * brkpts[1];
- e->current_value = e->init_y;
- e->rate = 0.0;
- e->offset = offset;
- e->scaler = scaler;
- e->original_offset = offset;
- e->original_scaler = scaler;
- e->base = base;
- e->end = (dur_in_samples - 1);
- e->loc = 0;
- e->index = 0;
-
- if (base == 1.0)
- {
- e->style = MUS_ENV_LINEAR;
- if ((npts == 2) &&
- (brkpts[1] == brkpts[3]))
- e->env_func = mus_env_line;
- else e->env_func = mus_env_linear;
- e->power = 0.0;
- e->init_power = 0.0;
- canonicalize_env(e, brkpts, npts, dur_in_samples, scaler);
- e->rates[npts - 1] = 0.0;
- }
- else
- {
- if (base == 0.0)
- {
- e->style = MUS_ENV_STEP;
- e->env_func = mus_env_step;
- e->power = 0.0;
- e->init_power = 0.0;
- canonicalize_env(e, brkpts, npts, dur_in_samples, scaler);
- e->rates[npts - 1] = e->offset + (scaler * brkpts[npts * 2 - 1]); /* stick at last value, which in this case is the value (not an increment) */
- }
- else
- {
- e->style = MUS_ENV_EXPONENTIAL;
- e->env_func = mus_env_exponential;
- edata = fixup_exp_env(e, brkpts, npts, offset, scaler, base);
- if (edata == NULL)
- {
- free(e);
- return(NULL);
- }
- canonicalize_env(e, edata, npts, dur_in_samples, 1.0);
- e->rates[npts - 1] = 1.0;
- e->power = exp(edata[1]);
- e->init_power = e->power;
- e->offset -= e->scaler;
- free(edata);
- }
- }
-
- e->rate = e->rates[0];
- e->loc = e->locs[0];
- return((mus_any *)e);
- }
-
- /* one way to make an impulse: (make-env '(0 1 1 0) :length 1 :base 0.0)
- * a counter: (make-env '(0 0 1 1) :length 21 :scaler 20) -- length = 1+scaler
- */
-
-
- static void env_set_location(mus_any *ptr, mus_long_t val)
- {
- seg *gen = (seg *)ptr;
- mus_long_t ctr = 0, loc;
-
- loc = gen->locs[gen->index] - gen->loc;
- if (loc == val) return;
-
- if (loc > val)
- mus_reset(ptr);
- else ctr = loc;
-
- while ((gen->index < (gen->size - 1)) && /* this was gen->size */
- (ctr < val))
- {
- mus_long_t samps;
- if (val > gen->locs[gen->index])
- samps = gen->locs[gen->index] - ctr;
- else samps = val - ctr;
-
- switch (gen->style)
- {
- case MUS_ENV_LINEAR:
- gen->current_value += (samps * gen->rate);
- break;
-
- case MUS_ENV_STEP:
- gen->current_value = gen->rate;
- break;
-
- case MUS_ENV_EXPONENTIAL:
- gen->power *= exp(samps * log(gen->rate));
- gen->current_value = gen->offset + (gen->scaler * gen->power);
- break;
- }
-
- ctr += samps;
- if (ctr < val)
- {
- gen->index++;
- if (gen->index < gen->size)
- gen->rate = gen->rates[gen->index];
- }
- }
- gen->loc = gen->locs[gen->index] - ctr;
- }
-
-
- mus_float_t mus_env_interp(mus_float_t x, mus_any *ptr)
- {
- /* the accuracy depends on the duration here -- more samples = more accurate */
- seg *gen = (seg *)ptr;
- env_set_location(ptr, (mus_long_t)((x * (gen->end + 1)) / (gen->original_data[gen->size * 2 - 2])));
- return(gen->current_value);
- }
-
-
- mus_float_t mus_env_any(mus_any *e, mus_float_t (*connect_points)(mus_float_t val))
- {
- /* "env_any" is supposed to mimic "out-any" */
- seg *gen = (seg *)e;
- mus_float_t *pts;
- int pt, size;
- mus_float_t y0, y1, new_val, val;
- mus_float_t scaler, offset;
-
- scaler = gen->original_scaler;
- offset = gen->original_offset;
- size = gen->size;
-
- if (size <= 1)
- return(offset + scaler * connect_points(0.0));
-
- pts = gen->original_data;
- pt = gen->index;
- if (pt >= (size - 1)) pt = size - 2;
- if (pts[pt * 2 + 1] <= pts[pt * 2 + 3])
- {
- y0 = pts[pt * 2 + 1];
- y1 = pts[pt * 2 + 3];
- }
- else
- {
- y1 = pts[pt * 2 + 1];
- y0 = pts[pt * 2 + 3];
- }
-
- val = (mus_env(e) - offset) / scaler;
- new_val = connect_points( (val - y0) / (y1 - y0));
- return(offset + scaler * (y0 + new_val * (y1 - y0)));
- }
-
-
- /* ---------------- pulsed-env ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *e, *p;
- bool gens_allocated;
- } plenv;
-
-
- static void free_pulsed_env(mus_any *ptr)
- {
- plenv *g;
- g = (plenv *)ptr;
- if (g->gens_allocated)
- {
- mus_free(g->e);
- mus_free(g->p);
- }
- free(ptr);
- }
-
- static mus_any *plenv_copy(mus_any *ptr)
- {
- plenv *g, *p;
- p = (plenv *)ptr;
- g = (plenv *)malloc(sizeof(plenv));
- memcpy((void *)g, (void *)ptr, sizeof(plenv));
- g->gens_allocated = true;
- g->e = mus_copy(p->e);
- g->p = mus_copy(p->p);
- return((mus_any *)g);
- }
-
-
- static mus_float_t run_pulsed_env(mus_any *ptr, mus_float_t input, mus_float_t unused)
- {
- return(mus_pulsed_env(ptr, input));
- }
-
-
- static void pulsed_env_reset(mus_any *ptr)
- {
- plenv *pl = (plenv *)ptr;
- mus_reset(pl->e);
- mus_reset(pl->p);
- }
-
-
- static bool pulsed_env_equalp(mus_any *p1, mus_any *p2)
- {
- plenv *f1 = (plenv *)p1;
- plenv *f2 = (plenv *)p2;
-
- if (f1 == f2) return(true);
- return((env_equalp(f1->e, f2->e)) &&
- (sw_equalp(f1->p, f2->p)));
- }
-
-
- static char *describe_pulsed_env(mus_any *ptr)
- {
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s",
- mus_name(ptr));
- return(describe_buffer);
- }
-
- static mus_any_class PULSED_ENV_CLASS = {
- MUS_PULSED_ENV,
- (char *)S_pulsed_env,
- &free_pulsed_env,
- &describe_pulsed_env,
- &pulsed_env_equalp,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- 0, 0,
- &run_pulsed_env,
- MUS_NOT_SPECIAL,
- NULL, 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &pulsed_env_reset,
- 0, &plenv_copy
- };
-
-
- mus_any *mus_make_pulsed_env(mus_any *e, mus_any *p)
- {
- plenv *gen;
-
- gen = (plenv *)malloc(sizeof(plenv));
- gen->core = &PULSED_ENV_CLASS;
- gen->e = e;
- gen->p = p;
- gen->gens_allocated = false;
- return((mus_any *)gen);
- }
-
- bool mus_is_pulsed_env(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PULSED_ENV));
- }
-
- mus_float_t mus_pulsed_env(mus_any *g, mus_float_t inval)
- {
- plenv *pl = (plenv *)g;
- mus_float_t pt_val;
- pt_val = mus_pulse_train(pl->p, inval);
- if (pt_val > 0.1)
- mus_reset(pl->e);
- return(mus_env(pl->e));
- }
-
-
- mus_float_t mus_pulsed_env_unmodulated(mus_any *g)
- {
- plenv *pl = (plenv *)g;
- mus_float_t pt_val;
- pt_val = mus_pulse_train_unmodulated(pl->p);
- if (pt_val > 0.1)
- mus_reset(pl->e);
- return(mus_env(pl->e));
- }
-
-
-
-
- /* ---------------- input/output ---------------- */
-
- static mus_float_t mus_read_sample(mus_any *fd, mus_long_t frample, int chan)
- {
- if ((check_gen(fd, "mus-read-sample")) &&
- ((fd->core)->read_sample))
- return(((*(fd->core)->read_sample))(fd, frample, chan));
- return((mus_float_t)mus_error(MUS_NO_SAMPLE_INPUT,
- ":can't find %s's sample input function",
- mus_name(fd)));
- }
-
-
- char *mus_file_name(mus_any *gen)
- {
- if ((check_gen(gen, S_mus_file_name)) &&
- (gen->core->file_name))
- return((*(gen->core->file_name))(gen));
- else mus_error(MUS_NO_FILE_NAME, "can't get %s's file name", mus_name(gen));
- return(NULL);
- }
-
-
- bool mus_is_input(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_INPUT));
- }
-
-
- bool mus_is_output(mus_any *gen)
- {
- return((gen) &&
- (gen->core->extended_type == MUS_OUTPUT));
- }
-
-
-
- /* ---------------- file->sample ---------------- */
-
- typedef struct {
- mus_any_class *core;
- int chan;
- int dir;
- mus_long_t loc;
- char *file_name;
- int chans;
- mus_float_t **ibufs, **saved_data;
- mus_float_t *sbuf;
- mus_long_t data_start, data_end, file_end;
- mus_long_t file_buffer_size;
- mus_float_t (*reader)(mus_any *ptr);
- } rdin;
-
-
- static char *describe_file_to_sample(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static bool rdin_equalp(mus_any *p1, mus_any *p2)
- {
- rdin *r1 = (rdin *)p1;
- rdin *r2 = (rdin *)p2;
- return((p1 == p2) ||
- ((r1) && (r2) &&
- (r1->core->type == r2->core->type) &&
- (r1->chan == r2->chan) &&
- (r1->loc == r2->loc) &&
- (r1->dir == r2->dir) &&
- (r1->file_name) &&
- (r2->file_name) &&
- (strcmp(r1->file_name, r2->file_name) == 0)));
- }
-
-
- static void free_file_to_sample(mus_any *p)
- {
- rdin *ptr = (rdin *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_long_t make_ibufs(rdin *gen)
- {
- int i;
- mus_long_t len;
- len = gen->file_end + 1;
- if (len > gen->file_buffer_size)
- len = gen->file_buffer_size;
-
- gen->ibufs = (mus_float_t **)malloc(gen->chans * sizeof(mus_float_t *));
- for (i = 0; i < gen->chans; i++)
- gen->ibufs[i] = (mus_float_t *)malloc(len * sizeof(mus_float_t));
-
- return(len);
- }
-
- static mus_any *rdin_copy(mus_any *ptr)
- {
- rdin *g, *p;
- p = (rdin *)ptr;
- g = (rdin *)malloc(sizeof(rdin));
- memcpy((void *)g, (void *)ptr, sizeof(rdin));
- g->file_name = mus_strdup(p->file_name);
- if (p->ibufs)
- {
- int i;
- mus_long_t len;
- len = make_ibufs(g);
- for (i = 0; i < g->chans; i++)
- memcpy((void *)(g->ibufs[i]), (void *)(p->ibufs[i]), len * sizeof(mus_float_t));
- }
- return((mus_any *)g);
- }
-
- static mus_long_t file_to_sample_length(mus_any *ptr) {return((((rdin *)ptr)->file_end));}
-
- static int file_to_sample_channels(mus_any *ptr) {return((int)(((rdin *)ptr)->chans));}
-
- static mus_float_t file_to_sample_increment(mus_any *rd) {return((mus_float_t)(((rdin *)rd)->dir));}
- static mus_float_t file_to_sample_set_increment(mus_any *rd, mus_float_t val) {((rdin *)rd)->dir = (int)val; return(val);}
-
- static char *file_to_sample_file_name(mus_any *ptr) {return(((rdin *)ptr)->file_name);}
-
- static void no_reset(mus_any *ptr) {}
-
- static mus_float_t mus_in_any_from_file(mus_any *ptr, mus_long_t samp, int chan)
- {
- /* check in-core buffer bounds,
- * if needed read new buffer (taking into account dir)
- * return mus_float_t at samp (frample)
- */
- rdin *gen = (rdin *)ptr;
-
- if (chan >= gen->chans)
- return(0.0);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
-
- if ((samp >= 0) &&
- (samp < gen->file_end))
- {
- /* got to read it from the file */
- int fd;
- mus_long_t newloc;
- /* read in first buffer start either at samp (dir > 0) or samp-bufsize (dir < 0) */
-
- if (samp >= gen->data_start) /* gen dir is irrelevant here (see grev in clm23.scm) */
- newloc = samp;
- else newloc = (mus_long_t)(samp - (gen->file_buffer_size * .75));
- /* The .75 in the backwards read is trying to avoid reading the full buffer on
- * nearly every sample when we're oscillating around the
- * nominal buffer start/end (in src driven by an oscil for example)
- */
- if (newloc < 0) newloc = 0;
- gen->data_start = newloc;
- gen->data_end = newloc + gen->file_buffer_size - 1;
- fd = mus_sound_open_input(gen->file_name);
- if (fd == -1)
- return((mus_float_t)mus_error(MUS_CANT_OPEN_FILE,
- "open(%s) -> %s",
- gen->file_name, STRERROR(errno)));
- else
- {
- if (gen->ibufs == NULL)
- make_ibufs(gen);
- mus_file_seek_frample(fd, gen->data_start);
-
- if ((gen->data_start + gen->file_buffer_size) >= gen->file_end)
- mus_file_read_chans(fd, gen->data_start, gen->file_end - gen->data_start, gen->chans, gen->ibufs, gen->ibufs);
- else mus_file_read_chans(fd, gen->data_start, gen->file_buffer_size, gen->chans, gen->ibufs, gen->ibufs);
-
- /* we have to check file_end here because chunked files can have trailing chunks containing
- * comments or whatever. io.c (mus_file_read_*) merely calls read, and translates bytes --
- * if it gets fewer than requested, it zeros from the point where the incoming file data stopped,
- * but that can be far beyond the actual end of the sample data! It is at this level that
- * we know how much data is actually supposed to be in the file.
- *
- * Also, file_end is the number of framples, so we should not read samp # file_end (see above).
- */
-
- mus_sound_close_input(fd);
- if (gen->data_end > gen->file_end) gen->data_end = gen->file_end;
- }
-
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
- }
-
- return(0.0);
- }
-
-
- static mus_float_t run_file_to_sample(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- /* mus_read_sample here? */
- return(mus_in_any_from_file(ptr, (int)arg1, (int)arg2));
- }
-
-
- static int file_to_sample_end(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- if (gen)
- {
- if (gen->ibufs)
- {
- int i;
- for (i = 0; i < gen->chans; i++)
- if (gen->ibufs[i])
- free(gen->ibufs[i]);
- free(gen->ibufs);
- gen->ibufs = NULL;
- gen->sbuf = NULL;
- }
- }
- return(0);
- }
-
-
- static mus_any_class FILE_TO_SAMPLE_CLASS = {
- MUS_FILE_TO_SAMPLE,
- (char *)S_file_to_sample,
- &free_file_to_sample,
- &describe_file_to_sample,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- 0, 0,
- &file_to_sample_increment,
- &file_to_sample_set_increment,
- &run_file_to_sample,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &mus_in_any_from_file,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- 0, /* location */
- 0, /* set_location */
- 0, /* channel */
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- bool mus_is_file_to_sample(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILE_TO_SAMPLE));
- }
-
-
- mus_any *mus_make_file_to_sample_with_buffer_size(const char *filename, mus_long_t buffer_size)
- {
- rdin *gen;
-
- if (filename == NULL)
- mus_error(MUS_NO_FILE_NAME_PROVIDED, S_make_file_to_sample " requires a file name");
- else
- {
- gen = (rdin *)calloc(1, sizeof(rdin));
- gen->core = &FILE_TO_SAMPLE_CLASS;
-
- gen->file_name = (char *)malloc((strlen(filename) + 1) * sizeof(char));
- strcpy(gen->file_name, filename);
- gen->data_end = -1; /* force initial read */
-
- gen->chans = mus_sound_chans(gen->file_name);
- if (gen->chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_make_file_to_sample ": %s chans: %d", filename, gen->chans);
-
- gen->file_end = mus_sound_framples(gen->file_name);
- if (gen->file_end < 0)
- mus_error(MUS_NO_LENGTH, S_make_file_to_sample ": %s framples: %lld", filename, gen->file_end);
-
- if (buffer_size < gen->file_end)
- gen->file_buffer_size = buffer_size;
- else gen->file_buffer_size = gen->file_end;
-
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_file_to_sample(const char *filename)
- {
- return(mus_make_file_to_sample_with_buffer_size(filename, clm_file_buffer_size));
- }
-
-
- mus_float_t mus_file_to_sample(mus_any *ptr, mus_long_t samp, int chan)
- {
- rdin *gen = (rdin *)ptr;
-
- if (chan >= gen->chans)
- return(0.0);
-
- /* redundant in a sense, but saves the call overhead of mus_in_any_from_file */
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- return((mus_float_t)(gen->ibufs[chan][samp - gen->data_start]));
-
- return(mus_in_any_from_file(ptr, samp, chan));
- }
-
-
-
- /* ---------------- readin ---------------- */
-
- /* readin reads only the desired channel and increments the location by the direction
- * it inherits from and specializes the file_to_sample class
- */
-
- static char *describe_readin(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s[chan %d], loc: %lld, dir: %d",
- mus_name(ptr),
- gen->file_name, gen->chan, gen->loc, gen->dir);
- return(describe_buffer);
- }
-
-
- static void free_readin(mus_any *p)
- {
- rdin *ptr = (rdin *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_float_t run_readin(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(((rdin *)ptr)->reader(ptr));}
- static mus_float_t readin_to_sample(mus_any *ptr, mus_long_t samp, int chan) {return(((rdin *)ptr)->reader(ptr));}
-
- static mus_float_t rd_increment(mus_any *ptr) {return((mus_float_t)(((rdin *)ptr)->dir));}
- static mus_float_t rd_set_increment(mus_any *ptr, mus_float_t val) {((rdin *)ptr)->dir = (int)val; return(val);}
-
- static mus_long_t rd_location(mus_any *rd) {return(((rdin *)rd)->loc);}
- static mus_long_t rd_set_location(mus_any *rd, mus_long_t loc) {((rdin *)rd)->loc = loc; return(loc);}
-
- static int rd_channel(mus_any *rd) {return(((rdin *)rd)->chan);}
-
- static mus_any_class READIN_CLASS = {
- MUS_READIN,
- (char *)S_readin,
- &free_readin,
- &describe_readin,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &rd_increment,
- &rd_set_increment,
- &run_readin,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &readin_to_sample,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- &rd_location,
- &rd_set_location,
- &rd_channel,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- bool mus_is_readin(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_READIN));
- }
-
-
- mus_float_t mus_readin(mus_any *ptr)
- {
- return(((rdin *)ptr)->reader(ptr));
- }
-
-
- static mus_float_t safe_readin(mus_any *ptr)
- {
- mus_float_t res;
- rdin *rd = (rdin *)ptr;
-
- if ((rd->loc < rd->file_end) &&
- (rd->loc >= 0))
- res = rd->sbuf[rd->loc];
- else res = 0.0;
- rd->loc += rd->dir;
- return(res);
- }
-
-
- static mus_float_t readin(mus_any *ptr)
- {
- mus_float_t res;
- rdin *rd = (rdin *)ptr;
-
- if ((rd->loc <= rd->data_end) &&
- (rd->loc >= rd->data_start))
- res = rd->sbuf[rd->loc - rd->data_start];
- else
- {
- if ((rd->loc < 0) || (rd->loc >= rd->file_end))
- res = 0.0;
- else res = mus_in_any_from_file(ptr, rd->loc, rd->chan);
- }
-
- rd->loc += rd->dir;
- return(res);
- }
-
-
- mus_any *mus_make_readin_with_buffer_size(const char *filename, int chan, mus_long_t start, int direction, mus_long_t buffer_size)
- {
- rdin *gen;
- if (chan >= mus_sound_chans(filename))
- mus_error(MUS_NO_SUCH_CHANNEL, S_make_readin ": %s, chan: %d, but chans: %d", filename, chan, mus_sound_chans(filename));
-
- gen = (rdin *)mus_make_file_to_sample(filename);
- if (gen)
- {
- gen->core = &READIN_CLASS;
- gen->loc = start;
- gen->dir = direction;
- gen->chan = chan;
- /* the saved data option does not save us anything in file_to_sample above */
- gen->saved_data = mus_sound_saved_data(filename);
- if (!gen->saved_data)
- {
- char *str;
- str = mus_expand_filename(filename);
- if (str)
- {
- gen->saved_data = mus_sound_saved_data(str);
- free(str);
- }
- }
- if (gen->saved_data)
- {
- gen->file_buffer_size = gen->file_end;
- gen->sbuf = gen->saved_data[chan];
- gen->reader = safe_readin;
- gen->data_start = 0;
- gen->data_end = gen->file_end;
- }
- else
- {
- gen->ibufs = (mus_float_t **)calloc(gen->chans, sizeof(mus_float_t *));
- if (buffer_size > gen->file_end)
- {
- gen->file_buffer_size = gen->file_end;
- gen->reader = safe_readin;
- gen->ibufs[chan] = (mus_float_t *)malloc(gen->file_buffer_size * sizeof(mus_float_t));
- mus_in_any_from_file((mus_any *)gen, 0, chan);
- }
- else
- {
- gen->file_buffer_size = buffer_size;
- gen->reader = readin;
- gen->ibufs[chan] = (mus_float_t *)malloc(gen->file_buffer_size * sizeof(mus_float_t));
- }
- gen->sbuf = gen->ibufs[chan];
- }
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
- /* it would be easy to extend readin to read from a float-vector by using the saved_data and safe_readin
- * business above -- just need mus_make_readin_from_float_vector or something.
- */
-
-
- mus_long_t mus_set_location(mus_any *gen, mus_long_t loc)
- {
- if ((check_gen(gen, S_set S_mus_location)) &&
- (gen->core->set_location))
- return((*(gen->core->set_location))(gen, loc));
- return((mus_long_t)mus_error(MUS_NO_LOCATION, "can't set %s's location", mus_name(gen)));
- }
-
-
-
- /* ---------------- in-any ---------------- */
-
- mus_float_t mus_in_any(mus_long_t samp, int chan, mus_any *IO)
- {
- if (IO) return(mus_read_sample(IO, samp, chan));
- return(0.0);
- }
-
-
- bool mus_in_any_is_safe(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- return((gen) &&
- ((gen->core->read_sample == mus_in_any_from_file) ||
- (gen->core->read_sample == readin_to_sample)));
- }
-
-
-
- /* ---------------- file->frample ---------------- */
-
- /* also built on file->sample */
-
- static char *describe_file_to_frample(mus_any *ptr)
- {
- rdin *gen = (rdin *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static mus_float_t run_file_to_frample(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_error(MUS_NO_RUN, "no run method for file->frample");
- return(0.0);
- }
-
-
- static mus_any_class FILE_TO_FRAMPLE_CLASS = {
- MUS_FILE_TO_FRAMPLE,
- (char *)S_file_to_frample,
- &free_file_to_sample,
- &describe_file_to_frample,
- &rdin_equalp,
- 0, 0,
- &file_to_sample_length, 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &file_to_sample_increment, /* allow backward reads */
- &file_to_sample_set_increment,
- &run_file_to_frample,
- MUS_INPUT,
- NULL,
- &file_to_sample_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- &mus_in_any_from_file,
- 0,
- &file_to_sample_file_name,
- &file_to_sample_end,
- 0, /* location */
- 0, /* set_location */
- 0, /* channel */
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdin_copy
- };
-
-
- mus_any *mus_make_file_to_frample_with_buffer_size(const char *filename, mus_long_t buffer_size)
- {
- rdin *gen;
- gen = (rdin *)mus_make_file_to_sample_with_buffer_size(filename, buffer_size);
- if (gen)
- {
- gen->core = &FILE_TO_FRAMPLE_CLASS;
- return((mus_any *)gen);
- }
- return(NULL);
- }
-
-
- mus_any *mus_make_file_to_frample(const char *filename)
- {
- return(mus_make_file_to_frample_with_buffer_size(filename, clm_file_buffer_size));
- }
-
-
- bool mus_is_file_to_frample(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FILE_TO_FRAMPLE));
- }
-
-
- mus_float_t *mus_file_to_frample(mus_any *ptr, mus_long_t samp, mus_float_t *f)
- {
- rdin *gen = (rdin *)ptr;
- int i;
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- mus_long_t pos;
- pos = samp - gen->data_start;
- f[0] = gen->ibufs[0][pos];
- for (i = 1; i < gen->chans; i++)
- f[i] = gen->ibufs[i][pos];
- }
- else
- {
- if ((samp < 0) ||
- (samp >= gen->file_end))
- {
- for (i = 0; i < gen->chans; i++)
- f[i] = 0.0;
- }
- else
- {
- f[0] = mus_in_any_from_file(ptr, samp, 0);
- for (i = 1; i < gen->chans; i++)
- f[i] = mus_in_any_from_file(ptr, samp, i);
- }
- }
- return(f);
- }
-
-
-
- /* ---------------- sample->file ---------------- */
-
- /* in all output functions, the assumption is that we're adding to whatever already exists */
- /* also, the "end" methods need to flush the output buffer */
-
- /* rdout struct is in clm.h */
-
- static char *describe_sample_to_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static bool sample_to_file_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static void free_sample_to_file(mus_any *p)
- {
- rdout *ptr = (rdout *)p;
- if (ptr->core->end) ((*ptr->core->end))(p);
- free(ptr->file_name);
- free(ptr);
- }
-
- static mus_any *rdout_copy(mus_any *ptr)
- {
- rdout *g, *p;
- p = (rdout *)ptr;
- g = (rdout *)malloc(sizeof(rdout));
- memcpy((void *)g, (void *)ptr, sizeof(rdout));
- g->file_name = mus_strdup(p->file_name);
- if (p->obufs)
- {
- int i;
- mus_long_t bytes;
- bytes = clm_file_buffer_size * sizeof(mus_float_t);
- g->obufs = (mus_float_t **)malloc(g->chans * sizeof(mus_float_t *));
- for (i = 0; i < g->chans; i++)
- {
- g->obufs[i] = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->obufs[i]), (void *)(p->obufs[i]), bytes);
- }
- g->obuf0 = g->obufs[0];
- if (g->chans > 1)
- g->obuf1 = g->obufs[1];
- else g->obuf1 = NULL;
- }
- return((mus_any *)g);
- }
-
- static int sample_to_file_channels(mus_any *ptr) {return((int)(((rdout *)ptr)->chans));}
-
- static mus_long_t bufferlen(mus_any *ptr) {return(clm_file_buffer_size);}
-
- static mus_long_t set_bufferlen(mus_any *ptr, mus_long_t len) {clm_file_buffer_size = len; return(len);}
-
- static char *sample_to_file_file_name(mus_any *ptr) {return(((rdout *)ptr)->file_name);}
-
- static int sample_to_file_end(mus_any *ptr);
-
- static mus_float_t run_sample_to_file(mus_any *ptr, mus_float_t arg1, mus_float_t arg2) {mus_error(MUS_NO_RUN, "no run method for sample->file"); return(0.0);}
-
- static mus_any_class SAMPLE_TO_FILE_CLASS = {
- MUS_SAMPLE_TO_FILE,
- (char *)S_sample_to_file,
- &free_sample_to_file,
- &describe_sample_to_file,
- &sample_to_file_equalp,
- 0, 0,
- &bufferlen, &set_bufferlen, /* does this have any effect on the current gen? */
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- 0, 0,
- &run_sample_to_file,
- MUS_OUTPUT,
- NULL,
- &sample_to_file_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- &mus_out_any_to_file,
- &sample_to_file_file_name,
- &sample_to_file_end,
- 0, 0, 0,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdout_copy
- };
-
-
- static int *sample_type_zero = NULL;
-
- int mus_sample_type_zero(mus_sample_t samp_type)
- {
- return(sample_type_zero[samp_type]);
- }
-
-
- static void flush_buffers(rdout *gen)
- {
- int fd;
-
- if ((gen->obufs == NULL) ||
- (mus_file_probe(gen->file_name) == 0) ||
- (gen->chans == 0))
- return; /* can happen if output abandoned, then later mus_free called via GC sweep */
-
- fd = mus_sound_open_input(gen->file_name);
- if (fd == -1)
- {
- /* no output yet, so open the output file and write the current samples (no need to add to existing samples in this case) */
- fd = mus_sound_open_output(gen->file_name,
- (int)sampling_rate,
- gen->chans,
- gen->output_sample_type,
- gen->output_header_type,
- NULL);
- if (fd == -1)
- mus_error(MUS_CANT_OPEN_FILE,
- "open(%s) -> %s",
- gen->file_name, STRERROR(errno));
- else
- {
- mus_file_write(fd, 0, gen->out_end, gen->chans, gen->obufs);
- mus_sound_close_output(fd, (gen->out_end + 1) * gen->chans * mus_bytes_per_sample(mus_sound_sample_type(gen->file_name)));
- }
- }
- else
- {
- /* get existing samples, add new output, write back to output */
- mus_float_t **addbufs = NULL;
- int i;
- mus_sample_t sample_type;
- mus_long_t current_file_framples, framples_to_add;
-
- sample_type = mus_sound_sample_type(gen->file_name);
- current_file_framples = mus_sound_framples(gen->file_name);
- /* this is often 0 (brand-new file) */
-
- if (current_file_framples > gen->data_start)
- {
- bool allocation_failed = false;
- addbufs = (mus_float_t **)calloc(gen->chans, sizeof(mus_float_t *));
-
- for (i = 0; i < gen->chans; i++)
- {
- /* clm_file_buffer_size may be too large, but it's very hard to tell that
- * in advance. In Linux, malloc returns a non-null pointer even when
- * there's no memory available, so you have to touch the memory to force
- * the OS to deal with it, then the next allocation returns null.
- */
- addbufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
- if (addbufs[i])
- addbufs[i][0] = 0.0;
- else
- {
- allocation_failed = true;
- break;
- }
- }
-
- if (allocation_failed)
- {
- mus_long_t old_file_buffer_size = 0;
-
- /* first clean up the mess we made */
- for (i = 0; i < gen->chans; i++)
- if (addbufs[i])
- {
- free(addbufs[i]);
- addbufs[i] = NULL;
- }
- free(addbufs);
-
- /* it would take a lot of screwing around to find the biggest clm_file_buffer_size we could handle,
- * and it might fail on the next call (if more chans), so we'll throw an error. We could get
- * say 1024 samps per chan, then run through a loop outputting the current buffer, but geez...
- */
- /* but... if we hit this in with-sound, mus_error calls (eventually) s7_error which sees the
- * dynamic-wind and tries to call mus-close, which tries to flush the buffers and we have
- * an infinite loop. So, we need to clean up right now.
- */
- mus_sound_close_input(fd);
- old_file_buffer_size = clm_file_buffer_size;
- clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
- mus_error(MUS_MEMORY_ALLOCATION_FAILED, S_mus_file_buffer_size " (%lld) is too large: we can't allocate the output buffers!", old_file_buffer_size);
- return;
- }
- }
-
- framples_to_add = gen->out_end - gen->data_start;
-
- /* if the caller reset clm_file_buffer_size during a run, framples_to_add might be greater than the assumed buffer size,
- * so we need to complain and fix up the limits. In CLM, the size is set in sound.lisp, begin-with-sound.
- * In Snd via mus_set_file_buffer_size in clm2xen.c. The initial default is set in mus_initialize
- * called in CLM by clm-initialize-links via in cmus.c, and in Snd in clm2xen.c when the module is setup.
- */
- if (framples_to_add >= clm_file_buffer_size)
- {
- mus_print("clm-file-buffer-size changed? %lld <= %lld (start: %lld, end: %lld, %lld)",
- clm_file_buffer_size, framples_to_add, gen->data_start, gen->data_end, gen->out_end);
-
- framples_to_add = clm_file_buffer_size - 1;
- /* this means we drop samples -- the other choice (short of throwing an error) would
- * be to read/allocate the bigger size.
- */
- }
- if (addbufs)
- {
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_read(fd, gen->data_start, framples_to_add + 1, gen->chans, addbufs);
- }
- mus_sound_close_input(fd); /* close previous mus_sound_open_input */
-
- fd = mus_sound_reopen_output(gen->file_name, gen->chans, sample_type,
- mus_sound_header_type(gen->file_name),
- mus_sound_data_location(gen->file_name));
-
- if ((current_file_framples < gen->data_start) &&
- (sample_type_zero[sample_type] != 0))
- {
- /* we're about to create a gap in the output file. mus_file_seek_frample calls lseek which (man lseek):
- *
- * "The lseek function allows the file offset to be set beyond the end of
- * the existing end-of-file of the file (but this does not change the size
- * of the file). If data is later written at this point, subsequent reads
- * of the data in the gap return bytes of zeros (until data is actually
- * written into the gap)."
- *
- * but 0 bytes in a file are not interpreted as sound samples of 0 in several sample types.
- * for example, mus-mulaw 0 => -.98, whereas sound sample 0 is a byte of 255.
- * see the table at the end of this file (sample_type_zero) for the other cases.
- *
- * So, we need to write explicit sample-type 0 values in those cases where machine 0's
- * won't be sample type 0. sample_type_zero[type] != 0 signals we have such a
- * case, and returns the nominal zero value. For unsigned shorts, we also need to
- * take endianess into account.
- */
-
- mus_long_t filler, current_samps, bytes, bps;
- unsigned char *zeros;
- #define MAX_ZERO_SAMPLES 65536
-
- bps = mus_bytes_per_sample(sample_type);
- filler = gen->data_start - current_file_framples;
- mus_file_seek_frample(fd, current_file_framples);
-
- if (filler > MAX_ZERO_SAMPLES)
- bytes = MAX_ZERO_SAMPLES * bps * gen->chans;
- else bytes = filler * bps * gen->chans;
-
- zeros = (unsigned char *)malloc(bytes);
- if (bps == 1)
- memset((void *)zeros, sample_type_zero[sample_type], bytes);
- else /* it has to be a short */
- {
- int df, i, b1, b2;
- df = sample_type_zero[sample_type];
- b1 = df >> 8;
- b2 = df & 0xff;
- for (i = 0; i < bytes; i += 2)
- {
- zeros[i] = b2;
- zeros[i + 1] = b1;
- }
- }
- /* (with-sound (:sample-type mus-ulshort) (fm-violin 10 1 440 .1)) */
- while (filler > 0)
- {
- ssize_t wbytes;
- if (filler > MAX_ZERO_SAMPLES)
- current_samps = MAX_ZERO_SAMPLES;
- else
- {
- current_samps = filler;
- bytes = current_samps * bps * gen->chans;
- }
- wbytes = write(fd, zeros, bytes);
- if (wbytes != bytes) fprintf(stderr, "%s[%d]: write trouble\n", __func__, __LINE__);
- filler -= current_samps;
- }
- free(zeros);
- }
-
- if (addbufs)
- {
- int j;
- /* fill/write output buffers with current data added to saved data */
- for (j = 0; j < gen->chans; j++)
- {
- mus_float_t *adder, *vals;
- mus_long_t add4;
- adder = addbufs[j];
- vals = gen->obufs[j];
- add4 = framples_to_add - 4;
- i = 0;
- while (i <= add4)
- {
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- adder[i] += vals[i];
- i++;
- }
- for (; i <= framples_to_add; i++)
- adder[i] += vals[i];
- }
-
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_write(fd, 0, framples_to_add, gen->chans, addbufs);
- for (i = 0; i < gen->chans; i++)
- free(addbufs[i]);
- free(addbufs);
- }
- else
- {
- /* output currently empty, so just flush out the gen->obufs */
- mus_file_seek_frample(fd, gen->data_start);
- mus_file_write(fd, 0, framples_to_add, gen->chans, gen->obufs);
- }
-
- if (current_file_framples <= gen->out_end)
- current_file_framples = gen->out_end + 1;
- mus_sound_close_output(fd, current_file_framples * gen->chans * mus_bytes_per_sample(sample_type));
- }
- }
-
-
- mus_any *mus_sample_to_file_add(mus_any *out1, mus_any *out2)
- {
- mus_long_t min_framples;
- rdout *dest = (rdout *)out1;
- rdout *in_coming = (rdout *)out2;
- int chn, min_chans;
-
- min_chans = dest->chans;
- if (in_coming->chans < min_chans) min_chans = in_coming->chans;
- min_framples = in_coming->out_end;
-
- for (chn = 0; chn < min_chans; chn++)
- {
- mus_long_t i;
- for (i = 0; i < min_framples; i++)
- dest->obufs[chn][i] += in_coming->obufs[chn][i];
- memset((void *)(in_coming->obufs[chn]), 0, min_framples * sizeof(mus_float_t));
- }
-
- if (min_framples > dest->out_end)
- dest->out_end = min_framples;
-
- in_coming->out_end = 0;
- in_coming->data_start = 0;
-
- return((mus_any*)dest);
- }
-
-
- mus_float_t mus_out_any_to_file(mus_any *ptr, mus_long_t samp, int chan, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((chan >= gen->chans) || /* checking for (val == 0.0) here appears to make no difference overall */
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obufs[chan][samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obufs[chan][0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static void mus_out_chans_to_file(rdout *gen, mus_long_t samp, int chans, mus_float_t *vals)
- {
- int i;
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- mus_long_t pos;
- pos = samp - gen->data_start;
- for (i = 0; i < chans; i++)
- gen->obufs[i][pos] += vals[i];
- }
- else
- {
- int j;
- if (samp < 0) return;
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- for (i = 0; i < chans; i++)
- gen->obufs[i][0] += vals[i];
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- }
-
-
- static mus_float_t mus_outa_to_file(mus_any *ptr, mus_long_t samp, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((!(gen->obuf0)) ||
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obuf0[samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obuf0[0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static mus_float_t mus_outb_to_file(mus_any *ptr, mus_long_t samp, mus_float_t val)
- {
- rdout *gen = (rdout *)ptr;
- if (!ptr) return(val);
-
- if ((!(gen->obuf1)) ||
- (!(gen->obufs)))
- return(val);
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- gen->obuf1[samp - gen->data_start] += val;
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obuf1[0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
-
- if (samp > gen->out_end)
- gen->out_end = samp;
- return(val);
- }
-
-
- static int sample_to_file_end(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- if ((gen) && (gen->obufs))
- {
- if (gen->chans > 0)
- {
- int i;
- flush_buffers(gen); /* this forces the error handling stuff, unlike in free reader case */
- for (i = 0; i < gen->chans; i++)
- if (gen->obufs[i])
- free(gen->obufs[i]);
- }
- free(gen->obufs);
- gen->obufs = NULL;
- gen->obuf0 = NULL;
- gen->obuf1 = NULL;
- }
- return(0);
- }
-
-
- bool mus_is_sample_to_file(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SAMPLE_TO_FILE));
- }
-
-
- static mus_any *mus_make_sample_to_file_with_comment_1(const char *filename, int out_chans,
- mus_sample_t samp_type, mus_header_t head_type, const char *comment, bool reopen)
- {
- if (filename == NULL)
- mus_error(MUS_NO_FILE_NAME_PROVIDED, S_make_sample_to_file " requires a file name");
- else
- {
- int fd;
- if (out_chans <= 0)
- return(NULL);
- if (reopen)
- fd = mus_sound_reopen_output(filename, out_chans, samp_type, head_type, mus_sound_data_location(filename));
- else fd = mus_sound_open_output(filename, (int)sampling_rate, out_chans, samp_type, head_type, comment);
- if (fd == -1)
- mus_error(MUS_CANT_OPEN_FILE,
- S_make_sample_to_file ": open(%s) -> %s",
- filename, STRERROR(errno));
- else
- {
- rdout *gen;
- int i;
-
- gen = (rdout *)calloc(1, sizeof(rdout));
- gen->core = &SAMPLE_TO_FILE_CLASS;
- gen->file_name = (char *)calloc(strlen(filename) + 1, sizeof(char));
- strcpy(gen->file_name, filename);
- gen->data_start = 0;
- gen->data_end = clm_file_buffer_size - 1;
- gen->out_end = 0;
- gen->chans = out_chans;
- gen->output_sample_type = samp_type;
- gen->output_header_type = head_type;
- gen->obufs = (mus_float_t **)malloc(gen->chans * sizeof(mus_float_t *));
- for (i = 0; i < gen->chans; i++)
- gen->obufs[i] = (mus_float_t *)calloc(clm_file_buffer_size, sizeof(mus_float_t));
- gen->obuf0 = gen->obufs[0];
- if (out_chans > 1)
- gen->obuf1 = gen->obufs[1];
- else gen->obuf1 = NULL;
-
- /* clear previous, if any */
- if (mus_file_close(fd) != 0)
- mus_error(MUS_CANT_CLOSE_FILE,
- S_make_sample_to_file ": close(%d, %s) -> %s",
- fd, gen->file_name, STRERROR(errno));
-
- return((mus_any *)gen);
- }
- }
- return(NULL);
- }
-
-
- mus_any *mus_continue_sample_to_file(const char *filename)
- {
- return(mus_make_sample_to_file_with_comment_1(filename,
- mus_sound_chans(filename),
- mus_sound_sample_type(filename),
- mus_sound_header_type(filename),
- NULL,
- true));
- }
-
-
- mus_any *mus_make_sample_to_file_with_comment(const char *filename, int out_chans, mus_sample_t samp_type, mus_header_t head_type, const char *comment)
- {
- return(mus_make_sample_to_file_with_comment_1(filename, out_chans, samp_type, head_type, comment, false));
- }
-
-
- mus_float_t mus_sample_to_file(mus_any *fd, mus_long_t samp, int chan, mus_float_t val)
- {
- /* return(mus_write_sample(ptr, samp, chan, val)); */
- if ((fd) &&
- ((fd->core)->write_sample))
- return(((*(fd->core)->write_sample))(fd, samp, chan, val));
- mus_error(MUS_NO_SAMPLE_OUTPUT,
- S_sample_to_file ": can't find %s's sample output function",
- mus_name(fd));
- return(val);
- }
-
-
- int mus_close_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- if ((mus_is_output(ptr)) && (gen->obufs)) sample_to_file_end(ptr);
- return(0);
- }
-
-
- /* ---------------- out-any ---------------- */
-
- mus_float_t mus_out_any(mus_long_t samp, mus_float_t val, int chan, mus_any *IO)
- {
- if ((IO) &&
- (samp >= 0))
- {
- if ((IO->core)->write_sample)
- return(((*(IO->core)->write_sample))(IO, samp, chan, val));
- mus_error(MUS_NO_SAMPLE_OUTPUT,
- "can't find %s's sample output function",
- mus_name(IO));
- }
- return(val);
- }
-
-
- mus_float_t mus_safe_out_any_to_file(mus_long_t samp, mus_float_t val, int chan, mus_any *IO)
- {
- rdout *gen = (rdout *)IO;
- if (chan >= gen->chans) /* checking for (val == 0.0) here appears to make no difference overall */
- return(val);
- /* does this need to check obufs? */
-
- if ((samp <= gen->data_end) &&
- (samp >= gen->data_start))
- {
- gen->obufs[chan][samp - gen->data_start] += val;
- if (samp > gen->out_end)
- gen->out_end = samp;
- }
- else
- {
- int j;
- if (samp < 0) return(val);
- flush_buffers(gen);
- for (j = 0; j < gen->chans; j++)
- memset((void *)(gen->obufs[j]), 0, clm_file_buffer_size * sizeof(mus_float_t));
- gen->data_start = samp;
- gen->data_end = samp + clm_file_buffer_size - 1;
- gen->obufs[chan][0] += val;
- gen->out_end = samp; /* this resets the current notion of where in the buffer the new data ends */
- }
- return(val);
-
- }
-
-
- bool mus_out_any_is_safe(mus_any *IO)
- {
- rdout *gen = (rdout *)IO;
- return((gen) &&
- (gen->obufs) &&
- (gen->core->write_sample == mus_out_any_to_file));
- }
-
-
-
- /* ---------------- frample->file ---------------- */
-
- static char *describe_frample_to_file(mus_any *ptr)
- {
- rdout *gen = (rdout *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s %s",
- mus_name(ptr),
- gen->file_name);
- return(describe_buffer);
- }
-
-
- static mus_float_t run_frample_to_file(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_error(MUS_NO_RUN, "no run method for frample->file");
- return(0.0);
- }
-
-
- static mus_any_class FRAMPLE_TO_FILE_CLASS = {
- MUS_FRAMPLE_TO_FILE,
- (char *)S_frample_to_file,
- &free_sample_to_file,
- &describe_frample_to_file,
- &sample_to_file_equalp,
- 0, 0,
- &bufferlen, &set_bufferlen,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- 0, 0,
- &run_frample_to_file,
- MUS_OUTPUT,
- NULL,
- &sample_to_file_channels,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,
- &mus_out_any_to_file,
- &sample_to_file_file_name,
- &sample_to_file_end,
- 0, 0, 0,
- 0, 0, 0, 0,
- &no_reset,
- 0, &rdout_copy
- };
-
-
- mus_any *mus_make_frample_to_file_with_comment(const char *filename, int chans, mus_sample_t samp_type, mus_header_t head_type, const char *comment)
- {
- rdout *gen = NULL;
- gen = (rdout *)mus_make_sample_to_file_with_comment(filename, chans, samp_type, head_type, comment);
- if (gen) gen->core = &FRAMPLE_TO_FILE_CLASS;
- return((mus_any *)gen);
- }
-
-
- bool mus_is_frample_to_file(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_FRAMPLE_TO_FILE));
- }
-
-
- mus_float_t *mus_frample_to_file(mus_any *ptr, mus_long_t samp, mus_float_t *data)
- {
- rdout *gen = (rdout *)ptr;
- if (!gen) return(data);
-
- if (gen->chans == 1)
- mus_outa_to_file(ptr, samp, data[0]);
- else
- {
- if (gen->chans == 2)
- {
- mus_outa_to_file(ptr, samp, data[0]);
- mus_outb_to_file(ptr, samp, data[1]);
- }
- else mus_out_chans_to_file(gen, samp, gen->chans, data);
- }
- return(data);
- }
-
-
- mus_any *mus_continue_frample_to_file(const char *filename)
- {
- rdout *gen = NULL;
- gen = (rdout *)mus_continue_sample_to_file(filename);
- if (gen) gen->core = &FRAMPLE_TO_FILE_CLASS;
- return((mus_any *)gen);
- }
-
-
- mus_float_t *mus_frample_to_frample(mus_float_t *matrix, int mx_chans, mus_float_t *in_samps, int in_chans, mus_float_t *out_samps, int out_chans)
- {
- /* in->out conceptually, so left index is in_chan, it (j below) steps by out_chans */
- int i, j, offset;
- if (mx_chans < out_chans) out_chans = mx_chans;
- if (mx_chans < in_chans) in_chans = mx_chans;
- for (i = 0; i < out_chans; i++)
- {
- out_samps[i] = in_samps[0] * matrix[i];
- for (j = 1, offset = mx_chans; j < in_chans; j++, offset += mx_chans)
- out_samps[i] += in_samps[j] * matrix[offset + i];
- }
- return(out_samps);
- }
-
-
-
- /* ---------------- locsig ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *outn_writer;
- mus_any *revn_writer;
- mus_float_t *outf, *revf;
- mus_float_t *outn;
- mus_float_t *revn;
- int chans, rev_chans;
- mus_interp_t type;
- mus_float_t reverb;
- bool safe_output;
- void *closure;
- void (*locsig_func)(mus_any *ptr, mus_long_t loc, mus_float_t val);
- void (*detour)(mus_any *ptr, mus_long_t loc);
- } locs;
-
-
- static bool locsig_equalp(mus_any *p1, mus_any *p2)
- {
- locs *g1 = (locs *)p1;
- locs *g2 = (locs *)p2;
- if (p1 == p2) return(true);
- return((g1) && (g2) &&
- (g1->core->type == g2->core->type) &&
- (g1->chans == g2->chans) &&
- (clm_arrays_are_equal(g1->outn, g2->outn, g1->chans)) &&
- (((bool)(g1->revn != NULL)) == ((bool)(g2->revn != NULL))) &&
- ((!(g1->revn)) || (clm_arrays_are_equal(g1->revn, g2->revn, g1->rev_chans))));
- }
-
-
- static char *describe_locsig(mus_any *ptr)
- {
- char *str;
- int i, lim = 16;
- locs *gen = (locs *)ptr;
-
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s chans %d, outn: [",
- mus_name(ptr),
- gen->chans);
- str = (char *)malloc(STR_SIZE * sizeof(char));
-
- if (gen->outn)
- {
- if (gen->chans - 1 < lim) lim = gen->chans - 1;
- for (i = 0; i < lim; i++)
- {
- snprintf(str, STR_SIZE, "%.3f ", gen->outn[i]);
- if ((strlen(describe_buffer) + strlen(str)) < (DESCRIBE_BUFFER_SIZE - 16))
- strcat(describe_buffer, str);
- else break;
- }
- if (gen->chans - 1 > lim) strcat(describe_buffer, "...");
- snprintf(str, STR_SIZE, "%.3f]", gen->outn[gen->chans - 1]);
- strcat(describe_buffer, str);
- }
- else
- {
- strcat(describe_buffer, "nil!]");
- }
-
- if ((gen->rev_chans > 0) && (gen->revn))
- {
- strcat(describe_buffer, ", revn: [");
- lim = 16;
- if (gen->rev_chans - 1 < lim) lim = gen->rev_chans - 1;
- for (i = 0; i < lim; i++)
- {
- snprintf(str, STR_SIZE, "%.3f ", gen->revn[i]);
- if ((strlen(describe_buffer) + strlen(str)) < (DESCRIBE_BUFFER_SIZE - 16))
- strcat(describe_buffer, str);
- else break;
- }
- if (gen->rev_chans - 1 > lim) strcat(describe_buffer, "...");
- snprintf(str, STR_SIZE, "%.3f]", gen->revn[gen->rev_chans - 1]);
- strcat(describe_buffer, str);
- }
-
- snprintf(str, STR_SIZE, ", interp: %s", interp_type_to_string(gen->type));
- strcat(describe_buffer, str);
- free(str);
- return(describe_buffer);
- }
-
-
- static void free_locsig(mus_any *p)
- {
- locs *ptr = (locs *)p;
- if (ptr->outn)
- {
- free(ptr->outn);
- ptr->outn = NULL;
- }
- if (ptr->revn)
- {
- free(ptr->revn);
- ptr->revn = NULL;
- }
- if (ptr->outf) free(ptr->outf);
- ptr->outf = NULL;
- if (ptr->revf) free(ptr->revf);
- ptr->revf = NULL;
- ptr->outn_writer = NULL;
- ptr->revn_writer = NULL;
- ptr->chans = 0;
- ptr->rev_chans = 0;
- free(ptr);
- }
-
- static mus_any *locs_copy(mus_any *ptr)
- {
- locs *g, *p;
- int bytes;
- p = (locs *)ptr;
- g = (locs *)malloc(sizeof(locs));
- memcpy((void *)g, (void *)ptr, sizeof(locs));
- bytes = g->chans * sizeof(mus_float_t);
- if (p->outn)
- {
- g->outn = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outn), (void *)(p->outn), bytes);
- }
- if (p->outf)
- {
- g->outf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outf), (void *)(p->outf), bytes);
- }
- bytes = g->rev_chans * sizeof(mus_float_t);
- if (p->revn)
- {
- g->revn = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revn), (void *)(p->revn), bytes);
- }
- if (p->revf)
- {
- g->revf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revf), (void *)(p->revf), bytes);
- }
- return((mus_any *)g);
- }
-
- static mus_long_t locsig_length(mus_any *ptr) {return(((locs *)ptr)->chans);}
-
- static int locsig_channels(mus_any *ptr) {return(((locs *)ptr)->chans);}
-
- static mus_float_t *locsig_data(mus_any *ptr) {return(((locs *)ptr)->outn);}
-
- static mus_float_t *locsig_xcoeffs(mus_any *ptr) {return(((locs *)ptr)->revn);}
-
- mus_float_t *mus_locsig_outf(mus_any *ptr) {return(((locs *)ptr)->outf);} /* clm2xen.c */
- mus_float_t *mus_locsig_revf(mus_any *ptr) {return(((locs *)ptr)->revf);}
-
- void *mus_locsig_closure(mus_any *ptr) {return(((locs *)ptr)->closure);}
- static void *locsig_set_closure(mus_any *ptr, void *e) {((locs *)ptr)->closure = e; return(e);}
-
- void mus_locsig_set_detour(mus_any *ptr, void (*detour)(mus_any *ptr, mus_long_t val))
- {
- locs *gen = (locs *)ptr;
- gen->detour = detour;
- }
-
-
- static void locsig_reset(mus_any *ptr)
- {
- locs *gen = (locs *)ptr;
- if (gen->outn) memset((void *)(gen->outn), 0, gen->chans * sizeof(mus_float_t));
- if (gen->revn) memset((void *)(gen->revn), 0, gen->rev_chans * sizeof(mus_float_t));
- }
-
-
- static mus_float_t locsig_xcoeff(mus_any *ptr, int index)
- {
- locs *gen = (locs *)ptr;
- if (gen->revn)
- return(gen->revn[index]);
- return(0.0);
- }
-
-
- static mus_float_t locsig_set_xcoeff(mus_any *ptr, int index, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if (gen->revn)
- gen->revn[index] = val;
- return(val);
- }
-
-
- static mus_any *locsig_warned = NULL;
- /* these locsig error messages are a pain -- using the output pointer in the wan hope that
- * subsequent runs will use a different output generator.
- */
-
- mus_float_t mus_locsig_ref(mus_any *ptr, int chan)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->chans))
- return(gen->outn[chan]);
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_ref ": chan %d >= %d",
- chan, gen->chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(0.0);
- }
-
-
- mus_float_t mus_locsig_set(mus_any *ptr, int chan, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->chans))
- gen->outn[chan] = val;
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_set ": chan %d >= %d",
- chan, gen->chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(val);
- }
-
-
- mus_float_t mus_locsig_reverb_ref(mus_any *ptr, int chan)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->rev_chans))
- return(gen->revn[chan]);
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_reverb_ref ": chan %d, but this locsig has %d reverb chans",
- chan, gen->rev_chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(0.0);
- }
-
-
- mus_float_t mus_locsig_reverb_set(mus_any *ptr, int chan, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- if ((ptr) && (mus_is_locsig(ptr)))
- {
- if ((chan >= 0) &&
- (chan < gen->rev_chans))
- gen->revn[chan] = val;
- else
- {
- if (locsig_warned != gen->outn_writer)
- {
- mus_error(MUS_NO_SUCH_CHANNEL,
- S_locsig_reverb_set ": chan %d >= %d",
- chan, gen->rev_chans);
- locsig_warned = gen->outn_writer;
- }
- }
- }
- return(val);
- }
-
-
- static mus_float_t run_locsig(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_locsig(ptr, (mus_long_t)arg1, arg2);
- return(arg2);
- }
-
-
- static mus_any_class LOCSIG_CLASS = {
- MUS_LOCSIG,
- (char *)S_locsig,
- &free_locsig,
- &describe_locsig,
- &locsig_equalp,
- &locsig_data, 0,
- &locsig_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_locsig,
- MUS_OUTPUT,
- &mus_locsig_closure,
- &locsig_channels,
- 0, 0, 0, 0,
- &locsig_xcoeff, &locsig_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &locsig_xcoeffs, 0,
- &locsig_reset,
- &locsig_set_closure, /* the method name is set_environ (clm2xen.c) */
- &locs_copy
- };
-
-
- bool mus_is_locsig(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_LOCSIG));
- }
-
-
- static void mus_locsig_fill(mus_float_t *arr, int chans, mus_float_t degree, mus_float_t scaler, mus_interp_t type)
- {
- if (chans == 1)
- arr[0] = scaler;
- else
- {
- mus_float_t deg, pos, frac, degs_per_chan;
- int left, right;
- /* this used to check for degree < 0.0 first, but as Michael Klingbeil noticed, that
- * means that in the stereo case, the location can jump to 90 => click.
- */
- if (chans == 2)
- {
- /* there's no notion of a circle of speakers here, so we don't have to equate, for example, -90 and 270 */
- if (degree > 90.0)
- deg = 90.0;
- else
- {
- if (degree < 0.0)
- deg = 0.0;
- else deg = degree;
- }
- degs_per_chan = 90.0;
- }
- else
- {
- deg = fmod(degree, 360.0);
- if (deg < 0.0)
- {
- /* -0.0 is causing trouble when mus_float_t == float */
- if (deg < -0.0000001)
- deg += 360.0; /* C's fmod can return negative results when modulus is positive */
- else deg = 0.0;
- }
- degs_per_chan = 360.0 / chans;
- }
- pos = deg / degs_per_chan;
- left = (int)pos; /* floor(pos) */
- right = left + 1;
- if (right >= chans) right = 0;
- frac = pos - left;
- if (type == MUS_INTERP_LINEAR)
- {
- arr[left] = scaler * (1.0 - frac);
- arr[right] = scaler * frac;
- }
- else
- {
- mus_float_t ldeg, c, s;
- ldeg = M_PI_2 * (0.5 - frac);
- scaler *= sqrt(2.0) / 2.0;
- c = cos(ldeg);
- s = sin(ldeg);
- arr[left] = scaler * (c + s);
- arr[right] = scaler * (c - s);
- }
- }
- }
-
-
- static void mus_locsig_mono_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- }
-
-
- static void mus_locsig_mono(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outa_to_file(gen->revn_writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_stereo_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outb_to_file(gen->outn_writer, loc, val * gen->outn[1]);
- }
-
-
- static void mus_locsig_stereo(mus_any *ptr, mus_long_t loc, mus_float_t val) /* but mono rev */
- {
- locs *gen = (locs *)ptr;
- mus_outa_to_file(gen->outn_writer, loc, val * gen->outn[0]);
- mus_outb_to_file(gen->outn_writer, loc, val * gen->outn[1]);
- mus_outa_to_file(gen->revn_writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_any(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
- for (i = 0; i < gen->chans; i++)
- {
- gen->outf[i] = val * gen->outn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->outf[i]);
- }
- writer = (rdout *)(gen->revn_writer);
- for (i = 0; i < gen->rev_chans; i++)
- {
- gen->revf[i] = val * gen->revn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->revf[i]);
- }
- }
-
- static void mus_locsig_safe_mono_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- /* here we know in each safe case that obufs fits loc chans and the output gen is ok */
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->outn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- }
-
-
- static void mus_locsig_safe_mono(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->outn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->revn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_safe_stereo_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- writer->obufs[0][pos] += (val * gen->outn[0]);
- writer->obufs[1][pos] += (val * gen->outn[1]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- mus_outb_to_file((mus_any *)writer, loc, val * gen->outn[1]);
- }
- }
-
- static void mus_locsig_safe_stereo(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- writer->obufs[0][pos] += (val * gen->outn[0]);
- writer->obufs[1][pos] += (val * gen->outn[1]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- mus_outa_to_file((mus_any *)writer, loc, val * gen->outn[0]);
- mus_outb_to_file((mus_any *)writer, loc, val * gen->outn[1]);
- }
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- writer->obufs[0][loc - writer->data_start] += (val * gen->revn[0]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else mus_outa_to_file((mus_any *)writer, loc, val * gen->revn[0]);
- }
-
-
- static void mus_locsig_detour(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- /* here we let the closure data decide what to do with the output */
- locs *gen = (locs *)ptr;
- if (gen->detour)
- {
- int i;
- for (i = 0; i < gen->chans; i++)
- gen->outf[i] = val * gen->outn[i];
-
- for (i = 0; i < gen->rev_chans; i++)
- gen->revf[i] = val * gen->revn[i];
-
- (*(gen->detour))(ptr, loc);
- }
- }
-
- static void mus_locsig_any_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
- for (i = 0; i < gen->chans; i++)
- {
- gen->outf[i] = val * gen->outn[i];
- if (writer)
- mus_out_any_to_file((mus_any *)writer, loc, i, gen->outf[i]);
- }
- }
-
- static void mus_locsig_safe_any_no_reverb(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->chans; i++)
- writer->obufs[i][pos] += (val * gen->outn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->outn[i], i, (mus_any *)writer);
- }
- }
-
-
- static void mus_locsig_safe_any(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- int i;
- locs *gen = (locs *)ptr;
- rdout *writer = (rdout *)(gen->outn_writer);
-
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->chans; i++)
- writer->obufs[i][pos] += (val * gen->outn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->outn[i], i, (mus_any *)writer);
- }
-
- writer = (rdout *)(gen->revn_writer);
- if ((loc <= writer->data_end) &&
- (loc >= writer->data_start))
- {
- mus_long_t pos;
- pos = loc - writer->data_start;
- for (i = 0; i < gen->rev_chans; i++)
- writer->obufs[i][pos] += (val * gen->revn[i]);
- if (loc > writer->out_end)
- writer->out_end = loc;
- }
- else
- {
- for (i = 0; i < gen->rev_chans; i++)
- mus_safe_out_any_to_file(loc, val * gen->revn[i], i, (mus_any *)writer);
- }
- }
-
-
- mus_any *mus_make_locsig(mus_float_t degree, mus_float_t distance, mus_float_t reverb,
- int chans, mus_any *output, /* direct signal output */
- int rev_chans, mus_any *revput, /* reverb output */
- mus_interp_t type)
- {
- locs *gen;
- mus_float_t dist;
- if (chans <= 0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_locsig ": chans: %d", chans);
- return(NULL);
- }
- if (isnan(degree))
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_locsig ": degree: %f", degree);
- return(NULL);
- }
-
- gen = (locs *)calloc(1, sizeof(locs));
- gen->core = &LOCSIG_CLASS;
- gen->outf = (mus_float_t *)calloc(chans, sizeof(mus_float_t));
-
- gen->type = type;
- gen->reverb = reverb;
- gen->safe_output = false;
- if (distance > 1.0)
- dist = 1.0 / distance;
- else dist = 1.0;
-
- if (mus_is_output(output))
- gen->outn_writer = output;
- gen->chans = chans;
- gen->outn = (mus_float_t *)calloc(gen->chans, sizeof(mus_float_t));
- mus_locsig_fill(gen->outn, gen->chans, degree, dist, type);
-
- if (mus_is_output(revput))
- gen->revn_writer = revput;
- gen->rev_chans = rev_chans;
- if (gen->rev_chans > 0)
- {
- gen->revn = (mus_float_t *)calloc(gen->rev_chans, sizeof(mus_float_t));
- gen->revf = (mus_float_t *)calloc(gen->rev_chans, sizeof(mus_float_t));
- mus_locsig_fill(gen->revn, gen->rev_chans, degree, (reverb * sqrt(dist)), type);
- }
-
- /* now choose the output function based on chans, and reverb
- */
- if ((output == NULL) && (revput == NULL))
- gen->locsig_func = mus_locsig_detour;
- else
- {
- gen->locsig_func = mus_locsig_any;
-
- if ((mus_is_output(output)) &&
- (mus_out_any_is_safe(output)) &&
- (mus_channels(output) == chans))
- {
- if (rev_chans > 0)
- {
- if ((rev_chans == 1) &&
- (mus_is_output(revput)) &&
- (mus_out_any_is_safe(revput)) &&
- (mus_channels(revput) == 1))
- {
- gen->safe_output = true;
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_safe_mono; break;
- case 2: gen->locsig_func = mus_locsig_safe_stereo; break;
- default: gen->locsig_func = mus_locsig_safe_any; break;
- }
- }
- }
- else
- {
- gen->safe_output = true;
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_safe_mono_no_reverb; break;
- case 2: gen->locsig_func = mus_locsig_safe_stereo_no_reverb; break;
- default: gen->locsig_func = mus_locsig_safe_any_no_reverb; break;
- }
- }
- }
- else
- {
- if (rev_chans > 0)
- {
- if (rev_chans == 1)
- {
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_mono; break;
- case 2: gen->locsig_func = mus_locsig_stereo; break;
- default: gen->locsig_func = mus_locsig_any; break;
- }
- }
- }
- else
- {
- switch (chans)
- {
- case 1: gen->locsig_func = mus_locsig_mono_no_reverb; break;
- case 2: gen->locsig_func = mus_locsig_stereo_no_reverb; break;
- default: gen->locsig_func = mus_locsig_any_no_reverb; break;
- }
- }
- }
- }
- return((mus_any *)gen);
- }
-
- void mus_locsig(mus_any *ptr, mus_long_t loc, mus_float_t val)
- {
- locs *gen = (locs *)ptr;
- (*(gen->locsig_func))(ptr, loc, val);
- }
-
- int mus_locsig_channels(mus_any *ptr)
- {
- return(((locs *)ptr)->chans);
- }
-
- int mus_locsig_reverb_channels(mus_any *ptr)
- {
- return(((locs *)ptr)->rev_chans);
- }
-
-
- void mus_move_locsig(mus_any *ptr, mus_float_t degree, mus_float_t distance)
- {
- locs *gen = (locs *)ptr;
- mus_float_t dist;
-
- if (distance > 1.0)
- dist = 1.0 / distance;
- else dist = 1.0;
-
- if (gen->rev_chans > 0)
- {
- if (gen->rev_chans > 2)
- memset((void *)(gen->revn), 0, gen->rev_chans * sizeof(mus_float_t));
- mus_locsig_fill(gen->revn, gen->rev_chans, degree, (gen->reverb * sqrt(dist)), gen->type);
- }
- if (gen->chans > 2)
- memset((void *)(gen->outn), 0, gen->chans * sizeof(mus_float_t));
- mus_locsig_fill(gen->outn, gen->chans, degree, dist, gen->type);
- }
-
-
-
- /* ---------------- move-sound ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_any *outn_writer;
- mus_any *revn_writer;
- mus_float_t *outf, *revf;
- int out_channels, rev_channels;
- mus_long_t start, end;
- mus_any *doppler_delay, *doppler_env, *rev_env;
- mus_any **out_delays, **out_envs, **rev_envs;
- int *out_map;
- bool free_arrays, free_gens;
- void *closure;
- void (*detour)(mus_any *ptr, mus_long_t loc);
- } dloc;
-
-
- static bool move_sound_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
- int mus_move_sound_channels(mus_any *ptr) {return(((dloc *)ptr)->out_channels);}
- int mus_move_sound_reverb_channels(mus_any *ptr) {return(((dloc *)ptr)->rev_channels);}
- static mus_long_t move_sound_length(mus_any *ptr) {return(((dloc *)ptr)->out_channels);} /* need both because return types differ */
- static void move_sound_reset(mus_any *ptr) {}
-
- mus_float_t *mus_move_sound_outf(mus_any *ptr) {return(((dloc *)ptr)->outf);}
- mus_float_t *mus_move_sound_revf(mus_any *ptr) {return(((dloc *)ptr)->revf);}
-
- void *mus_move_sound_closure(mus_any *ptr) {return(((dloc *)ptr)->closure);}
- static void *move_sound_set_closure(mus_any *ptr, void *e) {((dloc *)ptr)->closure = e; return(e);}
-
- void mus_move_sound_set_detour(mus_any *ptr, void (*detour)(mus_any *ptr, mus_long_t val))
- {
- dloc *gen = (dloc *)ptr;
- gen->detour = detour;
- }
-
-
- static char *describe_move_sound(mus_any *ptr)
- {
- dloc *gen = (dloc *)ptr;
- char *dopdly = NULL, *dopenv = NULL, *revenv = NULL;
- char *outdlys = NULL, *outenvs = NULL, *revenvs = NULL;
- char *outmap = NULL;
- char *starts = NULL;
- char *str1 = NULL, *str2 = NULL, *str3 = NULL;
- char *allstr = NULL;
- int len;
-
- starts = mus_format("%s start: %lld, end: %lld, out chans %d, rev chans: %d",
- mus_name(ptr),
- gen->start,
- gen->end,
- gen->out_channels,
- gen->rev_channels);
- dopdly = mus_format("doppler %s", str1 = mus_describe(gen->doppler_delay));
- dopenv = mus_format("doppler %s", str2 = mus_describe(gen->doppler_env));
- revenv = mus_format("global reverb %s", str3 = mus_describe(gen->rev_env));
- outdlys = clm_array_to_string(gen->out_delays, gen->out_channels, "out_delays", " ");
- outenvs = clm_array_to_string(gen->out_envs, gen->out_channels, "out_envs", " ");
- revenvs = clm_array_to_string(gen->rev_envs, gen->rev_channels, "rev_envs", " ");
- outmap = int_array_to_string(gen->out_map, gen->out_channels, "out_map");
-
- len = 64 + strlen(starts) + strlen(dopdly) + strlen(dopenv) + strlen(revenv) +
- strlen(outdlys) + strlen(outenvs) + strlen(revenvs) + strlen(outmap);
- allstr = (char *)malloc(len * sizeof(char));
- snprintf(allstr, len, "%s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n free: arrays: %s, gens: %s\n",
- starts, dopdly, dopenv, revenv, outdlys, outenvs, revenvs, outmap,
- (gen->free_arrays) ? "true" : "false",
- (gen->free_gens) ? "true" : "false");
- if (str1) free(str1);
- if (str2) free(str2);
- if (str3) free(str3);
- free(starts);
- free(dopdly);
- free(dopenv);
- free(revenv);
- free(outdlys);
- free(outenvs);
- free(revenvs);
- free(outmap);
- return(allstr);
- }
-
-
- static void free_move_sound(mus_any *p)
- {
- dloc *ptr = (dloc *)p;
- if (ptr->free_gens)
- {
- int i;
- /* free everything except outer arrays and IO stuff */
- if (ptr->doppler_delay) mus_free(ptr->doppler_delay);
- if (ptr->doppler_env) mus_free(ptr->doppler_env);
- if (ptr->rev_env) mus_free(ptr->rev_env);
- if (ptr->out_delays)
- for (i = 0; i < ptr->out_channels; i++)
- if (ptr->out_delays[i]) mus_free(ptr->out_delays[i]);
- if (ptr->out_envs)
- for (i = 0; i < ptr->out_channels; i++)
- if (ptr->out_envs[i]) mus_free(ptr->out_envs[i]);
- if (ptr->rev_envs)
- for (i = 0; i < ptr->rev_channels; i++)
- if (ptr->rev_envs[i]) mus_free(ptr->rev_envs[i]);
- }
-
- if (ptr->free_arrays)
- {
- /* free outer arrays */
- if (ptr->out_envs) {free(ptr->out_envs); ptr->out_envs = NULL;}
- if (ptr->rev_envs) {free(ptr->rev_envs); ptr->rev_envs = NULL;}
- if (ptr->out_delays) {free(ptr->out_delays); ptr->out_delays = NULL;}
- if (ptr->out_map) free(ptr->out_map);
- }
-
- /* we created these in make_move_sound, so it should always be safe to free them */
- if (ptr->outf) free(ptr->outf);
- if (ptr->revf) free(ptr->revf);
- free(ptr);
- }
-
- static mus_any *dloc_copy(mus_any *ptr)
- {
- dloc *g, *p;
- int i, bytes;
- p = (dloc *)ptr;
- g = (dloc *)malloc(sizeof(dloc));
- memcpy((void *)g, (void *)ptr, sizeof(dloc));
-
- if (p->outf)
- {
- bytes = p->out_channels * sizeof(mus_float_t);
- g->outf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->outf), (void *)(p->outf), bytes);
- }
- if (p->revf)
- {
- bytes = p->rev_channels * sizeof(mus_float_t);
- g->revf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->revf), (void *)(p->revf), bytes);
- }
-
- g->free_arrays = true;
- g->free_gens = true;
- if (p->doppler_delay) g->doppler_delay = mus_copy(p->doppler_delay);
- if (p->doppler_env) g->doppler_env = mus_copy(p->doppler_env);
- if (p->rev_env) g->rev_env = mus_copy(p->rev_env);
- if (p->out_envs)
- {
- g->out_envs = (mus_any **)malloc(p->out_channels * sizeof(mus_any *));
- for (i = 0; i < p->out_channels; i++) g->out_envs[i] = mus_copy(p->out_envs[i]);
- }
- if (p->rev_envs)
- {
- g->rev_envs = (mus_any **)malloc(p->rev_channels * sizeof(mus_any *));
- for (i = 0; i < p->rev_channels; i++) g->rev_envs[i] = mus_copy(p->rev_envs[i]);
- }
- if (p->out_delays)
- {
- g->out_delays = (mus_any **)malloc(p->out_channels * sizeof(mus_any *));
- for (i = 0; i < p->out_channels; i++) g->out_delays[i] = mus_copy(p->out_delays[i]);
- }
- if (p->out_map)
- {
- bytes = p->out_channels * sizeof(int);
- g->out_map = (int *)malloc(bytes);
- memcpy((void *)(g->out_map), (void *)(p->out_map), bytes);
- }
-
- return((mus_any *)g);
- }
-
- bool mus_is_move_sound(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_MOVE_SOUND));
- }
-
-
- mus_float_t mus_move_sound(mus_any *ptr, mus_long_t loc, mus_float_t uval)
- {
- dloc *gen = (dloc *)ptr;
- mus_float_t val;
- int chan;
-
- if (loc > gen->end) val = 0.0; else val = uval;
-
- /* initial silence */
- if (loc < gen->start)
- {
- mus_delay_unmodulated(gen->doppler_delay, val);
- /* original calls out_any here with 0.0 -- a no-op */
- return(val);
- }
-
- /* doppler */
- if (gen->doppler_delay)
- val = mus_delay(gen->doppler_delay, val, mus_env(gen->doppler_env));
-
- /* direct signal */
- for (chan = 0; chan < gen->out_channels; chan++)
- {
- mus_float_t sample;
- sample = val * mus_env(gen->out_envs[chan]);
- if (gen->out_delays[chan])
- sample = mus_delay_unmodulated(gen->out_delays[chan], sample);
- gen->outf[gen->out_map[chan]] = sample;
- }
-
- /* reverb */
- if ((gen->rev_env) &&
- (gen->revf))
- {
- val *= mus_env(gen->rev_env);
- if (gen->rev_envs)
- {
- if (gen->rev_channels == 1)
- gen->revf[0] = val * mus_env(gen->rev_envs[0]);
- else
- {
- for (chan = 0; chan < gen->rev_channels; chan++)
- gen->revf[gen->out_map[chan]] = val * mus_env(gen->rev_envs[chan]);
- }
- }
- else gen->revf[0] = val;
-
- if (gen->revn_writer)
- mus_frample_to_file(gen->revn_writer, loc, gen->revf);
- }
-
- /* file output */
- if (gen->outn_writer)
- mus_frample_to_file(gen->outn_writer, loc, gen->outf);
-
- if (gen->detour)
- (*(gen->detour))(ptr, loc);
- return(uval);
- }
-
-
- static mus_float_t run_move_sound(mus_any *ptr, mus_float_t arg1, mus_float_t arg2)
- {
- mus_move_sound(ptr, (mus_long_t)arg1, arg2);
- return(arg2);
- }
-
-
- static mus_any_class MOVE_SOUND_CLASS = {
- MUS_MOVE_SOUND,
- (char *)S_move_sound,
- &free_move_sound,
- &describe_move_sound,
- &move_sound_equalp,
- 0, 0,
- &move_sound_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_move_sound,
- MUS_OUTPUT,
- &mus_move_sound_closure,
- &mus_move_sound_channels,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &move_sound_reset,
- &move_sound_set_closure,
- &dloc_copy
- };
-
-
- mus_any *mus_make_move_sound(mus_long_t start, mus_long_t end, int out_channels, int rev_channels,
- mus_any *doppler_delay, mus_any *doppler_env, mus_any *rev_env,
- mus_any **out_delays, mus_any **out_envs, mus_any **rev_envs,
- int *out_map, mus_any *output, mus_any *revput, bool free_arrays, bool free_gens)
- {
- /* most of these args come to us in a list at the lisp/xen level ("dlocs" struct is actually a list)
- * so the make-move-sound function in lisp/xen is (make-move-sound dloc-list output revout)
- * where the trailing args mimic locsig.
- */
- dloc *gen;
- if (out_channels <= 0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_move_sound ": out chans: %d", out_channels);
- return(NULL);
- }
- gen = (dloc *)calloc(1, sizeof(dloc));
- gen->core = &MOVE_SOUND_CLASS;
-
- gen->start = start;
- gen->end = end;
- gen->out_channels = out_channels;
- gen->rev_channels = rev_channels;
- gen->doppler_delay = doppler_delay;
- gen->doppler_env = doppler_env;
- gen->rev_env = rev_env;
- gen->out_delays = out_delays;
- gen->out_envs = out_envs;
- gen->rev_envs = rev_envs;
- gen->out_map = out_map;
-
- /* default is to free only what we make ourselves */
- gen->free_gens = free_gens;
- gen->free_arrays = free_arrays;
-
- gen->outf = (mus_float_t *)calloc(out_channels, sizeof(mus_float_t));
- if (mus_is_output(output))
- gen->outn_writer = output;
-
- if (rev_channels > 0)
- {
- if (mus_is_output(revput))
- gen->revn_writer = revput;
- gen->revf = (mus_float_t *)calloc(rev_channels, sizeof(mus_float_t));
- }
-
- return((mus_any *)gen);
- }
-
-
-
- /* ---------------- src ---------------- */
-
- /* sampling rate conversion */
- /* taken from sweep_srate.c of Perry Cook. To quote Perry:
- *
- * 'The conversion is performed by sinc interpolation.
- * J. O. Smith and P. Gossett, "A Flexible Sampling-Rate Conversion Method,"
- * Proc. of the IEEE Conference on Acoustics, Speech, and Signal Processing, San Diego, CA, March, 1984.
- * There are essentially two cases, one where the conversion factor
- * is less than one, and the sinc table is used as is yielding a sound
- * which is band limited to the 1/2 the new sampling rate (we don't
- * want to create bandwidth where there was none). The other case
- * is where the conversion factor is greater than one and we 'warp'
- * the sinc table to make the final cutoff equal to the original sampling
- * rate /2. Warping the sinc table is based on the similarity theorem
- * of the time and frequency domain, stretching the time domain (sinc
- * table) causes shrinking in the frequency domain.'
- *
- * we also scale the amplitude if interpolating to take into account the broadened sinc
- * this means that isolated pulses get scaled by 1/src, but that's a dumb special case
- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*feeder)(void *arg, int direction);
- mus_float_t (*block_feeder)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- mus_float_t x;
- mus_float_t incr, width_1;
- int width, lim, start, sinc4;
- int len;
- mus_float_t *data, *sinc_table, *coeffs;
- void *closure;
- } sr;
-
-
- #define SRC_SINC_DENSITY 2000
- #define SRC_SINC_WIDTH 10
- #define SRC_SINC_WINDOW_SIZE 8000
-
- static mus_float_t **sinc_tables = NULL;
- static int *sinc_widths = NULL;
- static int sincs = 0;
- static mus_float_t *sinc = NULL, *sinc_window = NULL;
- static int sinc_size = 0;
-
- void mus_clear_sinc_tables(void)
- {
- if (sincs)
- {
- int i;
- for (i = 0; i < sincs; i++)
- if (sinc_tables[i])
- free(sinc_tables[i]);
- free(sinc_tables);
- sinc_tables = NULL;
-
- free(sinc_window);
- sinc_window = NULL;
- free(sinc_widths);
- sinc_widths = NULL;
- sincs = 0;
- }
- }
-
-
- static int init_sinc_table(int width)
- {
- int i, size, padded_size, loc;
- mus_float_t win_freq, win_phase;
- #if HAVE_SINCOS
- double sn, snp, cs, csp;
- #endif
-
- if (width > sinc_size)
- {
- int old_end;
- mus_float_t sinc_phase, sinc_freq;
- if (sinc_size == 0)
- old_end = 1;
- else old_end = sinc_size * SRC_SINC_DENSITY + 4;
- padded_size = width * SRC_SINC_DENSITY + 4;
- if (sinc_size == 0)
- {
- sinc = (mus_float_t *)malloc(padded_size * sizeof(mus_float_t));
- sinc[0] = 1.0;
- }
- else sinc = (mus_float_t *)realloc(sinc, padded_size * sizeof(mus_float_t));
- sinc_size = width;
- sinc_freq = M_PI / (mus_float_t)SRC_SINC_DENSITY;
- sinc_phase = old_end * sinc_freq;
- #if HAVE_SINCOS
- sincos(sinc_freq, &sn, &cs);
- if (old_end == 1)
- {
- sinc[1] = sin(sinc_phase) / (2.0 * sinc_phase);
- old_end++;
- sinc_phase += sinc_freq;
- }
- for (i = old_end; i < padded_size;)
- {
- sincos(sinc_phase, &snp, &csp);
- sinc[i] = snp / (2.0 * sinc_phase);
- i++;
- sinc_phase += sinc_freq;
- sinc[i] = (snp * cs + csp * sn) / (2.0 * sinc_phase);
- i++;
- sinc_phase += sinc_freq;
- }
- #else
- for (i = old_end; i < padded_size; i++, sinc_phase += sinc_freq)
- sinc[i] = sin(sinc_phase) / (2.0 * sinc_phase);
- #endif
- }
-
- for (i = 0; i < sincs; i++)
- if (sinc_widths[i] == width)
- return(i);
-
- if (sincs == 0)
- {
- mus_float_t ph, incr;
- incr = M_PI / SRC_SINC_WINDOW_SIZE;
- sinc_window = (mus_float_t *)calloc(SRC_SINC_WINDOW_SIZE + 16, sizeof(mus_float_t));
- for (i = 0, ph = 0.0; i < SRC_SINC_WINDOW_SIZE; i++, ph += incr)
- sinc_window[i] = 1.0 + cos(ph);
-
- sinc_tables = (mus_float_t **)calloc(8, sizeof(mus_float_t *));
- sinc_widths = (int *)calloc(8, sizeof(int));
- sincs = 8;
- loc = 0;
- }
- else
- {
- loc = -1;
- for (i = 0; i < sincs; i++)
- if (sinc_widths[i] == 0)
- {
- loc = i;
- break;
- }
- if (loc == -1)
- {
- sinc_tables = (mus_float_t **)realloc(sinc_tables, (sincs + 8) * sizeof(mus_float_t *));
- sinc_widths = (int *)realloc(sinc_widths, (sincs + 8) * sizeof(int));
- for (i = sincs; i < (sincs + 8); i++)
- {
- sinc_widths[i] = 0;
- sinc_tables[i] = NULL;
- }
- loc = sincs;
- sincs += 8;
- }
- }
-
- sinc_widths[loc] = width;
- size = width * SRC_SINC_DENSITY;
- padded_size = size + 4;
- win_freq = (mus_float_t)SRC_SINC_WINDOW_SIZE / (mus_float_t)size;
-
- sinc_tables[loc] = (mus_float_t *)malloc(padded_size * 2 * sizeof(mus_float_t));
- sinc_tables[loc][padded_size] = 1.0;
-
- for (i = 1, win_phase = win_freq; i < padded_size; i++, win_phase += win_freq)
- {
- mus_float_t val;
- val = sinc[i] * sinc_window[(int)win_phase];
- sinc_tables[loc][padded_size + i] = val;
- sinc_tables[loc][padded_size - i] = val;
- }
-
- return(loc);
- }
-
-
- bool mus_is_src(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SRC));
- }
-
-
- static void free_src_gen(mus_any *srptr)
- {
- sr *srp = (sr *)srptr;
- if (srp->data) free(srp->data);
- if (srp->coeffs) free(srp->coeffs);
- free(srp);
- }
-
- static mus_any *sr_copy(mus_any *ptr)
- {
- sr *g, *p;
- int bytes;
-
- p = (sr *)ptr;
- g = (sr *)malloc(sizeof(sr));
- memcpy((void *)g, (void *)ptr, sizeof(sr));
-
- bytes = (2 * g->lim + 1) * sizeof(mus_float_t);
- g->data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->data), (void *)(p->data), bytes);
-
- if (p->coeffs)
- {
- bytes = p->lim * sizeof(mus_float_t);
- g->coeffs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->coeffs), (void *)(p->coeffs), bytes);
- }
- return((mus_any *)g);
- }
-
- static bool src_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_src(mus_any *ptr)
- {
- sr *gen = (sr *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s width: %d, x: %.3f, incr: %.3f, sinc table len: %d",
- mus_name(ptr),
- gen->width, gen->x, gen->incr, gen->len);
- return(describe_buffer);
- }
-
-
- static mus_long_t src_length(mus_any *ptr) {return(((sr *)ptr)->width);}
- static mus_float_t run_src_gen(mus_any *srptr, mus_float_t sr_change, mus_float_t unused) {return(mus_src(srptr, sr_change, NULL));}
-
- static void *src_closure(mus_any *rd) {return(((sr *)rd)->closure);}
- static void *src_set_closure(mus_any *rd, void *e) {((sr *)rd)->closure = e; return(e);}
-
- static mus_float_t src_increment(mus_any *rd) {return(((sr *)rd)->incr);}
- static mus_float_t src_set_increment(mus_any *rd, mus_float_t val) {((sr *)rd)->incr = val; return(val);}
-
- static mus_float_t *src_sinc_table(mus_any *rd) {return(((sr *)rd)->sinc_table);}
-
- static void src_reset(mus_any *ptr)
- {
- sr *gen = (sr *)ptr;
- memset((void *)(gen->data), 0, (gen->lim + 1) * sizeof(mus_float_t));
- gen->x = 0.0;
- /* center the data if possible */
- if (gen->feeder)
- {
- int i, dir = 1;
- if (gen->incr < 0.0) dir = -1;
- for (i = gen->width - 1; i < gen->lim; i++)
- gen->data[i] = gen->feeder(gen->closure, dir);
- }
- gen->start = 0;
- }
-
- void mus_src_init(mus_any *ptr)
- {
- sr *srp = (sr *)ptr;
- if (srp->feeder)
- {
- int i, dir = 1;
- if (srp->incr < 0.0) dir = -1;
- for (i = srp->width - 1; i < srp->lim; i++)
- {
- srp->data[i] = srp->feeder(srp->closure, dir);
- srp->data[i + srp->lim] = srp->data[i];
- }
- }
- }
-
- static mus_any_class SRC_CLASS = {
- MUS_SRC,
- (char *)S_src,
- &free_src_gen,
- &describe_src,
- &src_equalp,
- &src_sinc_table, 0,
- &src_length, /* sinc width actually */
- 0,
- 0, 0, 0, 0,
- &fallback_scaler, 0,
- &src_increment,
- &src_set_increment,
- &run_src_gen,
- MUS_NOT_SPECIAL,
- &src_closure,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &src_reset,
- &src_set_closure,
- &sr_copy
- };
-
-
- mus_any *mus_make_src_with_init(mus_float_t (*input)(void *arg, int direction), mus_float_t srate, int width, void *closure, void (*init)(void *p, mus_any *g))
- {
- /* besides 1, 2, .5, other common cases: 1.5, 3
- */
-
- if (fabs(srate) > MUS_MAX_CLM_SRC)
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_src ": srate arg invalid: %f", srate);
- else
- {
- if ((width < 0) || (width > MUS_MAX_CLM_SINC_WIDTH))
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_src ": width arg invalid: %d", width);
- else
- {
- sr *srp;
- int wid, loc;
-
- if (width <= 0) width = SRC_SINC_WIDTH;
- if (width < (int)(fabs(srate) * 2))
- wid = (int)(ceil(fabs(srate)) * 2);
- else wid = width;
- if ((srate == 2.0) &&
- ((wid & 1) != 0))
- wid++;
-
- srp = (sr *)calloc(1, sizeof(sr));
- srp->core = &SRC_CLASS;
- srp->x = 0.0;
- srp->feeder = input;
- srp->block_feeder = NULL;
- srp->closure = closure;
- srp->incr = srate;
- srp->width = wid;
- srp->lim = 2 * wid;
- srp->start = 0;
- srp->len = wid * SRC_SINC_DENSITY;
- srp->width_1 = 1.0 - wid;
- srp->sinc4 = srp->width * SRC_SINC_DENSITY + 4;
- srp->data = (mus_float_t *)calloc(2 * srp->lim + 1, sizeof(mus_float_t));
- loc = init_sinc_table(wid);
- srp->sinc_table = sinc_tables[loc];
- srp->coeffs = NULL;
-
- if (init)
- init(closure, (mus_any *)srp);
-
- if (srp->feeder)
- {
- int i, dir = 1;
- if (srate < 0.0) dir = -1;
- for (i = wid - 1; i < srp->lim; i++)
- {
- srp->data[i] = srp->feeder(closure, dir);
- srp->data[i + srp->lim] = srp->data[i];
- }
- /* was i = 0 here but we want the incoming data centered */
- }
- return((mus_any *)srp);
- }
- }
- return(NULL);
- }
-
- mus_any *mus_make_src(mus_float_t (*input)(void *arg, int direction), mus_float_t srate, int width, void *closure)
- {
- return(mus_make_src_with_init(input, srate, width, closure, NULL));
- }
-
- mus_float_t mus_src(mus_any *srptr, mus_float_t sr_change, mus_float_t (*input)(void *arg, int direction))
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum, zf, srx, factor;
- int lim, loc, xi;
- bool int_ok;
- mus_float_t *data, *sinc_table;
-
- lim = srp->lim;
- loc = srp->start;
- data = srp->data;
- sinc_table = srp->sinc_table;
-
- if (sr_change > MUS_MAX_CLM_SRC)
- sr_change = MUS_MAX_CLM_SRC;
- else
- {
- if (sr_change < -MUS_MAX_CLM_SRC)
- sr_change = -MUS_MAX_CLM_SRC;
- }
- srx = srp->incr + sr_change;
-
- if (srp->x >= 1.0)
- {
- int i, fsx, dir = 1;
-
- if (srx < 0.0) dir = -1;
- fsx = (int)(srp->x);
- srp->x -= fsx;
-
- if (input) {srp->feeder = input; srp->block_feeder = NULL;}
-
- data[loc] = srp->feeder(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
-
- for (i = 1; i < fsx; i++)
- {
- /* there are two copies of the circular data buffer back-to-back so that we can
- * run the convolution below without worrying about the buffer end.
- */
- data[loc] = srp->feeder(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
- }
- srp->start = loc; /* next time around we start here */
- }
-
- /* now loc = beginning of data */
-
- /* if (srx == 0.0) srx = 0.01; */ /* can't decide about this ... */
- if (srx < 0.0) srx = -srx;
- if (srx > 1.0)
- {
- factor = 1.0 / srx;
- /* this is not exact since we're sampling the sinc and so on, but it's close over a wide range */
- zf = factor * (mus_float_t)SRC_SINC_DENSITY;
- xi = (int)(zf + 0.5);
-
- /* (let ((e (make-env '(0 1 1 1.1) :length 11))) (src-channel e))
- */
- /* we're comparing adding xi lim times to zf and if there's no difference, using the int case */
- if (fabs((xi - zf) * lim) > 2.0) int_ok = false; else int_ok = true;
- }
- else
- {
- factor = 1.0;
- zf = (mus_float_t)SRC_SINC_DENSITY;
- xi = SRC_SINC_DENSITY;
- int_ok = true;
- }
-
- sum = 0.0;
- if (int_ok)
- {
- int sinc_loc, sinc_incr, last, last10, xs;
-
- xs = (int)(zf * (srp->width_1 - srp->x));
- sinc_loc = xs + srp->sinc4;
- sinc_incr = xi;
- last = loc + lim;
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[sinc_loc];
- }
- else
- {
- mus_float_t sinc_loc, sinc_incr, x;
- int last, last10;
-
- x = zf * (srp->width_1 - srp->x);
- sinc_loc = x + srp->sinc4;
- sinc_incr = zf;
- last = loc + lim;
-
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[(int)sinc_loc];
- }
-
- srp->x += srx;
- return(sum * factor);
- }
-
-
- void mus_src_to_buffer(mus_any *srptr, mus_float_t (*input)(void *arg, int direction), mus_float_t *out_data, mus_long_t dur)
- {
- /* sr_change = 0.0
- */
- sr *srp = (sr *)srptr;
- mus_float_t sum, x, zf, srx, factor, sincx, srpx;
- int lim, i, xi, xs, dir = 1;
- bool int_ok;
- mus_long_t k;
- mus_float_t *data, *sinc_table;
-
- lim = srp->lim;
- sincx = (mus_float_t)SRC_SINC_DENSITY;
- data = srp->data;
- sinc_table = srp->sinc_table;
- srx = srp->incr;
- srpx = srp->x;
- if (srx < 0.0)
- {
- dir = -1;
- srx = -srx;
- }
- if (srx > 1.0)
- {
- factor = 1.0 / srx;
- /* this is not exact since we're sampling the sinc and so on, but it's close over a wide range */
- zf = factor * sincx;
- xi = (int)zf;
- if (fabs((xi - zf) * lim) > 2.0) int_ok = false; else int_ok = true;
- }
- else
- {
- factor = 1.0;
- zf = sincx;
- xi = SRC_SINC_DENSITY;
- int_ok = true;
- }
-
- for (k = 0; k < dur; k++)
- {
- int loc;
- loc = srp->start;
- if (srpx >= 1.0)
- {
- int fsx;
- /* modf here is very slow??! */
- fsx = (int)srpx;
- srpx -= fsx;
-
- data[loc] = input(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
-
- for (i = 1; i < fsx; i++)
- {
- /* there are two copies of the circular data buffer back-to-back so that we can
- * run the convolution below without worrying about the buffer end.
- */
- data[loc] = input(srp->closure, dir);
- data[loc + lim] = data[loc];
- loc++;
- if (loc == lim) loc = 0;
- }
- srp->start = loc; /* next time around we start here */
- }
-
- sum = 0.0;
- if (int_ok)
- {
- int sinc_loc, sinc_incr, last, last10;
-
- xs = (int)(zf * (srp->width_1 - srpx));
- sinc_loc = xs + srp->sinc4;
- sinc_incr = xi;
- last = loc + lim;
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[sinc_loc];
- }
- else
- {
- mus_float_t sinc_loc, sinc_incr;
- int last, last10;
-
- x = zf * (srp->width_1 - srpx);
- sinc_loc = x + srp->sinc4;
- sinc_incr = zf;
- last = loc + lim;
-
- last10 = last - 10;
-
- while (loc <= last10)
- {
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- sum += data[loc++] * sinc_table[(int)sinc_loc]; sinc_loc += sinc_incr;
- }
- for (; loc < last; loc++, sinc_loc += sinc_incr)
- sum += data[loc] * sinc_table[(int)sinc_loc];
- }
- srpx += srx;
- out_data[k] = sum * factor;
- }
- srp->x = srpx;
- }
-
-
- /* it was a cold, rainy day...
- * and on an even colder day, I changed this to use a circular data buffer, rather than memmove
- * then changed yet again to use straight buffers
- */
-
- mus_float_t *mus_src_20(mus_any *srptr, mus_float_t *in_data, mus_long_t dur)
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum;
- int lim, i, width, wid1, wid10, xs, xi;
- mus_long_t k, dur2;
- mus_float_t *out_data, *ldata, *coeffs;
-
- dur2 = dur / 2 + 1;
- if ((dur & 1) != 0) dur2++;
- out_data = (mus_float_t *)malloc(dur2 * sizeof(mus_float_t));
-
- lim = srp->lim; /* 2 * width so it's even */
- width = srp->width;
-
- coeffs = (mus_float_t *)malloc(lim * sizeof(mus_float_t));
- if ((width & 1) != 0)
- xs = (int)((2 + width) * (SRC_SINC_DENSITY / 2)) + 4; /* Humph -- looks like crap -- maybe if odd width use the real one above, or insist on even width */
- else xs = (int)((1 + width) * (SRC_SINC_DENSITY / 2)) + 4;
- xi = SRC_SINC_DENSITY; /* skip a location (coeff=0.0) */
-
- for (i = 0; i < width; i++, xs += xi)
- coeffs[i] = srp->sinc_table[xs];
-
- for (i = 0; i < lim; i++)
- in_data[i] = srp->data[i];
-
- ldata = (mus_float_t *)in_data;
- wid10 = width - 10;
- wid1 = width - 1;
-
- for (k = 0; k < dur2; k++, ldata += 2)
- {
- int j;
- sum = ldata[wid1];
- i = 0;
- j = 0;
- while (i <= wid10)
- {
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- sum += (ldata[j] * coeffs[i++]); j += 2;
- }
- for (; i < width; i++, j += 2)
- sum += (ldata[j] * coeffs[i]);
- out_data[k] = sum * 0.5;
- }
-
- free(coeffs);
- return(out_data);
- }
-
-
- mus_float_t *mus_src_05(mus_any *srptr, mus_float_t *in_data, mus_long_t dur)
- {
- sr *srp = (sr *)srptr;
- mus_float_t sum;
- int lim, i, width, wid1, wid10, xs, xi;
- mus_long_t k, dur2;
- mus_float_t *out_data, *ldata, *coeffs;
-
- dur2 = dur * 2;
- out_data = (mus_float_t *)malloc((dur2 + 1) * sizeof(mus_float_t));
- out_data[dur2] = 0.0;
-
- lim = srp->lim;
- width = srp->width;
-
- coeffs = (mus_float_t *)malloc(lim * sizeof(mus_float_t));
- xs = (SRC_SINC_DENSITY / 2) + 4;
- xi = SRC_SINC_DENSITY;
-
- for (i = 0; i < lim; i++, xs += xi)
- coeffs[i] = srp->sinc_table[xs];
-
- for (i = 0; i < lim; i++)
- in_data[i] = srp->data[i];
-
- ldata = (mus_float_t *)in_data;
- wid10 = lim - 10;
- wid1 = width - 1;
-
- for (k = 0; k < dur2; k += 2)
- {
- out_data[k] = ldata[wid1];
-
- sum = 0.0;
- i = 0;
- while (i <= wid10)
- {
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- sum += (ldata[i] * coeffs[i]); i++;
- }
- for (; i < lim; i++)
- sum += (ldata[i] * coeffs[i]);
- out_data[k + 1] = sum;
-
- ldata++;
- }
-
- free(coeffs);
- return(out_data);
- }
-
-
-
-
- /* ---------------- granulate ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*rd)(void *arg, int direction);
- mus_float_t (*block_rd)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- int s20;
- int s50;
- int rmp;
- mus_float_t amp;
- int cur_out;
- int input_hop;
- int ctr;
- int output_hop;
- mus_float_t *out_data; /* output buffer */
- int out_data_len;
- mus_float_t *in_data; /* input buffer */
- int in_data_len;
- void *closure;
- int (*edit)(void *closure);
- mus_float_t *grain; /* grain data */
- int grain_len;
- bool first_samp;
- unsigned long randx; /* gen-local random number seed */
- } grn_info;
-
-
- bool mus_is_granulate(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_GRANULATE));
- }
-
-
- static bool granulate_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_granulate(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s expansion: %.3f (%d/%d), scaler: %.3f, length: %.3f secs (%d samps), ramp: %.3f",
- mus_name(ptr),
- (mus_float_t)(gen->output_hop) / (mus_float_t)(gen->input_hop),
- gen->input_hop, gen->output_hop,
- gen->amp,
- (mus_float_t)(gen->grain_len) / (mus_float_t)sampling_rate, gen->grain_len,
- (mus_float_t)(gen->rmp) / (mus_float_t)sampling_rate);
- return(describe_buffer);
- }
-
-
- static void free_granulate(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- if (gen->out_data) free(gen->out_data);
- if (gen->in_data) free(gen->in_data);
- if (gen->grain) free(gen->grain);
- free(gen);
- }
-
- static mus_any *grn_info_copy(mus_any *ptr)
- {
- grn_info *g, *p;
- int bytes;
-
- p = (grn_info *)ptr;
- g = (grn_info *)malloc(sizeof(grn_info));
- memcpy((void *)g, (void *)ptr, sizeof(grn_info));
-
- bytes = g->out_data_len * sizeof(mus_float_t);
- g->out_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->out_data), (void *)(p->out_data), bytes);
-
- bytes = g->in_data_len * sizeof(mus_float_t);
- g->in_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->in_data), (void *)(p->in_data), bytes);
- g->grain = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->grain), (void *)(p->grain), bytes);
-
- return((mus_any *)g);
- }
-
- static mus_long_t grn_length(mus_any *ptr) {return(((grn_info *)ptr)->grain_len);}
-
- static mus_long_t grn_set_length(mus_any *ptr, mus_long_t val)
- {
- grn_info *gen = ((grn_info *)ptr);
- if ((val > 0) && (val < gen->out_data_len))
- gen->grain_len = (int)val; /* larger -> segfault */
- return(gen->grain_len);
- }
-
- static mus_float_t grn_scaler(mus_any *ptr) {return(((grn_info *)ptr)->amp);}
- static mus_float_t grn_set_scaler(mus_any *ptr, mus_float_t val) {((grn_info *)ptr)->amp = val; return(val);}
-
- static mus_float_t grn_frequency(mus_any *ptr) {return(((mus_float_t)((grn_info *)ptr)->output_hop) / (mus_float_t)sampling_rate);}
- static mus_float_t grn_set_frequency(mus_any *ptr, mus_float_t val) {((grn_info *)ptr)->output_hop = (int)((mus_float_t)sampling_rate * val); return(val);}
-
- static void *grn_closure(mus_any *rd) {return(((grn_info *)rd)->closure);}
- static void *grn_set_closure(mus_any *rd, void *e) {((grn_info *)rd)->closure = e; return(e);}
-
- static mus_float_t grn_increment(mus_any *ptr)
- {
- grn_info *gen = ((grn_info *)ptr);
- return(((mus_float_t)(gen->output_hop)) / ((mus_float_t)(gen->input_hop)));
- }
-
- static mus_float_t grn_set_increment(mus_any *ptr, mus_float_t val)
- {
- grn_info *gen = ((grn_info *)ptr);
- if (val != 0.0)
- gen->input_hop = (int)(gen->output_hop / val);
- return(val);
- }
-
- static mus_long_t grn_hop(mus_any *ptr) {return(((grn_info *)ptr)->output_hop);}
- static mus_long_t grn_set_hop(mus_any *ptr, mus_long_t val) {((grn_info *)ptr)->output_hop = (int)val; return(val);}
-
- static mus_long_t grn_ramp(mus_any *ptr) {return(((grn_info *)ptr)->rmp);}
-
- static mus_long_t grn_set_ramp(mus_any *ptr, mus_long_t val)
- {
- grn_info *gen = (grn_info *)ptr;
- if (val < (gen->grain_len * .5))
- gen->rmp = (int)val;
- return(val);
- }
-
- static mus_float_t *granulate_data(mus_any *ptr) {return(((grn_info *)ptr)->grain);}
- int mus_granulate_grain_max_length(mus_any *ptr) {return(((grn_info *)ptr)->in_data_len);}
-
- static mus_long_t grn_location(mus_any *ptr) {return((mus_long_t)(((grn_info *)ptr)->randx));}
- static mus_long_t grn_set_location(mus_any *ptr, mus_long_t val) {((grn_info *)ptr)->randx = (unsigned long)val; return(val);}
-
- static mus_float_t run_granulate(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_granulate(ptr, NULL));}
-
-
- static void grn_reset(mus_any *ptr)
- {
- grn_info *gen = (grn_info *)ptr;
- gen->cur_out = 0;
- gen->ctr = 0;
- memset((void *)(gen->out_data), 0, gen->out_data_len * sizeof(mus_float_t));
- memset((void *)(gen->in_data), 0, gen->in_data_len * sizeof(mus_float_t));
- memset((void *)(gen->grain), 0, gen->in_data_len * sizeof(mus_float_t));
- gen->first_samp = true;
- }
-
-
- static int grn_irandom(grn_info *spd, int amp)
- {
- /* gen-local next_random */
- spd->randx = spd->randx * 1103515245 + 12345;
- return((int)(amp * INVERSE_MAX_RAND2 * ((mus_float_t)((unsigned int)(spd->randx >> 16) & 32767))));
- }
-
-
- static mus_any_class GRANULATE_CLASS = {
- MUS_GRANULATE,
- (char *)S_granulate,
- &free_granulate,
- &describe_granulate,
- &granulate_equalp,
- &granulate_data, 0,
- &grn_length, /* segment-length */
- &grn_set_length,
- &grn_frequency, /* spd-out */
- &grn_set_frequency,
- 0, 0,
- &grn_scaler, /* segment-scaler */
- &grn_set_scaler,
- &grn_increment,
- &grn_set_increment,
- &run_granulate,
- MUS_NOT_SPECIAL,
- &grn_closure,
- 0,
- 0, 0, 0, 0, 0, 0,
- &grn_hop, &grn_set_hop,
- &grn_ramp, &grn_set_ramp,
- 0, 0, 0, 0,
- &grn_location, &grn_set_location, /* local randx */
- 0, 0, 0, 0, 0,
- &grn_reset,
- &grn_set_closure,
- &grn_info_copy
- };
-
-
- mus_any *mus_make_granulate(mus_float_t (*input)(void *arg, int direction),
- mus_float_t expansion, mus_float_t length, mus_float_t scaler,
- mus_float_t hop, mus_float_t ramp, mus_float_t jitter, int max_size,
- int (*edit)(void *closure),
- void *closure)
- {
- grn_info *spd;
- int outlen;
- outlen = (int)(sampling_rate * (hop + length));
- if (max_size > outlen) outlen = max_size;
- if (expansion <= 0.0)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_granulate ": expansion must be > 0.0: %f", expansion);
- return(NULL);
- }
- if (outlen <= 0)
- {
- mus_error(MUS_NO_LENGTH, S_make_granulate ": size is %d (hop: %f, segment-length: %f)?", outlen, hop, length);
- return(NULL);
- }
- if ((hop * sampling_rate) < expansion)
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_granulate ": expansion (%f) must be < hop * srate (%f)", expansion, hop * sampling_rate);
- return(NULL);
- }
- spd = (grn_info *)malloc(sizeof(grn_info));
- spd->core = &GRANULATE_CLASS;
- spd->cur_out = 0;
- spd->ctr = 0;
- spd->grain_len = (int)(ceil(length * sampling_rate));
- spd->rmp = (int)(ramp * spd->grain_len);
- spd->amp = scaler;
- spd->output_hop = (int)(hop * sampling_rate);
- spd->input_hop = (int)((mus_float_t)(spd->output_hop) / expansion);
- spd->s20 = 2 * (int)(jitter * sampling_rate * hop); /* was *.05 here and *.02 below */
- /* added "2 *" 21-Mar-05 and replaced irandom with (grn)mus_irandom below */
- spd->s50 = (int)(jitter * sampling_rate * hop * 0.4);
- spd->out_data_len = outlen;
- spd->out_data = (mus_float_t *)calloc(spd->out_data_len, sizeof(mus_float_t));
- spd->in_data_len = outlen + spd->s20 + 1;
- spd->in_data = (mus_float_t *)malloc(spd->in_data_len * sizeof(mus_float_t));
- spd->rd = input;
- spd->block_rd = NULL;
- spd->closure = closure;
- spd->edit = edit;
- spd->grain = (mus_float_t *)malloc(spd->in_data_len * sizeof(mus_float_t));
- spd->first_samp = true;
- spd->randx = mus_rand_seed(); /* caller can override this via the mus_location method */
- next_random();
- return((mus_any *)spd);
- }
-
-
- void mus_granulate_set_edit_function(mus_any *ptr, int (*edit)(void *closure))
- {
- grn_info *gen = (grn_info *)ptr;
- if (!(gen->grain))
- gen->grain = (mus_float_t *)calloc(gen->in_data_len, sizeof(mus_float_t));
- gen->edit = edit;
- }
-
-
- mus_float_t mus_granulate_with_editor(mus_any *ptr, mus_float_t (*input)(void *arg, int direction), int (*edit)(void *closure))
- {
- /* in_data_len is the max grain size (:maxsize arg), not the current grain size
- * out_data_len is the size of the output buffer
- * grain_len is the current grain size
- * cur_out is the out_data buffer location where we need to add in the next grain
- * ctr is where we are now in out_data
- */
- grn_info *spd = (grn_info *)ptr;
- mus_float_t result = 0.0;
-
- if (spd->ctr < spd->out_data_len)
- result = spd->out_data[spd->ctr]; /* else return 0.0 */
- spd->ctr++;
-
- if (spd->ctr >= spd->cur_out) /* time for next grain */
- {
- /* set up edit/input functions and possible outside-accessible grain array */
- int i;
- int (*spd_edit)(void *closure) = edit;
- if (input) {spd->rd = input; spd->block_rd = NULL;}
- if (spd_edit == NULL) spd_edit = spd->edit;
-
- if (spd->first_samp)
- {
- /* fill up in_data, out_data is already cleared */
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, 0, spd->in_data_len);
- else
- {
- for (i = 0; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- else
- {
-
- /* align output buffer to flush the data we've already output, and zero out new trailing portion */
- if (spd->cur_out >= spd->out_data_len)
- {
- /* entire buffer has been output, and in fact we've been sending 0's for awhile to fill out hop */
- memset((void *)(spd->out_data), 0, spd->out_data_len * sizeof(mus_float_t)); /* so zero the entire thing (it's all old) */
- }
- else
- {
- /* move yet-un-output data to 0, zero trailers */
- int good_samps;
- good_samps = (spd->out_data_len - spd->cur_out);
- memmove((void *)(spd->out_data), (void *)(spd->out_data + spd->cur_out), good_samps * sizeof(mus_float_t));
- memset((void *)(spd->out_data + good_samps), 0, spd->cur_out * sizeof(mus_float_t)); /* must be cur_out trailing samples to 0 */
- }
-
- /* align input buffer */
- if (spd->input_hop > spd->in_data_len)
- {
- /* need to flush enough samples to accommodate the fact that the hop is bigger than our data buffer */
- for (i = spd->in_data_len; i < spd->input_hop; i++) spd->rd(spd->closure, 1);
- /* then get a full input buffer */
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, 0, spd->in_data_len);
- else
- {
- for (i = 0; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- else
- {
- /* align input buffer with current input hop location */
- int good_samps;
- good_samps = (spd->in_data_len - spd->input_hop);
- memmove((void *)(spd->in_data), (void *)(spd->in_data + spd->input_hop), good_samps * sizeof(mus_float_t));
- if (spd->block_rd)
- spd->block_rd(spd->closure, 1, spd->in_data, good_samps, spd->in_data_len);
- else
- {
- for (i = good_samps; i < spd->in_data_len; i++)
- spd->in_data[i] = spd->rd(spd->closure, 1);
- }
- }
- }
-
- /* create current grain */
- {
- int lim, curstart, j;
-
- lim = spd->grain_len;
- curstart = grn_irandom(spd, spd->s20); /* start location in input buffer */
- if ((curstart + spd->grain_len) > spd->in_data_len)
- lim = (spd->in_data_len - curstart);
- if (lim > spd->grain_len)
- lim = spd->grain_len;
- else
- {
- if (lim < spd->grain_len)
- memset((void *)(spd->grain), 0, (spd->grain_len - lim) * sizeof(mus_float_t));
- }
- if (spd->rmp > 0)
- {
- int steady_end, up_end;
- mus_float_t amp = 0.0, incr;
- steady_end = (spd->grain_len - spd->rmp);
- incr = (mus_float_t)(spd->amp) / (mus_float_t)(spd->rmp);
- up_end = spd->rmp;
- if (up_end > lim) up_end = lim;
- for (i = 0, j = curstart; i < up_end; i++, j++)
- {
- spd->grain[i] = (amp * spd->in_data[j]);
- amp += incr;
- }
- if (steady_end > lim) steady_end = lim;
- for (; i < steady_end; i++, j++)
- spd->grain[i] = (amp * spd->in_data[j]);
- for (; i < lim; i++, j++)
- {
- spd->grain[i] = (amp * spd->in_data[j]);
- amp -= incr;
- }
- }
- else
- {
- /* ramp is 0.0, so just scale the input buffer by the current amp */
- if (spd->amp == 1.0)
- memcpy((void *)(spd->grain), (void *)(spd->in_data + curstart), lim * sizeof(mus_float_t));
- else
- {
- for (i = 0, j = curstart; i < lim; i++, j++)
- spd->grain[i] = (spd->amp * spd->in_data[j]);
- }
- }
- }
-
- /* add new grain into output buffer */
- {
- int new_len;
- if (spd_edit)
- {
- new_len = (*spd_edit)(spd->closure);
- if (new_len <= 0)
- new_len = spd->grain_len;
- else
- {
- if (new_len > spd->out_data_len)
- new_len = spd->out_data_len;
- }
- }
- else new_len = spd->grain_len;
- if (new_len > spd->out_data_len) /* can be off-by-one here if hop is just barely greater then 0.0 (user is screwing around...) */
- new_len = spd->out_data_len;
- for (i = 0; i < new_len; i++)
- spd->out_data[i] += spd->grain[i];
- }
-
- /* set location of next grain calculation */
- spd->ctr = 0;
- spd->cur_out = spd->output_hop + grn_irandom(spd, 2 * spd->s50) - (spd->s50 >> 1);
- /* this form suggested by Marc Lehmann */
- /* "2 *" added 21-Mar-05 and irandom replaced with mus_irandom, grn_irandom 28-Feb-06 */
- /* use of gen-local random sequence suggested by Kjetil Matheussen (to keep multi-channel grns in sync) */
- if (spd->cur_out < 0) spd->cur_out = 0;
-
- if (spd->first_samp)
- {
- spd->first_samp = false;
- spd->ctr = 1;
- return(spd->out_data[0]);
- }
- }
- return(result);
- }
-
-
- mus_float_t mus_granulate(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- return(mus_granulate_with_editor(ptr, input, NULL));
- }
-
-
-
- /* ---------------- Fourier transform ---------------- */
-
- /* fft of mus_float_t data in zero-based arrays
- */
-
- static void mus_big_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is);
-
- #if HAVE_FFTW3 && HAVE_COMPLEX_TRIG
-
- static fftw_complex *c_in_data = NULL, *c_out_data = NULL;
- static fftw_plan c_r_plan, c_i_plan;
- static int last_c_fft_size = 0;
-
- static void mus_fftw_with_imag(mus_float_t *rl, mus_float_t *im, int n, int dir)
- {
- int i, n4;
-
- if (n != last_c_fft_size)
- {
- if (c_in_data)
- {
- fftw_free(c_in_data);
- fftw_free(c_out_data);
- fftw_destroy_plan(c_r_plan);
- fftw_destroy_plan(c_i_plan);
- }
- c_in_data = (fftw_complex *)fftw_malloc(n * sizeof(fftw_complex)); /* rl/im data is mus_float_t */
- c_out_data = (fftw_complex *)fftw_malloc(n * sizeof(fftw_complex));
- c_r_plan = fftw_plan_dft_1d(n, c_in_data, c_out_data, FFTW_FORWARD, FFTW_ESTIMATE);
- c_i_plan = fftw_plan_dft_1d(n, c_in_data, c_out_data, FFTW_BACKWARD, FFTW_ESTIMATE);
- last_c_fft_size = n;
- }
-
- n4 = n - 4;
- i = 0;
- while (i <= n4)
- {
- /* adding code to avoid this loop saves essentially nothing, mainly because the great majority of the calls
- * are actually handling two real arrays at once -- the imag=0 case is 1/10 of the total. In the zero case,
- * the savings here is about 10%, but that is swamped by the fft itself (say 5-10 in c*).
- * using the new split array code (see below) saves essentially nothing -- perhaps 1 to 2% overall.
- */
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- c_in_data[i] = rl[i] + _Complex_I * im[i];
- i++;
- }
- for (; i < n; i++)
- c_in_data[i] = rl[i] + _Complex_I * im[i];
-
- if (dir == -1)
- fftw_execute(c_r_plan);
- else fftw_execute(c_i_plan);
-
- i = 0;
- while (i <= n4)
- {
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- i++;
- }
- for (; i < n; i++)
- {
- rl[i] = creal(c_out_data[i]);
- im[i] = cimag(c_out_data[i]);
- }
- }
-
-
- void mus_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- /* simple timing tests indicate fftw is slightly faster than mus_fft in this context
- */
- if (n < (1 << 30))
- mus_fftw_with_imag(rl, im, n, is);
- else mus_big_fft(rl, im, n, is);
- }
-
- #else
-
- static void mus_scramble(mus_float_t *rl, mus_float_t *im, int n)
- {
- /* bit reversal */
-
- int i, j;
- mus_float_t vr, vi;
- j = 0;
- for (i = 0; i < n; i++)
- {
- int m;
- if (j > i)
- {
- vr = rl[j];
- vi = im[j];
- rl[j] = rl[i];
- im[j] = im[i];
- rl[i] = vr;
- im[i] = vi;
- }
- m = n >> 1;
- while ((m >= 2) && (j >= m))
- {
- j -= m;
- m = m >> 1;
- }
- j += m;
- }
- }
-
-
- void mus_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- /* standard fft: real part in rl, imaginary in im,
- * rl and im are zero-based.
- * see fxt/simplfft/fft.c (Joerg Arndt)
- */
- int m, j, mh, ldm, lg, i, i2, j2, imh;
- mus_float_t u, vr, vi, angle;
-
- if (n >= (1 << 30))
- {
- mus_big_fft(rl, im, n, is);
- return;
- }
-
- imh = (int)(log(n + 1) / log(2.0));
- mus_scramble(rl, im, n);
- m = 2;
- ldm = 1;
- mh = n >> 1;
- angle = (M_PI * is);
- for (lg = 0; lg < imh; lg++)
- {
- mus_float_t c, s, ur, ui;
- c = cos(angle);
- s = sin(angle);
- ur = 1.0;
- ui = 0.0;
- for (i2 = 0; i2 < ldm; i2++)
- {
- i = i2;
- j = i2 + ldm;
- for (j2 = 0; j2 < mh; j2++)
- {
- vr = ur * rl[j] - ui * im[j];
- vi = ur * im[j] + ui * rl[j];
- rl[j] = rl[i] - vr;
- im[j] = im[i] - vi;
- rl[i] += vr;
- im[i] += vi;
- i += m;
- j += m;
- }
- u = ur;
- ur = (ur * c) - (ui * s);
- ui = (ui * c) + (u * s);
- }
- mh >>= 1;
- ldm = m;
- angle *= 0.5;
- m <<= 1;
- }
- }
- #endif
-
-
- static void mus_big_fft(mus_float_t *rl, mus_float_t *im, mus_long_t n, int is)
- {
- mus_long_t m, j, mh, ldm, i, i2, j2;
- int imh, lg;
- mus_float_t u, vr, vi, angle;
-
- imh = (int)(log(n + 1) / log(2.0));
-
- j = 0;
- for (i = 0; i < n; i++)
- {
- if (j > i)
- {
- vr = rl[j];
- vi = im[j];
- rl[j] = rl[i];
- im[j] = im[i];
- rl[i] = vr;
- im[i] = vi;
- }
- m = n >> 1;
- while ((m >= 2) && (j >= m))
- {
- j -= m;
- m = m >> 1;
- }
- j += m;
- }
-
- m = 2;
- ldm = 1;
- mh = n >> 1;
- angle = (M_PI * is);
- for (lg = 0; lg < imh; lg++)
- {
- mus_float_t c, s, ur, ui;
- c = cos(angle);
- s = sin(angle);
- ur = 1.0;
- ui = 0.0;
- for (i2 = 0; i2 < ldm; i2++)
- {
- i = i2;
- j = i2 + ldm;
- for (j2 = 0; j2 < mh; j2++)
- {
- vr = ur * rl[j] - ui * im[j];
- vi = ur * im[j] + ui * rl[j];
- rl[j] = rl[i] - vr;
- im[j] = im[i] - vi;
- rl[i] += vr;
- im[i] += vi;
- i += m;
- j += m;
- }
- u = ur;
- ur = (ur * c) - (ui * s);
- ui = (ui * c) + (u * s);
- }
- mh >>= 1;
- ldm = m;
- angle *= 0.5;
- m <<= 1;
- }
- }
-
-
- #if HAVE_GSL
- #include <gsl/gsl_sf_bessel.h>
-
- mus_float_t mus_bessi0(mus_float_t x)
- {
- gsl_sf_result res;
- gsl_sf_bessel_I0_e(x, &res);
- return((mus_float_t)(res.val));
- }
-
- #else
-
- mus_float_t mus_bessi0(mus_float_t x)
- {
- if (x == 0.0) return(1.0);
- if (fabs(x) <= 15.0)
- {
- mus_float_t z, denominator, numerator;
- z = x * x;
- numerator = (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z * (z *
- 0.210580722890567e-22 + 0.380715242345326e-19) +
- 0.479440257548300e-16) + 0.435125971262668e-13) +
- 0.300931127112960e-10) + 0.160224679395361e-7) +
- 0.654858370096785e-5) + 0.202591084143397e-2) +
- 0.463076284721000e0) + 0.754337328948189e2) +
- 0.830792541809429e4) + 0.571661130563785e6) +
- 0.216415572361227e8) + 0.356644482244025e9) +
- 0.144048298227235e10);
- denominator = (z * (z * (z - 0.307646912682801e4) +
- 0.347626332405882e7) - 0.144048298227235e10);
- return(-numerator / denominator);
- }
- return(1.0);
- }
- #endif
-
-
- #if HAVE_COMPLEX_TRIG || HAVE_GSL
- static mus_float_t ultraspherical(int n, mus_float_t x, mus_float_t lambda)
- {
- /* this is also the algorithm used in gsl gegenbauer.c -- slow but not as bad as using the binomials! */
- mus_float_t fn1, fn2 = 1.0, fn = 1.0;
- int k;
- if (n == 0) return(1.0);
- if (lambda == 0.0)
- fn1 = 2.0 * x;
- else fn1 = 2.0 * x * lambda;
- if (n == 1) return(fn1);
- for (k = 2; k <= n; k++)
- {
- fn = ((2.0 * x * (k + lambda - 1.0) * fn1) - ((k + (2.0 * lambda) - 2.0) * fn2)) / (mus_float_t)k;
- fn2 = fn1;
- fn1 = fn;
- }
- return(fn);
- }
- #endif
-
-
- bool mus_is_fft_window(int val)
- {
- switch (val)
- {
- case MUS_RECTANGULAR_WINDOW: case MUS_HANN_WINDOW: case MUS_WELCH_WINDOW: case MUS_PARZEN_WINDOW:
- case MUS_BARTLETT_WINDOW: case MUS_HAMMING_WINDOW: case MUS_BLACKMAN2_WINDOW: case MUS_BLACKMAN3_WINDOW:
- case MUS_BLACKMAN4_WINDOW: case MUS_EXPONENTIAL_WINDOW: case MUS_RIEMANN_WINDOW: case MUS_KAISER_WINDOW:
- case MUS_CAUCHY_WINDOW: case MUS_POISSON_WINDOW: case MUS_GAUSSIAN_WINDOW: case MUS_TUKEY_WINDOW:
- case MUS_DOLPH_CHEBYSHEV_WINDOW: case MUS_HANN_POISSON_WINDOW: case MUS_CONNES_WINDOW:
- case MUS_SAMARAKI_WINDOW: case MUS_ULTRASPHERICAL_WINDOW: case MUS_BARTLETT_HANN_WINDOW:
- case MUS_BOHMAN_WINDOW: case MUS_FLAT_TOP_WINDOW: case MUS_BLACKMAN5_WINDOW: case MUS_BLACKMAN6_WINDOW:
- case MUS_BLACKMAN7_WINDOW: case MUS_BLACKMAN8_WINDOW: case MUS_BLACKMAN9_WINDOW: case MUS_BLACKMAN10_WINDOW:
- case MUS_RV2_WINDOW: case MUS_RV3_WINDOW: case MUS_RV4_WINDOW: case MUS_MLT_SINE_WINDOW:
- case MUS_PAPOULIS_WINDOW: case MUS_DPSS_WINDOW: case MUS_SINC_WINDOW:
- return(true);
- break;
- }
- return(false);
- }
-
-
- #if HAVE_GSL
- #include <gsl/gsl_version.h>
- #if ((GSL_MAJOR_VERSION >= 1) && (GSL_MINOR_VERSION >= 9))
- #include <gsl/gsl_math.h>
- #include <gsl/gsl_eigen.h>
- #define HAVE_GSL_EIGEN_NONSYMMV_WORKSPACE 1
- #endif
- #endif
-
-
- static mus_float_t sqr(mus_float_t x) {return(x * x);}
-
-
- mus_float_t *mus_make_fft_window_with_window(mus_fft_window_t type, mus_long_t size, mus_float_t beta, mus_float_t mu, mus_float_t *window)
- {
- /* mostly taken from
- * Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the
- * Discrete Fourier Transform," Proceedings of the IEEE, Vol. 66, No. 1,
- * January 1978.
- *
- * Albert H. Nuttall, "Some Windows with Very Good Sidelobe Behaviour",
- * IEEE Transactions of Acoustics, Speech, and Signal Processing, Vol. ASSP-29,
- * No. 1, February 1981, pp 84-91
- */
-
- mus_long_t i, j, midn, midp1;
- mus_float_t freq, rate, angle = 0.0, cx;
- if (window == NULL) return(NULL);
-
- midn = size >> 1;
- midp1 = (size + 1) / 2;
- freq = TWO_PI / (mus_float_t)size;
- rate = 1.0 / (mus_float_t)midn;
-
- switch (type)
- {
- case MUS_RECTANGULAR_WINDOW:
- for (i = 0; i < size; i++)
- window[i] = 1.0;
- break;
-
- case MUS_WELCH_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = 1.0 - sqr((mus_float_t)(i - midn) / (mus_float_t)midp1);
- window[j] = window[i];
- }
- break;
-
- case MUS_CONNES_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = sqr(1.0 - sqr((mus_float_t)(i - midn) / (mus_float_t)midp1));
- window[j] = window[i];
- }
- break;
-
- case MUS_PARZEN_WINDOW:
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = 1.0 - fabs((mus_float_t)(i - midn) / (mus_float_t)midp1);
- window[j] = window[i];
- }
- break;
-
- case MUS_BARTLETT_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += rate)
- {
- window[i] = angle;
- window[j] = angle;
- }
- break;
-
- case MUS_BARTLETT_HANN_WINDOW:
- {
- mus_float_t ramp;
- rate *= 0.5;
- /* this definition taken from mathworks docs: they use size - 1 throughout -- this makes very little
- * difference unless you're using a small window. I decided to be consistent with all the other
- * windows, and besides, this way actually peaks at 1.0 (which matlab misses)
- */
- for (i = 0, j = size - 1, angle = -M_PI, ramp = 0.5; i <= midn; i++, j--, angle += freq, ramp -= rate)
- {
- window[i] = 0.62 - 0.48 * ramp + 0.38 * cos(angle);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_BOHMAN_WINDOW:
- {
- mus_float_t ramp;
- /* definition from diracdelta docs and "DSP Handbook" -- used in bispectrum ("minimum bispectrum bias supremum") */
- for (i = 0, j = size - 1, angle = M_PI, ramp = 0.0; i <= midn; i++, j--, angle -= freq, ramp += rate)
- {
- window[i] = ramp * cos(angle) + (sin(angle) / M_PI);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_HANN_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.5 - 0.5 * cos(angle);
- window[j] = window[i];
- }
- break;
-
- /* Rife-Vincent windows are an elaboration of this (Hann = RV1) */
-
- case MUS_RV2_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = .375 - 0.5 * cos(angle) + .125 * cos(2 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_RV3_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = (10.0 / 32.0) -
- (15.0 / 32.0) * cos(angle) +
- (6.0 / 32.0) * cos(2 * angle) -
- (1.0 / 32.0) * cos(3 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_RV4_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = (35.0 / 128.0) -
- (56.0 / 128.0) * cos(angle) +
- (28.0 / 128.0) * cos(2 * angle) -
- (8.0 / 128.0) * cos(3 * angle) +
- (1.0 / 128.0) * cos(4 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_HAMMING_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.54 - 0.46 * cos(angle);
- window[j] = window[i];
- }
- break;
-
- /* Blackman 1 is the same as Hamming */
-
- case MUS_BLACKMAN2_WINDOW: /* using Chebyshev polynomial equivalents here (this is also given as .42 .5 .08) */
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.42323 (* -0.49755 (cos a)) (* 0.07922 (cos (* a 2)))) */
- /* "A Family...": .42438 .49341 .078279 */
- cx = cos(angle);
- window[i] = .34401 + (cx * (-.49755 + (cx * .15844)));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN3_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.35875 (* -0.48829 (cos a)) (* 0.14128 (cos (* a 2))) (* -0.01168 (cos (* a 3)))) */
- /* (+ 0.36336 (* 0.48918 (cos a)) (* 0.13660 (cos (* a 2))) (* 0.01064 (cos (* a 3)))) is "Nuttall" window? */
- /* "A Family...": .36358 .489177 .136599 .0106411 */
-
- cx = cos(angle);
- window[i] = .21747 + (cx * (-.45325 + (cx * (.28256 - (cx * .04672)))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN4_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- { /* (+ 0.287333 (* -0.44716 (cos a)) (* 0.20844 (cos (* a 2))) (* -0.05190 (cos (* a 3))) (* 0.005149 (cos (* a 4)))) */
- /* "A Family...": .32321 .471492 .175534 .0284969 .001261357 */
- cx = cos(angle);
- window[i] = .084037 + (cx * (-.29145 + (cx * (.375696 + (cx * (-.20762 + (cx * .041194)))))));
- window[j] = window[i];
- }
- break;
-
- /* "A Family of Cosine-Sum Windows..." Albrecht */
-
- case MUS_BLACKMAN5_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .293557 -.451935 .201416 -.047926 .00502619 -.000137555 */
- /* partials->polynomial -> -0.196389809 -0.308844775 0.3626224697 -0.188952908 0.0402095206 -0.002200880, then fixup constant */
- cx = cos(angle);
- window[i] = 0.097167 +
- (cx * (-.3088448 +
- (cx * (.3626224 +
- (cx * (-.1889530 +
- (cx * (.04020952 +
- (cx * -.0022008)))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN6_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2712203 -.4334446 .2180041 -.0657853 .010761867 -.0007700127 .00001368088 */
- /* partials->polynomial -> -0.207255900 -0.239938736 0.3501594961
- * -0.247740954 0.0854382589 -0.012320203 0.0004377882
- */
- cx = cos(angle);
- window[i] = 0.063964353 +
- (cx * (-0.239938736 +
- (cx * (0.3501594961 +
- (cx * (-0.247740954 +
- (cx * (0.0854382589 +
- (cx * (-0.012320203 +
- (cx * 0.0004377882)))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN7_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2533176 -.4163269 .2288396 -.08157508 .017735924 -.0020967027 .00010677413 -.0000012807 */
- /* partials->polynomial -> -0.211210445 -0.182076216 0.3177137375 -0.284437984
- * 0.1367622316 -0.033403806 0.0034167722 -0.000081965
- */
- cx = cos(angle);
- window[i] = 0.04210723 +
- (cx * (-0.18207621 +
- (cx * (0.3177137375 +
- (cx * (-0.284437984 +
- (cx * (0.1367622316 +
- (cx * (-0.033403806 +
- (cx * (0.0034167722 +
- (cx * -0.000081965)))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN8_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2384331 -.4005545 .2358242 -.09527918 .025373955 -.0041524329 .00036856041 -.00001384355 .0000001161808 */
- /* partials->polynomial -> -0.210818693 -0.135382235 0.2752871215 -0.298843294 0.1853193194
- * -0.064888448 0.0117641902 -0.000885987 0.0000148711
- */
- cx = cos(angle);
- window[i] = 0.027614462 +
- (cx * (-0.135382235 +
- (cx * (0.2752871215 +
- (cx * (-0.298843294 +
- (cx * (0.1853193194 +
- (cx * (-0.064888448 +
- (cx * (0.0117641902 +
- (cx * (-0.000885987 +
- (cx * 0.0000148711)))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN9_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2257345 -.3860122 .2401294 -.1070542 .03325916 -.00687337 .0008751673 -.0000600859 .000001710716 -.00000001027272 */
- /* partials->polynomial -> -0.207743675 -0.098795950 0.2298837751 -0.294112951 0.2243389785
- * -0.103248745 0.0275674108 -0.003839580 0.0002189716 -0.000002630
- */
- cx = cos(angle);
- window[i] = 0.01799071953 +
- (cx * (-0.098795950 +
- (cx * (0.2298837751 +
- (cx * (-0.294112951 +
- (cx * (0.2243389785 +
- (cx * (-0.103248745 +
- (cx * (0.0275674108 +
- (cx * (-0.003839580 +
- (cx * (0.0002189716 +
- (cx * -0.000002630)))))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_BLACKMAN10_WINDOW:
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- /* .2151527 -.3731348 .2424243 -.1166907 .04077422 -.01000904 .0016398069 -.0001651660 .000008884663 -.000000193817 .00000000084824 */
- /* partials->polynomial -> -0.203281015 -0.071953468 0.1878870875 -0.275808066
- * 0.2489042133 -0.141729787 0.0502002984 -0.010458985 0.0011361511 -0.000049617 0.0000004343
- */
- cx = cos(angle);
- window[i] = 0.0118717384 +
- (cx * (-0.071953468 +
- (cx * (0.1878870875 +
- (cx * (-0.275808066 +
- (cx * (0.2489042133 +
- (cx * (-0.141729787 +
- (cx * (0.0502002984 +
- (cx * (-0.010458985 +
- (cx * (0.0011361511 +
- (cx * (-0.000049617 +
- (cx * 0.0000004343)))))))))))))))))));
- window[j] = window[i];
- }
- break;
-
- case MUS_FLAT_TOP_WINDOW:
- /* this definition taken from mathworks docs -- see above */
- for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
- {
- window[i] = 0.2156 - 0.4160 * cos(angle) + 0.2781 * cos(2 * angle) - 0.0836 * cos(3 * angle) + 0.0069 * cos(4 * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_EXPONENTIAL_WINDOW:
- {
- mus_float_t expn, expsum = 1.0;
- expn = log(2) / (mus_float_t)midn + 1.0;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = expsum - 1.0;
- window[j] = window[i];
- expsum *= expn;
- }
- }
- break;
-
- case MUS_KAISER_WINDOW:
- {
- mus_float_t I0beta;
- I0beta = mus_bessi0(beta); /* Harris multiplies beta by pi */
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = mus_bessi0(beta * sqrt(1.0 - sqr(angle))) / I0beta;
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_CAUCHY_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = 1.0 / (1.0 + sqr(beta * angle));
- window[j] = window[i];
- }
- break;
-
- case MUS_POISSON_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = exp((-beta) * angle);
- window[j] = window[i];
- }
- break;
-
- case MUS_HANN_POISSON_WINDOW:
- /* Hann * Poisson -- from JOS */
- {
- mus_float_t angle1;
- for (i = 0, j = size - 1, angle = 1.0, angle1 = 0.0; i <= midn; i++, j--, angle -= rate, angle1 += freq)
- {
- window[i] = exp((-beta) * angle) * (0.5 - 0.5 * cos(angle1));
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_RIEMANN_WINDOW:
- {
- mus_float_t sr1;
- sr1 = TWO_PI / (mus_float_t)size;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- if (i == midn)
- window[i] = 1.0;
- else
- {
- cx = sr1 * (midn - i);
- window[i] = sin(cx) / cx;
- }
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_GAUSSIAN_WINDOW:
- for (i = 0, j = size - 1, angle = 1.0; i <= midn; i++, j--, angle -= rate)
- {
- window[i] = exp(-.5 * sqr(beta * angle));
- window[j] = window[i];
- }
- break;
-
- case MUS_TUKEY_WINDOW:
- cx = midn * (1.0 - beta);
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- if (i >= cx)
- window[i] = 1.0;
- else window[i] = .5 * (1.0 - cos(M_PI * i / cx));
- window[j] = window[i];
- }
- break;
-
- case MUS_MLT_SINE_WINDOW:
- {
- mus_float_t scl;
- scl = M_PI / (mus_float_t)size;
- for (i = 0, j = size - 1; i <= midn; i++, j--)
- {
- window[i] = sin((i + 0.5) * scl);
- window[j] = window[i];
- }
- }
- break;
-
- case MUS_PAPOULIS_WINDOW:
- {
- int n2;
- n2 = size / 2;
- for (i = -n2; i < n2; i++)
- {
- mus_float_t ratio, pratio;
- ratio = (mus_float_t)i / (mus_float_t)n2;
- pratio = M_PI * ratio;
- window[i + n2] = (fabs(sin(pratio)) / M_PI) + (cos(pratio) * (1.0 - fabs(ratio)));
- }
- }
- break;
-
- case MUS_SINC_WINDOW:
- {
- mus_float_t scl;
- scl = 2 * M_PI / (size - 1);
- for (i = -midn, j = 0; i < midn; i++, j++)
- {
- if (i == 0)
- window[j] = 1.0;
- else window[j] = sin(i * scl) / (i * scl);
- }
- }
- break;
-
- case MUS_DPSS_WINDOW:
- #if HAVE_GSL_EIGEN_NONSYMMV_WORKSPACE
- {
- /* from Verma, Bilbao, Meng, "The Digital Prolate Spheroidal Window"
- * output checked using Julius Smith's dpssw.m, although my "beta" is different
- */
- double *data; /* "double" for gsl func */
- double cw, n1, pk = 0.0;
-
- cw = cos(2 * M_PI * beta);
- n1 = (size - 1) * 0.5;
- if ((mus_long_t)(size * size * sizeof(double)) > mus_max_malloc())
- {
- mus_error(MUS_ARG_OUT_OF_RANGE, S_make_fft_window ": dpss window requires size^2 * 8 bytes, but that exceeds the current mus-max-malloc amount");
- return(window);
- }
-
- data = (double *)calloc(size * size, sizeof(double));
- for (i = 0; i < size; i++)
- {
- double n2;
- n2 = n1 - i;
- data[i * size + i] = cw * n2 * n2;
- if (i < (size - 1))
- data[i * (size + 1) + 1] = 0.5 * (i + 1) * (size - 1 - i);
- if (i > 0)
- data[i * (size + 1) - 1] = 0.5 * i * (size - i);
- }
- {
- gsl_vector_complex_view evec_i;
- gsl_matrix_view m = gsl_matrix_view_array(data, size, size);
- gsl_vector_complex *eval = gsl_vector_complex_alloc(size);
- gsl_matrix_complex *evec = gsl_matrix_complex_alloc(size, size);
-
- gsl_eigen_nonsymmv_workspace *w = gsl_eigen_nonsymmv_alloc(size);
- gsl_eigen_nonsymmv(&m.matrix, eval, evec, w);
- gsl_eigen_nonsymmv_free(w);
-
- gsl_eigen_nonsymmv_sort(eval, evec, GSL_EIGEN_SORT_ABS_DESC);
- evec_i = gsl_matrix_complex_column(evec, 0);
-
- for (j = 0; j < size; j++)
- window[j] = GSL_REAL(gsl_vector_complex_get(&evec_i.vector, j));
-
- gsl_vector_complex_free(eval);
- gsl_matrix_complex_free(evec);
- }
-
- for (i = 0; i < size; i++)
- if (fabs(window[i]) > fabs(pk))
- pk = window[i];
- if (pk != 0.0)
- for (i = 0; i < size; i++)
- window[i] /= pk;
-
- free(data);
- }
- #else
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": DPSS window needs GSL");
- #endif
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- case MUS_SAMARAKI_WINDOW:
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- /* "Design of Ultraspherical Window Functions with Prescribed Spectral Characteristics", Bergen and Antoniou, EURASIP JASP 2004 */
- if (type == MUS_ULTRASPHERICAL_WINDOW)
- {
- if (mu == 0.0)
- type = MUS_DOLPH_CHEBYSHEV_WINDOW;
- else
- {
- if (mu == 1.0)
- type = MUS_SAMARAKI_WINDOW;
- }
- }
-
- #if HAVE_COMPLEX_TRIG
- {
- mus_float_t *rl, *im;
- mus_float_t pk = 0.0;
- mus_float_t alpha;
-
- freq = M_PI / (mus_float_t)size;
- if (beta < 0.2) beta = 0.2;
- alpha = creal(ccosh(cacosh(pow(10.0, beta)) / (mus_float_t)size));
-
- rl = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(size, sizeof(mus_float_t));
-
- for (i = 0, angle = 0.0; i < size; i++, angle += freq)
- {
- switch (type)
- {
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- rl[i] = creal(ccos(cacos(alpha * cos(angle)) * size)); /* here is Tn (Chebyshev polynomial first kind) */
- break;
-
- case MUS_SAMARAKI_WINDOW:
- /* Samaraki window uses Un instead */
- rl[i] = creal(csin(cacos(alpha * cos(angle)) * (size + 1.0)) / csin(cacos(alpha * cos(angle))));
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- /* Cn here */
- rl[i] = ultraspherical(size, alpha * cos(angle), mu);
- break;
-
- default:
- break;
- }
- }
-
- mus_fft(rl, im, size, -1); /* can be 1 here */
-
- pk = 0.0;
- for (i = 0; i < size; i++)
- if (pk < rl[i])
- pk = rl[i];
- if ((pk != 0.0) && (pk != 1.0))
- {
- for (i = 0, j = size / 2; i < size; i++)
- {
- window[i] = rl[j++] / pk;
- if (j == size) j = 0;
- }
- }
- else
- {
- memcpy((void *)window, (void *)rl, size * sizeof(mus_float_t));
- }
-
- free(rl);
- free(im);
- }
- #else
- #if HAVE_GSL
- {
- mus_float_t *rl, *im;
- mus_float_t pk;
- mus_float_t alpha;
-
- freq = M_PI / (mus_float_t)size;
- if (beta < 0.2) beta = 0.2;
- alpha = GSL_REAL(gsl_complex_cosh(
- gsl_complex_mul_real(
- gsl_complex_arccosh_real(pow(10.0, beta)),
- (mus_float_t)(1.0 / (mus_float_t)size))));
-
- rl = (mus_float_t *)malloc(size * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(size, sizeof(mus_float_t));
-
- for (i = 0, angle = 0.0; i < size; i++, angle += freq)
- {
- switch (type)
- {
- case MUS_DOLPH_CHEBYSHEV_WINDOW:
- rl[i] = GSL_REAL(gsl_complex_cos(
- gsl_complex_mul_real(
- gsl_complex_arccos_real(alpha * cos(angle)),
- (mus_float_t)size)));
- break;
-
- case MUS_SAMARAKI_WINDOW:
- rl[i] = GSL_REAL(gsl_complex_div(
- gsl_complex_sin(
- gsl_complex_mul_real(
- gsl_complex_arccos_real(alpha * cos(angle)),
- (mus_float_t)(size + 1.0))),
- gsl_complex_sin(
- gsl_complex_arccos_real(alpha * cos(angle)))));
- break;
-
- case MUS_ULTRASPHERICAL_WINDOW:
- rl[i] = ultraspherical(size, alpha * cos(angle), mu);
- break;
-
- default:
- break;
- }
-
- }
-
- mus_fft(rl, im, size, -1); /* can be 1 here */
-
- pk = 0.0;
- for (i = 0; i < size; i++)
- if (pk < rl[i])
- pk = rl[i];
- if ((pk != 0.0) && (pk != 1.0))
- {
- for (i = 0, j = size / 2; i < size; i++)
- {
- window[i] = rl[j++] / pk;
- if (j == size) j = 0;
- }
- }
- else
- {
- memcpy((void *)window, (void *)rl, size * sizeof(mus_float_t));
- }
- free(rl);
- free(im);
- }
- #else
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": Dolph-Chebyshev, Samaraki, and Ultraspherical windows need complex trig support");
- #endif
- #endif
- break;
-
- default:
- mus_error(MUS_NO_SUCH_FFT_WINDOW, S_make_fft_window ": unknown fft data window: %d", (int)type);
- break;
- }
- return(window);
- }
-
-
- mus_float_t *mus_make_fft_window(mus_fft_window_t type, mus_long_t size, mus_float_t beta)
- {
- return(mus_make_fft_window_with_window(type, size, beta, 0.0, (mus_float_t *)calloc(size, sizeof(mus_float_t))));
- }
-
-
- static const char *fft_window_names[MUS_NUM_FFT_WINDOWS] =
- {"Rectangular", "Hann", "Welch", "Parzen", "Bartlett", "Hamming", "Blackman2", "Blackman3", "Blackman4",
- "Exponential", "Riemann", "Kaiser", "Cauchy", "Poisson", "Gaussian", "Tukey", "Dolph-Chebyshev", "Hann-Poisson", "Connes",
- "Samaraki", "Ultraspherical", "Bartlett-Hann", "Bohman", "Flat-top",
- "Blackman5", "Blackman6", "Blackman7", "Blackman8", "Blackman9", "Blackman10",
- "Rife-Vincent2", "Rife-Vincent3", "Rife-Vincent4", "MLT Sine", "Papoulis", "DPSS (Slepian)", "Sinc"
- };
-
-
- const char *mus_fft_window_name(mus_fft_window_t win)
- {
- if (mus_is_fft_window((int)win))
- return(fft_window_names[(int)win]);
- return("unknown");
- }
-
-
- const char **mus_fft_window_names(void)
- {
- return(fft_window_names);
- }
-
-
- mus_float_t *mus_spectrum(mus_float_t *rdat, mus_float_t *idat, mus_float_t *window, mus_long_t n, mus_spectrum_t type)
- {
- mus_long_t i;
- mus_float_t maxa, lowest;
-
- if (window)
- {
- for (i = 0; i < n; i++)
- rdat[i] *= window[i];
- }
- memset((void *)idat, 0, n * sizeof(mus_float_t));
- mus_fft(rdat, idat, n, 1);
-
- lowest = 0.000001;
- maxa = 0.0;
- n = n / 2;
- for (i = 0; i < n; i++)
- {
- mus_float_t val;
- val = rdat[i] * rdat[i] + idat[i] * idat[i];
- if (val < lowest)
- rdat[i] = 0.001;
- else
- {
- rdat[i] = sqrt(val);
- if (rdat[i] > maxa) maxa = rdat[i];
- }
- }
- if (maxa > 0.0)
- {
- maxa = 1.0 / maxa;
- if (type == MUS_SPECTRUM_IN_DB)
- {
- mus_float_t todb;
- todb = 20.0 / log(10.0);
- for (i = 0; i < n; i++)
- rdat[i] = todb * log(rdat[i] * maxa);
- }
- else
- {
- if (type == MUS_SPECTRUM_NORMALIZED)
- for (i = 0; i < n; i++)
- rdat[i] *= maxa;
- }
- }
- return(rdat);
- }
-
-
- mus_float_t *mus_autocorrelate(mus_float_t *data, mus_long_t n)
- {
- mus_float_t *im;
- mus_float_t fscl;
- mus_long_t i, n2;
-
- n2 = n / 2;
- fscl = 1.0 / (mus_float_t)n;
- im = (mus_float_t *)calloc(n, sizeof(mus_float_t));
-
- mus_fft(data, im, n, 1);
- for (i = 0; i < n; i++)
- data[i] = data[i] * data[i] + im[i] * im[i];
- memset((void *)im, 0, n * sizeof(mus_float_t));
-
- mus_fft(data, im, n, -1);
- for (i = 0; i <= n2; i++)
- data[i] *= fscl;
- for (i = n2 + 1; i < n; i++)
- data[i] = 0.0;
-
- free(im);
- return(data);
- }
-
-
- mus_float_t *mus_correlate(mus_float_t *data1, mus_float_t *data2, mus_long_t n)
- {
- mus_float_t *im1, *im2;
- mus_long_t i;
- mus_float_t fscl;
-
- im1 = (mus_float_t *)calloc(n, sizeof(mus_float_t));
- im2 = (mus_float_t *)calloc(n, sizeof(mus_float_t));
-
- mus_fft(data1, im1, n, 1);
- mus_fft(data2, im2, n, 1);
-
- for (i = 0; i < n; i++)
- {
- mus_float_t tmp1, tmp2, tmp3, tmp4;
- tmp1 = data1[i] * data2[i];
- tmp2 = im1[i] * im2[i];
- tmp3 = data1[i] * im2[i];
- tmp4 = data2[i] * im1[i];
- data1[i] = tmp1 + tmp2;
- im1[i] = tmp3 - tmp4;
- }
-
- mus_fft(data1, im1, n, -1);
- fscl = 1.0 / (mus_float_t)n;
- for (i = 0; i < n; i++)
- data1[i] *= fscl;
-
- free(im1);
- free(im2);
-
- return(data1);
- }
-
-
- mus_float_t *mus_cepstrum(mus_float_t *data, mus_long_t n)
- {
- mus_float_t *rl, *im;
- mus_float_t fscl, lowest;
- mus_long_t i;
-
- lowest = 0.00000001;
- fscl = 2.0 / (mus_float_t)n;
-
- rl = (mus_float_t *)malloc(n * sizeof(mus_float_t));
- im = (mus_float_t *)calloc(n, sizeof(mus_float_t));
- memcpy((void *)rl, (void *)data, n * sizeof(mus_float_t));
-
- mus_fft(rl, im, n, 1);
-
- for (i = 0; i < n; i++)
- {
- rl[i] = rl[i] * rl[i] + im[i] * im[i];
- if (rl[i] < lowest)
- rl[i] = -10.0;
- else rl[i] = log(sqrt(rl[i]));
- }
- memset((void *)im, 0, n * sizeof(mus_float_t));
-
- mus_fft(rl, im, n, -1);
-
- for (i = 0; i < n; i++)
- if (fabs(rl[i]) > fscl)
- fscl = fabs(rl[i]);
-
- if (fscl > 0.0)
- for (i = 0; i < n; i++)
- data[i] = rl[i] / fscl;
-
- free(rl);
- free(im);
- return(data);
- }
-
-
-
- /* ---------------- convolve ---------------- */
-
- mus_float_t *mus_convolution(mus_float_t *rl1, mus_float_t *rl2, mus_long_t n)
- {
- /* convolves two real arrays.
- * rl1 and rl2 are assumed to be set up correctly for the convolution
- * (that is, rl1 (the "signal") is zero-padded by length of
- * (non-zero part of) rl2 and rl2 is stored in wrap-around order)
- * We treat rl2 as the imaginary part of the first fft, then do
- * the split, scaling, and (complex) spectral multiply in one step.
- * result in rl1
- */
-
- mus_long_t j, n2;
- mus_float_t invn;
-
- mus_fft(rl1, rl2, n, 1);
-
- n2 = n >> 1;
- invn = 0.25 / (mus_float_t)n;
- rl1[0] = ((rl1[0] * rl2[0]) / (mus_float_t)n);
- rl2[0] = 0.0;
-
- for (j = 1; j <= n2; j++)
- {
- mus_long_t nn2;
- mus_float_t rem, rep, aim, aip;
-
- nn2 = n - j;
- rep = (rl1[j] + rl1[nn2]);
- rem = (rl1[j] - rl1[nn2]);
- aip = (rl2[j] + rl2[nn2]);
- aim = (rl2[j] - rl2[nn2]);
-
- rl1[j] = invn * (rep * aip + aim * rem);
- rl2[j] = invn * (aim * aip - rep * rem);
- rl1[nn2] = rl1[j];
- rl2[nn2] = -rl2[j];
- }
-
- mus_fft(rl1, rl2, n, -1);
- return(rl1);
- }
-
-
- typedef struct {
- mus_any_class *core;
- mus_float_t (*feeder)(void *arg, int direction);
- mus_float_t (*block_feeder)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- mus_long_t fftsize, fftsize2, ctr, filtersize;
- mus_float_t *rl1, *rl2, *buf, *filter;
- void *closure;
- } conv;
-
-
- static bool convolve_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_convolve(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s size: %lld",
- mus_name(ptr),
- gen->fftsize);
- return(describe_buffer);
- }
-
-
- static void free_convolve(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- if (gen->rl1) free(gen->rl1);
- if (gen->rl2) free(gen->rl2);
- if (gen->buf) free(gen->buf);
- free(gen);
- }
-
- static mus_any *conv_copy(mus_any *ptr)
- {
- conv *g, *p;
- int bytes;
-
- p = (conv *)ptr;
- g = (conv *)malloc(sizeof(conv));
- memcpy((void *)g, (void *)ptr, sizeof(conv));
- bytes = g->fftsize * sizeof(mus_float_t);
- g->rl1 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rl1), (void *)(p->rl1), bytes);
- g->rl2 = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->rl2), (void *)(p->rl2), bytes);
- g->buf = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->buf), (void *)(p->buf), bytes);
- return((mus_any *)g);
- }
-
-
- static mus_long_t conv_length(mus_any *ptr) {return(((conv *)ptr)->fftsize);}
- static mus_float_t run_convolve(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_convolve(ptr, NULL));}
-
- static void *conv_closure(mus_any *rd) {return(((conv *)rd)->closure);}
- static void *conv_set_closure(mus_any *rd, void *e) {((conv *)rd)->closure = e; return(e);}
-
- static void convolve_reset(mus_any *ptr)
- {
- conv *gen = (conv *)ptr;
- gen->ctr = gen->fftsize2;
- memset((void *)(gen->rl1), 0, gen->fftsize * sizeof(mus_float_t));
- memset((void *)(gen->rl2), 0, gen->fftsize * sizeof(mus_float_t));
- memset((void *)(gen->buf), 0, gen->fftsize * sizeof(mus_float_t));
- }
-
-
- static mus_any_class CONVOLVE_CLASS = {
- MUS_CONVOLVE,
- (char *)S_convolve,
- &free_convolve,
- &describe_convolve,
- &convolve_equalp,
- 0, 0,
- &conv_length,
- 0,
- 0, 0, 0, 0,
- 0, 0,
- 0, 0,
- &run_convolve,
- MUS_NOT_SPECIAL,
- &conv_closure,
- 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,
- &convolve_reset,
- &conv_set_closure,
- &conv_copy
- };
-
-
- mus_float_t mus_convolve(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- conv *gen = (conv *)ptr;
- mus_float_t result;
- if (gen->ctr >= gen->fftsize2)
- {
- mus_long_t i, N;
- size_t bytes;
-
- N = gen->fftsize2;
- bytes = N * sizeof(mus_float_t);
-
- if (input) {gen->feeder = input; gen->block_feeder = NULL;}
- memset((void *)(gen->rl2), 0, bytes * 2);
- memcpy((void *)(gen->rl2), (void *)(gen->filter), gen->filtersize * sizeof(mus_float_t));
-
- memcpy((void *)(gen->buf), (void *)(gen->buf + N), bytes);
- memset((void *)(gen->buf + N), 0, bytes);
- memset((void *)(gen->rl1 + N), 0, bytes);
-
- if (gen->block_feeder)
- gen->block_feeder(gen->closure, 1, gen->rl1, 0, N);
- else
- {
- for (i = 0; i < N;)
- {
- gen->rl1[i] = gen->feeder(gen->closure, 1); i++;
- gen->rl1[i] = gen->feeder(gen->closure, 1); i++;
- }
- }
-
- mus_convolution(gen->rl1, gen->rl2, gen->fftsize);
-
- for (i = 0; i < N;)
- {
- gen->buf[i] += gen->rl1[i]; i++;
- gen->buf[i] += gen->rl1[i]; i++;
- }
- memcpy((void *)(gen->buf + N), (void *)(gen->rl1 + N), bytes);
- gen->ctr = 0;
- }
- result = gen->buf[gen->ctr];
- gen->ctr++;
- return(result);
- }
-
-
- bool mus_is_convolve(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_CONVOLVE));
- }
-
-
- mus_any *mus_make_convolve(mus_float_t (*input)(void *arg, int direction), mus_float_t *filter, mus_long_t fftsize, mus_long_t filtersize, void *closure)
- {
- conv *gen = NULL;
- gen = (conv *)malloc(sizeof(conv));
- gen->core = &CONVOLVE_CLASS;
- gen->feeder = input;
- gen->block_feeder = NULL;
- gen->closure = closure;
- gen->filter = filter;
- if (filter)
- {
- mus_long_t i;
- bool all_zero = true;
- for (i = 0; i < filtersize; i++)
- if (fabs(filter[i]) != 0.0) /* I'm getting -0.000 != 0.000 */
- {
- all_zero = false;
- break;
- }
- if (all_zero)
- mus_print("make_convolve: filter contains only 0.0.");
- }
- gen->filtersize = filtersize;
- gen->fftsize = fftsize;
- gen->fftsize2 = gen->fftsize / 2;
- gen->ctr = gen->fftsize2;
- gen->rl1 = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- gen->rl2 = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- gen->buf = (mus_float_t *)calloc(fftsize, sizeof(mus_float_t));
- return((mus_any *)gen);
- }
-
-
- void mus_convolve_files(const char *file1, const char *file2, mus_float_t maxamp, const char *output_file)
- {
- mus_long_t file1_len, file2_len, outlen, totallen;
- int file1_chans, file2_chans, output_chans;
- mus_float_t *data1, *data2;
- const char *errmsg = NULL;
- mus_float_t maxval = 0.0;
- mus_long_t i, fftlen;
-
- file1_len = mus_sound_framples(file1);
- file2_len = mus_sound_framples(file2);
- if ((file1_len <= 0) || (file2_len <= 0)) return;
-
- file1_chans = mus_sound_chans(file1);
- if (file1_chans <= 0) mus_error(MUS_NO_CHANNELS, S_convolve_files ": %s chans: %d", file1, file1_chans);
- file2_chans = mus_sound_chans(file2);
- if (file2_chans <= 0) mus_error(MUS_NO_CHANNELS, S_convolve_files ": %s chans: %d", file2, file2_chans);
- output_chans = file1_chans;
- if (file2_chans > output_chans) output_chans = file2_chans;
-
- fftlen = (mus_long_t)(pow(2.0, (int)ceil(log(file1_len + file2_len + 1) / log(2.0))));
- outlen = file1_len + file2_len + 1;
- totallen = outlen * output_chans;
-
- data1 = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
- data2 = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
-
- if (output_chans == 1)
- {
- mus_float_t *samps;
- samps = (mus_float_t *)calloc(fftlen, sizeof(mus_float_t));
-
- mus_file_to_array(file1, 0, 0, file1_len, samps);
- for (i = 0; i < file1_len; i++) data1[i] = samps[i];
- mus_file_to_array(file2, 0, 0, file2_len, samps);
- for (i = 0; i < file2_len; i++) data2[i] = samps[i];
-
- mus_convolution(data1, data2, fftlen);
-
- for (i = 0; i < outlen; i++)
- if (maxval < fabs(data1[i]))
- maxval = fabs(data1[i]);
-
- if (maxval > 0.0)
- {
- maxval = maxamp / maxval;
- for (i = 0; i < outlen; i++) data1[i] *= maxval;
- }
-
- for (i = 0; i < outlen; i++) samps[i] = data1[i];
- errmsg = mus_array_to_file_with_error(output_file, samps, outlen, mus_sound_srate(file1), 1);
-
- free(samps);
- }
- else
- {
- mus_float_t *samps;
- mus_float_t *outdat = NULL;
- int c1 = 0, c2 = 0, chan;
-
- samps = (mus_float_t *)calloc(totallen, sizeof(mus_float_t));
- outdat = (mus_float_t *)malloc(totallen * sizeof(mus_float_t));
-
- for (chan = 0; chan < output_chans; chan++)
- {
- mus_long_t j, k;
-
- mus_file_to_array(file1, c1, 0, file1_len, samps);
- for (k = 0; k < file1_len; k++) data1[k] = samps[k];
- mus_file_to_array(file2, c2, 0, file2_len, samps);
- for (k = 0; k < file2_len; k++) data2[k] = samps[k];
-
- mus_convolution(data1, data2, fftlen);
-
- for (j = chan, k = 0; j < totallen; j += output_chans, k++) outdat[j] = data1[k];
- c1++;
- if (c1 >= file1_chans) c1 = 0;
- c2++;
- if (c2 >= file2_chans) c2 = 0;
-
- memset((void *)data1, 0, fftlen * sizeof(mus_float_t));
- memset((void *)data2, 0, fftlen * sizeof(mus_float_t));
- }
-
- for (i = 0; i < totallen; i++)
- if (maxval < fabs(outdat[i]))
- maxval = fabs(outdat[i]);
-
- if (maxval > 0.0)
- {
- maxval = maxamp / maxval;
- for (i = 0; i < totallen; i++) outdat[i] *= maxval;
- }
-
- for (i = 0; i < totallen; i++)
- samps[i] = outdat[i];
-
- errmsg = mus_array_to_file_with_error(output_file, samps, totallen, mus_sound_srate(file1), output_chans);
- free(samps);
- free(outdat);
- }
-
- free(data1);
- free(data2);
-
- if (errmsg)
- mus_error(MUS_CANT_OPEN_FILE, S_convolve_files ": %s", errmsg);
- }
-
-
-
- /* ---------------- phase-vocoder ---------------- */
-
- typedef struct {
- mus_any_class *core;
- mus_float_t pitch;
- mus_float_t (*input)(void *arg, int direction);
- mus_float_t (*block_input)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end);
- void *closure;
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction));
- int (*edit)(void *arg);
- mus_float_t (*synthesize)(void *arg);
- int outctr, interp, filptr, N, D, topN;
- mus_float_t *win, *ampinc, *amps, *freqs, *phases, *phaseinc, *lastphase, *in_data;
-
- mus_float_t sum1;
- bool calc;
- #if HAVE_SINCOS
- double *cs, *sn;
- bool *sc_safe;
- int *indices;
- #endif
- } pv_info;
-
-
- bool mus_is_phase_vocoder(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_PHASE_VOCODER));
- }
-
-
- static bool phase_vocoder_equalp(mus_any *p1, mus_any *p2) {return(p1 == p2);}
-
-
- static char *describe_phase_vocoder(mus_any *ptr)
- {
- char *arr = NULL;
- pv_info *gen = (pv_info *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s outctr: %d, interp: %d, filptr: %d, N: %d, D: %d, in_data: %s",
- mus_name(ptr),
- gen->outctr, gen->interp, gen->filptr, gen->N, gen->D,
- arr = float_array_to_string(gen->in_data, gen->N, 0));
- if (arr) free(arr);
- return(describe_buffer);
- }
-
-
- static void free_phase_vocoder(mus_any *ptr)
- {
- pv_info *gen = (pv_info *)ptr;
- if (gen->in_data) free(gen->in_data);
- if (gen->amps) free(gen->amps);
- if (gen->freqs) free(gen->freqs);
- if (gen->phases) free(gen->phases);
- if (gen->win) free(gen->win);
- if (gen->phaseinc) free(gen->phaseinc);
- if (gen->lastphase) free(gen->lastphase);
- if (gen->ampinc) free(gen->ampinc);
- #if HAVE_SINCOS
- if (gen->indices) free(gen->indices);
- if (gen->sn) free(gen->sn);
- if (gen->cs) free(gen->cs);
- if (gen->sc_safe) free(gen->sc_safe);
- #endif
- free(gen);
- }
-
-
- static mus_any *pv_info_copy(mus_any *ptr)
- {
- pv_info *g, *p;
- int bytes;
-
- p = (pv_info *)ptr;
- g = (pv_info *)malloc(sizeof(pv_info));
- memcpy((void *)g, (void *)ptr, sizeof(pv_info));
-
- bytes = p->N * sizeof(mus_float_t);
- g->freqs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->freqs), (void *)(p->freqs), bytes);
- g->ampinc = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->ampinc), (void *)(p->ampinc), bytes);
- g->win = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->win), (void *)(p->win), bytes);
- if (p->in_data)
- {
- g->in_data = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->in_data), (void *)(p->in_data), bytes);
- }
-
- bytes = (p->N / 2) * sizeof(mus_float_t);
- g->amps = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->amps), (void *)(p->amps), bytes);
- g->phases = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phases), (void *)(p->phases), bytes);
- g->lastphase = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->lastphase), (void *)(p->lastphase), bytes);
- g->phaseinc = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->phaseinc), (void *)(p->phaseinc), bytes);
-
- #if HAVE_SINCOS
- bytes = (p->N / 2) * sizeof(int);
- g->indices = (int *)malloc(bytes);
- memcpy((void *)(g->indices), (void *)(p->indices), bytes);
-
- bytes = p->N * sizeof(double);
- g->sn = (double *)malloc(bytes);
- memcpy((void *)(g->sn), (void *)(p->sn), bytes);
- g->cs = (double *)malloc(bytes);
- memcpy((void *)(g->cs), (void *)(p->cs), bytes);
-
- bytes = p->N * sizeof(bool);
- g->sc_safe = (bool *)malloc(bytes);
- memcpy((void *)(g->sc_safe), (void *)(p->sc_safe), bytes);
- #endif
-
- return((mus_any *)g);
- }
-
-
- static mus_long_t pv_length(mus_any *ptr) {return(((pv_info *)ptr)->N);}
-
- static mus_long_t pv_hop(mus_any *ptr) {return(((pv_info *)ptr)->D);}
- static mus_long_t pv_set_hop(mus_any *ptr, mus_long_t val) {((pv_info *)ptr)->D = (int)val; return(val);}
-
- static mus_float_t pv_frequency(mus_any *ptr) {return(((pv_info *)ptr)->pitch);}
- static mus_float_t pv_set_frequency(mus_any *ptr, mus_float_t val) {((pv_info *)ptr)->pitch = val; return(val);}
-
- static void *pv_closure(mus_any *rd) {return(((pv_info *)rd)->closure);}
- static void *pv_set_closure(mus_any *rd, void *e) {((pv_info *)rd)->closure = e; return(e);}
-
- mus_float_t *mus_phase_vocoder_amp_increments(mus_any *ptr) {return(((pv_info *)ptr)->ampinc);}
- mus_float_t *mus_phase_vocoder_amps(mus_any *ptr) {return(((pv_info *)ptr)->amps);}
-
- mus_float_t *mus_phase_vocoder_freqs(mus_any *ptr) {return(((pv_info *)ptr)->freqs);}
- mus_float_t *mus_phase_vocoder_phases(mus_any *ptr) {return(((pv_info *)ptr)->phases);}
- mus_float_t *mus_phase_vocoder_phase_increments(mus_any *ptr) {return(((pv_info *)ptr)->phaseinc);}
-
- static mus_long_t pv_outctr(mus_any *ptr) {return((mus_long_t)(((pv_info *)ptr)->outctr));} /* mus_location wrapper */
- static mus_long_t pv_set_outctr(mus_any *ptr, mus_long_t val) {((pv_info *)ptr)->outctr = (int)val; return(val);}
-
- static mus_float_t run_phase_vocoder(mus_any *ptr, mus_float_t unused1, mus_float_t unused2) {return(mus_phase_vocoder(ptr, NULL));}
-
- static mus_float_t pv_increment(mus_any *rd) {return((mus_float_t)(((pv_info *)rd)->interp));}
- static mus_float_t pv_set_increment(mus_any *rd, mus_float_t val) {((pv_info *)rd)->interp = (int)val; return(val);}
-
-
- static void pv_reset(mus_any *ptr)
- {
- pv_info *gen = (pv_info *)ptr;
- if (gen->in_data) free(gen->in_data);
- gen->in_data = NULL;
- gen->outctr = gen->interp;
- gen->filptr = 0;
- memset((void *)(gen->ampinc), 0, gen->N * sizeof(mus_float_t));
- memset((void *)(gen->freqs), 0, gen->N * sizeof(mus_float_t));
- memset((void *)(gen->amps), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->phases), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->lastphase), 0, (gen->N / 2) * sizeof(mus_float_t));
- memset((void *)(gen->phaseinc), 0, (gen->N / 2) * sizeof(mus_float_t));
- }
-
-
- static mus_any_class PHASE_VOCODER_CLASS = {
- MUS_PHASE_VOCODER,
- (char *)S_phase_vocoder,
- &free_phase_vocoder,
- &describe_phase_vocoder,
- &phase_vocoder_equalp,
- 0, 0,
- &pv_length, 0,
- &pv_frequency,
- &pv_set_frequency,
- 0, 0,
- 0, 0,
- &pv_increment,
- &pv_set_increment,
- &run_phase_vocoder,
- MUS_NOT_SPECIAL,
- &pv_closure,
- 0,
- 0, 0, 0, 0, 0, 0,
- &pv_hop, &pv_set_hop,
- 0, 0,
- 0, 0, 0, 0,
- &pv_outctr, &pv_set_outctr,
- 0, 0, 0, 0, 0,
- &pv_reset,
- &pv_set_closure,
- &pv_info_copy
- };
-
-
- static int pv_last_fftsize = -1;
- static mus_float_t *pv_last_window = NULL;
-
- mus_any *mus_make_phase_vocoder(mus_float_t (*input)(void *arg, int direction),
- int fftsize, int overlap, int interp,
- mus_float_t pitch,
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)),
- int (*edit)(void *arg),
- mus_float_t (*synthesize)(void *arg),
- void *closure)
- {
- /* order of args is trying to match src, granulate etc
- * the inclusion of pitch and interp provides built-in time/pitch scaling which is 99% of phase-vocoder use
- */
- pv_info *pv;
- int N2, D;
-
- N2 = (int)(fftsize / 2);
- if (N2 == 0) return(NULL);
- D = fftsize / overlap;
- if (D == 0) return(NULL);
-
- pv = (pv_info *)malloc(sizeof(pv_info));
- pv->core = &PHASE_VOCODER_CLASS;
- pv->N = fftsize;
- pv->D = D;
- pv->topN = 0;
- pv->interp = interp;
- pv->outctr = interp;
- pv->filptr = 0;
- pv->pitch = pitch;
- pv->ampinc = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->freqs = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->amps = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->phases = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->lastphase = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->phaseinc = (mus_float_t *)calloc(N2, sizeof(mus_float_t));
- pv->in_data = NULL;
- pv->input = input;
- pv->block_input = NULL;
- pv->closure = closure;
- pv->analyze = analyze;
- pv->edit = edit;
- pv->synthesize = synthesize;
- pv->calc = true;
-
- if ((fftsize == pv_last_fftsize) && (pv_last_window))
- {
- pv->win = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- memcpy((void *)(pv->win), (const void *)pv_last_window, fftsize * sizeof(mus_float_t));
- }
- else
- {
- int i;
- mus_float_t scl;
- if (pv_last_window) free(pv_last_window);
- pv_last_fftsize = fftsize;
- pv_last_window = (mus_float_t *)malloc(fftsize * sizeof(mus_float_t));
- pv->win = mus_make_fft_window(MUS_HAMMING_WINDOW, fftsize, 0.0);
- scl = 2.0 / (0.54 * (mus_float_t)fftsize);
- for (i = 0; i < fftsize; i++)
- pv->win[i] *= scl;
- memcpy((void *)pv_last_window, (const void *)(pv->win), fftsize * sizeof(mus_float_t));
- }
-
- #if HAVE_SINCOS
- /* in some cases, sincos is slower than sin+cos? Callgrind is seriously confused by it!
- * in Linux at least, sincos is faster than sin+sin -- in my timing tests, although
- * callgrind is crazy, the actual runtimes are about 25% faster (sincos vs sin+sin).
- */
- pv->cs = (double *)malloc(fftsize * sizeof(double));
- pv->sn = (double *)malloc(fftsize * sizeof(double));
- pv->sc_safe = (bool *)calloc(fftsize, sizeof(bool));
- pv->indices = (int *)malloc(N2 * sizeof(int));
- #endif
- return((mus_any *)pv);
- }
-
-
- mus_float_t mus_phase_vocoder_with_editors(mus_any *ptr,
- mus_float_t (*input)(void *arg, int direction),
- bool (*analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)),
- int (*edit)(void *arg),
- mus_float_t (*synthesize)(void *arg))
- {
- pv_info *pv = (pv_info *)ptr;
- int N2, i;
- mus_float_t sum, sum1;
- mus_float_t (*pv_synthesize)(void *arg) = synthesize;
-
- if (pv_synthesize == NULL) pv_synthesize = pv->synthesize;
- N2 = pv->N / 2;
-
- if (pv->outctr >= pv->interp)
- {
- mus_float_t scl;
- bool (*pv_analyze)(void *arg, mus_float_t (*input)(void *arg1, int direction)) = analyze;
- int (*pv_edit)(void *arg) = edit;
-
- if (pv_analyze == NULL) pv_analyze = pv->analyze;
- if (pv_edit == NULL) pv_edit = pv->edit;
- if (input) {pv->input = input; pv->block_input = NULL;}
- pv->outctr = 0;
-
- if ((pv_analyze == NULL) ||
- ((*pv_analyze)(pv->closure, pv->input)))
- {
- int buf;
- memset((void *)(pv->freqs), 0, pv->N * sizeof(mus_float_t));
- if (pv->in_data == NULL)
- {
- pv->in_data = (mus_float_t *)malloc(pv->N * sizeof(mus_float_t));
- if (pv->block_input)
- pv->block_input(pv->closure, 1, pv->in_data, 0, pv->N);
- else
- {
- for (i = 0; i < pv->N; i++)
- pv->in_data[i] = pv->input(pv->closure, 1);
- }
- }
- else
- {
- int j;
- /* if back-to-back here we could omit a lot of data movement or just use a circle here! */
- for (i = 0, j = pv->D; j < pv->N; i++, j++)
- pv->in_data[i] = pv->in_data[j];
-
- if (pv->block_input)
- pv->block_input(pv->closure, 1, pv->in_data, pv->N - pv->D, pv->N);
- else
- {
- for (i = pv->N - pv->D; i < pv->N; i++)
- pv->in_data[i] = pv->input(pv->closure, 1);
- }
- }
- buf = pv->filptr % pv->N;
- for (i = 0; i < pv->N; i++)
- {
- pv->ampinc[buf++] = pv->win[i] * pv->in_data[i];
- if (buf >= pv->N) buf = 0;
- }
- pv->filptr += pv->D;
- mus_fft(pv->ampinc, pv->freqs, pv->N, 1);
- mus_rectangular_to_polar(pv->ampinc, pv->freqs, N2);
- }
-
- if ((pv_edit == NULL) ||
- ((*pv_edit)(pv->closure)))
- {
- mus_float_t pscl, kscl, ks;
- pscl = 1.0 / (mus_float_t)(pv->D);
- kscl = TWO_PI / (mus_float_t)(pv->N);
- for (i = 0, ks = 0.0; i < N2; i++, ks += kscl)
- {
- mus_float_t diff;
- diff = pv->freqs[i] - pv->lastphase[i];
- pv->lastphase[i] = pv->freqs[i];
- while (diff > M_PI) diff -= TWO_PI;
- while (diff < -M_PI) diff += TWO_PI;
- pv->freqs[i] = pv->pitch * (diff * pscl + ks);
- }
- }
- /* it's possible to build the endpoint waveforms here and interpolate, but there is no savings.
- * other pvocs use ifft rather than sin-bank, but then they have to make excuses.
- * Something I didn't expect -- the algorithm above focusses on the active frequency!
- * For example, the 4 or so bins around a given peak all tighten
- * to 4 bins running at almost exactly the same frequency (the center).
- */
-
- scl = 1.0 / (mus_float_t)(pv->interp);
- #if HAVE_SINCOS
- pv->topN = 0;
- #else
- pv->topN = N2;
- #endif
-
- for (i = 0; i < N2; i++)
- {
- #if HAVE_SINCOS
- double s, c;
- bool amp_zero;
-
- amp_zero = ((pv->amps[i] < 1e-7) && (pv->ampinc[i] == 0.0));
- if (!amp_zero)
- {
- pv->indices[pv->topN++] = i;
-
- pv->sc_safe[i] = (fabs(pv->freqs[i] - pv->phaseinc[i]) < 0.02); /* .5 is too big, .01 and .03 ok by tests */
- if (pv->sc_safe[i])
- {
- sincos((pv->freqs[i] + pv->phaseinc[i]) * 0.5, &s, &c);
- pv->sn[i] = s;
- pv->cs[i] = c;
- }
- }
-
- if ((!(pv->synthesize)) && (amp_zero))
- {
- pv->phases[i] += (pv->interp * (pv->freqs[i] + pv->phaseinc[i]) * 0.5);
- pv->phaseinc[i] = pv->freqs[i];
- }
- else
- {
- pv->ampinc[i] = scl * (pv->ampinc[i] - pv->amps[i]);
- pv->freqs[i] = scl * (pv->freqs[i] - pv->phaseinc[i]);
- }
- #else
- pv->ampinc[i] = scl * (pv->ampinc[i] - pv->amps[i]);
- pv->freqs[i] = scl * (pv->freqs[i] - pv->phaseinc[i]);
- #endif
- }
- }
-
- pv->outctr++;
- if (pv_synthesize)
- return((*pv_synthesize)(pv->closure));
-
- if (pv->calc)
- {
- mus_float_t *pinc, *frq, *ph, *amp, *panc;
- int topN;
- #if HAVE_SINCOS
- int j;
- double *cs, *sn;
- #endif
-
- topN = pv->topN;
- pinc = pv->phaseinc;
- frq = pv->freqs;
- ph = pv->phases;
- amp = pv->amps;
- panc = pv->ampinc;
- #if HAVE_SINCOS
- cs = pv->cs;
- sn = pv->sn;
- #endif
-
- sum = 0.0;
- sum1 = 0.0;
-
- /* amps can be negative here due to rounding troubles
- * sincos is faster (using shell time command) except in virtualbox running linux on a mac?
- * (callgrind does not handle sincos correctly).
- *
- * this version (22-Jan-14) is slower if no sincos;
- * if sincos, we use sin(a + b) = sin(a)cos(b) + cos(a)sin(b)
- * since sin(b) and cos(b) are constant through the pv->interp (implicit) loop, they are calculated once above.
- * Then here we calculate 2 samples on each run through this loop. I wonder if we could center the true case,
- * and get 3 samples? If 2, the difference is very small (we're taking the midpoint of the phase increment change,
- * so the two are not quite the same). In tests, 10000 samples, channel-distance is ca .15.
- *
- * If the amp zero phase is off (incorrectly incremented above), the effect is a sort of low-pass filter??
- * Are we getting cancellation from the overlap?
- */
-
- #if HAVE_SINCOS
- for (j = 0; j < topN; j++)
- {
- double sx, cx;
-
- i = pv->indices[j];
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- sincos(ph[i], &sx, &cx);
- sum += (amp[i] * sx);
-
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (pv->sc_safe[i])
- sum1 += amp[i] * (sx * cs[i] + cx * sn[i]);
- else sum1 += amp[i] * sin(ph[i]);
- }
- #else
- for (i = 0; i < topN; i++)
- {
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (amp[i] > 0.0) sum += amp[i] * sin(ph[i]);
-
- pinc[i] += frq[i];
- ph[i] += pinc[i];
- amp[i] += panc[i];
- if (amp[i] > 0.0) sum1 += amp[i] * sin(ph[i]);
- }
- #endif
- pv->sum1 = sum1;
- pv->calc = false;
- return(sum);
- }
- pv->calc = true;
- return(pv->sum1);
- }
-
-
- mus_float_t mus_phase_vocoder(mus_any *ptr, mus_float_t (*input)(void *arg, int direction))
- {
- return(mus_phase_vocoder_with_editors(ptr, input, NULL, NULL, NULL));
- }
-
-
- void mus_generator_set_feeders(mus_any *g,
- mus_float_t (*feed)(void *arg, int direction),
- mus_float_t (*block_feed)(void *arg, int direction, mus_float_t *block, mus_long_t start, mus_long_t end))
- {
- if (mus_is_src(g))
- {
- ((sr *)g)->feeder = feed;
- ((sr *)g)->block_feeder = block_feed;
- }
- else
- {
- if (mus_is_granulate(g))
- {
- ((grn_info *)g)->rd = feed;
- ((grn_info *)g)->block_rd = block_feed;
- }
- else
- {
- if (mus_is_phase_vocoder(g))
- {
- ((pv_info *)g)->input = feed;
- ((pv_info *)g)->block_input = block_feed;
- }
- else
- {
- if (mus_is_convolve(g))
- {
- ((conv *)g)->feeder = feed;
- ((conv *)g)->block_feeder = block_feed;
- }
- }
- }
- }
- }
-
- void mus_generator_copy_feeders(mus_any *dest, mus_any *source)
- {
- if (mus_is_src(dest))
- {
- ((sr *)dest)->feeder = ((sr *)source)->feeder;
- ((sr *)dest)->block_feeder = ((sr *)source)->block_feeder;
- }
- else
- {
- if (mus_is_granulate(dest))
- {
- ((grn_info *)dest)->rd = ((grn_info *)source)->rd;
- ((grn_info *)dest)->block_rd = ((grn_info *)source)->block_rd;
- }
- else
- {
- if (mus_is_phase_vocoder(dest))
- {
- ((pv_info *)dest)->input = ((pv_info *)source)->input;
- ((pv_info *)dest)->block_input = ((pv_info *)source)->block_input;
- }
- else
- {
- if (mus_is_convolve(dest))
- {
- ((conv *)dest)->feeder = ((conv *)source)->feeder;
- ((conv *)dest)->block_feeder = ((conv *)source)->block_feeder;
- }
- }
- }
- }
- }
-
-
-
- /* ---------------- single sideband "suppressed carrier" amplitude modulation (ssb-am) ---------------- */
-
- typedef struct {
- mus_any_class *core;
- bool shift_up;
- mus_float_t *coeffs;
- mus_any *hilbert, *dly;
- #if (!HAVE_SINCOS)
- mus_any *sin_osc, *cos_osc;
- #else
- double phase, freq, sign;
- #endif
- int size;
- } ssbam;
-
-
- bool mus_is_ssb_am(mus_any *ptr)
- {
- return((ptr) &&
- (ptr->core->type == MUS_SSB_AM));
- }
-
- static mus_float_t run_hilbert(flt *gen, mus_float_t input)
- {
- mus_float_t xout = 0.0;
- mus_float_t *state, *ts, *x, *end;
-
- x = (mus_float_t *)(gen->x);
- state = (mus_float_t *)(gen->state + gen->loc);
- ts = (mus_float_t *)(state + gen->order);
-
- (*state) = input;
- (*ts) = input;
- state += 2;
- end = (mus_float_t *)(state + 20);
-
- while (ts > end)
- {
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- xout += (*ts) * (*x); ts -= 2; x += 2;
- }
- while (ts > state)
- {
- xout += (*ts) * (*x); ts -= 2; x += 2;
- }
-
- gen->loc++;
- if (gen->loc == gen->order)
- gen->loc = 0;
-
- return(xout + ((*ts) * (*x)));
- #if 0
- int i, len;
- mus_float_t val = 0.0;
- len = g->order;
- g->state[0] = insig;
- for (i = 0; i < len; i += 2) val += (g->x[i] * g->state[i]);
- for (i = len - 1; i >= 1; i--) g->state[i] = g->state[i - 1];
- return(val);
- #endif
- }
-
-
- mus_float_t mus_ssb_am_unmodulated(mus_any *ptr, mus_float_t insig)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- return((mus_oscil_unmodulated(gen->cos_osc) * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (mus_oscil_unmodulated(gen->sin_osc) * run_hilbert((flt *)(gen->hilbert), insig)));
- #else
- double cx, sx;
- sincos(gen->phase, &sx, &cx);
- gen->phase += gen->freq;
- return((cx * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (sx * gen->sign * run_hilbert((flt *)(gen->hilbert), insig)));
- #endif
- }
-
-
- mus_float_t mus_ssb_am(mus_any *ptr, mus_float_t insig, mus_float_t fm)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- return((mus_oscil_fm(gen->cos_osc, fm) * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (mus_oscil_fm(gen->sin_osc, fm) * run_hilbert((flt *)(gen->hilbert), insig)));
- #else
- double cx, sx;
- sincos(gen->phase, &sx, &cx);
- gen->phase += (fm + gen->freq);
- return((cx * mus_delay_unmodulated_noz(gen->dly, insig)) +
- (sx * gen->sign * run_hilbert((flt *)(gen->hilbert), insig)));
- #endif
- }
-
-
- static void free_ssb_am(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- mus_free(gen->dly);
- mus_free(gen->hilbert);
- #if (!HAVE_SINCOS)
- mus_free(gen->cos_osc);
- mus_free(gen->sin_osc);
- #endif
- if (gen->coeffs) {free(gen->coeffs); gen->coeffs = NULL;}
- free(ptr);
- }
-
-
- static mus_any *ssbam_copy(mus_any *ptr)
- {
- ssbam *g, *p;
- int bytes;
-
- p = (ssbam *)ptr;
- g = (ssbam *)malloc(sizeof(ssbam));
- memcpy((void *)g, (void *)ptr, sizeof(ssbam));
-
- g->dly = mus_copy(p->dly);
- g->hilbert = mus_copy(p->hilbert);
- #if (!HAVE_SINCOS)
- g->cos_osc = mus_copy(p->cos_osc);
- g->sin_osc = mus_copy(p->sin_osc);
- #endif
-
- bytes = p->size * sizeof(mus_float_t);
- g->coeffs = (mus_float_t *)malloc(bytes);
- memcpy((void *)(g->coeffs), (void *)(p->coeffs), bytes);
-
- return((mus_any *)g);
- }
-
-
- static mus_float_t ssb_am_freq(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(mus_radians_to_hz(((osc *)((ssbam *)ptr)->sin_osc)->freq));
- #else
- return(mus_radians_to_hz(((ssbam *)ptr)->freq));
- #endif
- }
-
-
- static mus_float_t ssb_am_set_freq(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- mus_float_t rads;
- rads = mus_hz_to_radians(val);
- #if (!HAVE_SINCOS)
- ((osc *)(gen->sin_osc))->freq = rads;
- ((osc *)(gen->cos_osc))->freq = rads;
- #else
- gen->freq = rads;
- #endif
- return(val);
- }
-
-
- static mus_float_t ssb_am_increment(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(((osc *)((ssbam *)ptr)->sin_osc)->freq);
- #else
- return(((ssbam *)ptr)->freq);
- #endif
- }
-
-
- static mus_float_t ssb_am_set_increment(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- ((osc *)(gen->sin_osc))->freq = val;
- ((osc *)(gen->cos_osc))->freq = val;
- #else
- gen->freq = val;
- #endif
- return(val);
- }
-
-
- static mus_float_t ssb_am_phase(mus_any *ptr)
- {
- #if (!HAVE_SINCOS)
- return(fmod(((osc *)((ssbam *)ptr)->cos_osc)->phase - 0.5 * M_PI, TWO_PI));
- #else
- return(fmod(((ssbam *)ptr)->phase, TWO_PI));
- #endif
- }
-
-
- static mus_float_t ssb_am_set_phase(mus_any *ptr, mus_float_t val)
- {
- ssbam *gen = (ssbam *)ptr;
- #if (!HAVE_SINCOS)
- if (gen->shift_up)
- ((osc *)(gen->sin_osc))->phase = val + M_PI;
- else ((osc *)(gen->sin_osc))->phase = val;
- ((osc *)(gen->cos_osc))->phase = val + 0.5 * M_PI;
- #else
- gen->phase = val;
- #endif
- return(val);
- }
-
-
- static mus_long_t ssb_am_order(mus_any *ptr) {return(mus_order(((ssbam *)ptr)->dly));}
-
- static int ssb_am_interp_type(mus_any *ptr) {return(delay_interp_type(((ssbam *)ptr)->dly));}
-
- static mus_float_t *ssb_am_data(mus_any *ptr) {return(filter_data(((ssbam *)ptr)->hilbert));}
- static mus_float_t ssb_am_run(mus_any *ptr, mus_float_t insig, mus_float_t fm) {return(mus_ssb_am(ptr, insig, fm));}
-
- static mus_float_t *ssb_am_xcoeffs(mus_any *ptr) {return(mus_xcoeffs(((ssbam *)ptr)->hilbert));}
- static mus_float_t ssb_am_xcoeff(mus_any *ptr, int index) {return(mus_xcoeff(((ssbam *)ptr)->hilbert, index));}
- static mus_float_t ssb_am_set_xcoeff(mus_any *ptr, int index, mus_float_t val) {return(mus_set_xcoeff(((ssbam *)ptr)->hilbert, index, val));}
-
-
- static bool ssb_am_equalp(mus_any *p1, mus_any *p2)
- {
- return((p1 == p2) ||
- ((mus_is_ssb_am((mus_any *)p1)) &&
- (mus_is_ssb_am((mus_any *)p2)) &&
- (((ssbam *)p1)->shift_up == ((ssbam *)p2)->shift_up) &&
- #if (!HAVE_SINCOS)
- (mus_equalp(((ssbam *)p1)->sin_osc, ((ssbam *)p2)->sin_osc)) &&
- (mus_equalp(((ssbam *)p1)->cos_osc, ((ssbam *)p2)->cos_osc)) &&
- #else
- (((ssbam *)p1)->freq == ((ssbam *)p2)->freq) &&
- (((ssbam *)p1)->phase == ((ssbam *)p2)->phase) &&
- #endif
- (mus_equalp(((ssbam *)p1)->dly, ((ssbam *)p2)->dly)) &&
- (mus_equalp(((ssbam *)p1)->hilbert, ((ssbam *)p2)->hilbert))));
- }
-
-
- static char *describe_ssb_am(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- char *describe_buffer;
- describe_buffer = (char *)malloc(DESCRIBE_BUFFER_SIZE);
- snprintf(describe_buffer, DESCRIBE_BUFFER_SIZE, "%s shift: %s, sin/cos: %f Hz (%f radians), order: %d",
- mus_name(ptr),
- (gen->shift_up) ? "up" : "down",
- mus_frequency(ptr),
- mus_phase(ptr),
- (int)mus_order(ptr));
- return(describe_buffer);
- }
-
-
- static void ssb_reset(mus_any *ptr)
- {
- ssbam *gen = (ssbam *)ptr;
- ssb_am_set_phase(ptr, 0.0);
- mus_reset(gen->dly);
- mus_reset(gen->hilbert);
- }
-
-
- static mus_any_class SSB_AM_CLASS = {
- MUS_SSB_AM,
- (char *)S_ssb_am,
- &free_ssb_am,
- &describe_ssb_am,
- &ssb_am_equalp,
- &ssb_am_data, 0,
- &ssb_am_order, 0,
- &ssb_am_freq,
- &ssb_am_set_freq,
- &ssb_am_phase,
- &ssb_am_set_phase,
- &fallback_scaler, 0,
- &ssb_am_increment,
- &ssb_am_set_increment,
- &ssb_am_run,
- MUS_NOT_SPECIAL,
- NULL,
- &ssb_am_interp_type,
- 0, 0, 0, 0,
- &ssb_am_xcoeff, &ssb_am_set_xcoeff,
- 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,
- 0, 0,
- &ssb_am_xcoeffs, 0,
- &ssb_reset,
- 0, &ssbam_copy
- };
-
-
- static int ssb_am_last_flen = -1;
- static mus_float_t *ssb_am_last_coeffs = NULL;
-
- mus_any *mus_make_ssb_am(mus_float_t freq, int order)
- {
- ssbam *gen;
- int len, flen;
-
- if ((order & 1) == 0) order++; /* if order is even, the first Hilbert coeff is 0.0 */
- gen = (ssbam *)malloc(sizeof(ssbam));
- gen->core = &SSB_AM_CLASS;
-
- if (freq > 0)
- gen->shift_up = true;
- else gen->shift_up = false;
- #if (!HAVE_SINCOS)
- gen->sin_osc = mus_make_oscil(fabs(freq), (gen->shift_up) ? M_PI : 0.0);
- gen->cos_osc = mus_make_oscil(fabs(freq), M_PI * 0.5);
- #else
- if (gen->shift_up) gen->sign = -1.0; else gen->sign = 1.0;
- gen->freq = mus_hz_to_radians(fabs(freq));
- gen->phase = 0.0;
- #endif
- gen->dly = mus_make_delay(order, NULL, order, MUS_INTERP_NONE);
-
- len = order * 2 + 1;
- flen = len + 1; /* even -- need 4 */
- if ((flen & 2) != 0) flen += 2;
- gen->size = flen;
-
- if ((flen == ssb_am_last_flen) && (ssb_am_last_coeffs))
- {
- gen->coeffs = (mus_float_t *)malloc(flen * sizeof(mus_float_t));
- memcpy((void *)(gen->coeffs), (const void *)ssb_am_last_coeffs, flen * sizeof(mus_float_t));
- }
- else
- {
- int i, k;
- gen->coeffs = (mus_float_t *)calloc(flen, sizeof(mus_float_t));
- for (i = -order, k = 0; i <= order; i++, k++)
- {
- mus_float_t denom, num;
- denom = i * M_PI;
- num = 1.0 - cos(denom);
- if (i == 0)
- gen->coeffs[k] = 0.0;
- else gen->coeffs[k] = (num / denom) * (0.54 + (0.46 * cos(denom / order)));
- }
- /* so odd numbered coeffs are zero */
-
- /* can't be too fancy here because there might be several of these gens running in parallel at different sizes */
- if (ssb_am_last_coeffs) free(ssb_am_last_coeffs);
- ssb_am_last_flen = flen;
- ssb_am_last_coeffs = (mus_float_t *)malloc(flen * sizeof(mus_float_t));
- memcpy((void *)(ssb_am_last_coeffs), (const void *)(gen->coeffs), flen * sizeof(mus_float_t));
- }
-
- gen->hilbert = mus_make_fir_filter(flen, gen->coeffs, NULL);
- return((mus_any *)gen);
- }
-
- /* (define (hi) (let ((g (make-ssb-am 100.0))) (ssb-am g 1.0) (ssb-am g 0.0))) */
-
-
-
-
-
- /* ---------------- mus-apply ---------------- */
-
- mus_float_t (*mus_run_function(mus_any *g))(mus_any *gen, mus_float_t arg1, mus_float_t arg2)
- {
- if (g)
- return(g->core->run);
- return(NULL);
- }
-
- mus_float_t mus_apply(mus_any *gen, mus_float_t f1, mus_float_t f2)
- {
- /* what about non-gen funcs such as polynomial, ring_modulate etc? */
- if ((gen) && (gen->core->run))
- return((*(gen->core->run))(gen, f1, f2));
- return(0.0);
- }
-
-
- /* ---------------- mix files ---------------- */
-
- /* a mixing "instrument" along the lines of the mix function in clm */
- /* this is a very commonly used function, so it's worth picking out the special cases for optimization */
-
- #define IDENTITY_MIX 0
- #define IDENTITY_MONO_MIX 1
- #define SCALED_MONO_MIX 2
- #define SCALED_MIX 3
- #define ENVELOPED_MONO_MIX 4
- #define ENVELOPED_MIX 5
- #define ALL_MIX 6
-
- static int mix_file_type(int out_chans, int in_chans, mus_float_t *mx, mus_any ***envs)
- {
- if (envs)
- {
- if ((in_chans == 1) && (out_chans == 1))
- {
- if (envs[0][0])
- return(ENVELOPED_MONO_MIX);
- return(SCALED_MONO_MIX);
- }
- else
- {
- if (mx)
- return(ALL_MIX);
- return(ENVELOPED_MIX);
- }
- }
- if (mx)
- {
- int i, j;
- if ((in_chans == 1) && (out_chans == 1))
- {
- if (mx[0] == 1.0)
- return(IDENTITY_MONO_MIX);
- return(SCALED_MONO_MIX);
- }
- for (i = 0; i < out_chans; i++)
- for (j = 0; j < in_chans; j++)
- if (((i == j) && (mx[i * in_chans + j] != 1.0)) ||
- ((i != j) && (mx[i * in_chans + j] != 0.0)))
- return(SCALED_MIX);
- }
- if ((in_chans == 1) && (out_chans == 1))
- return(IDENTITY_MONO_MIX);
- return(IDENTITY_MIX);
- }
-
-
- void mus_file_mix_with_reader_and_writer(mus_any *outf, mus_any *inf,
- mus_long_t out_start, mus_long_t out_framples, mus_long_t in_start,
- mus_float_t *mx, int mx_chans,
- mus_any ***envs)
- {
- int mixtype, in_chans, out_chans;
- mus_long_t inc, outc, out_end;
- mus_float_t *out_data, *in_data, *local_mx;
-
- out_chans = mus_channels(outf);
- if (out_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", mus_describe(outf), out_chans);
-
- in_chans = mus_channels(inf);
- if (in_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", mus_describe(inf), in_chans);
-
- out_end = out_start + out_framples;
- mixtype = mix_file_type(out_chans, in_chans, mx, envs);
-
- in_data = (mus_float_t *)calloc((in_chans < out_chans) ? out_chans : in_chans, sizeof(mus_float_t));
- out_data = (mus_float_t *)calloc((in_chans < out_chans) ? out_chans : in_chans, sizeof(mus_float_t));
-
- local_mx = mx;
-
- switch (mixtype)
- {
- case ENVELOPED_MONO_MIX:
- {
- mus_any *e;
- e = envs[0][0];
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, in_data[0] * mus_env(e));
- }
- }
- break;
-
- case ENVELOPED_MIX:
- if (mx == NULL)
- {
- int i;
- mx_chans = (in_chans < out_chans) ? out_chans : in_chans;
- local_mx = (mus_float_t *)calloc(mx_chans * mx_chans, sizeof(mus_float_t));
- for (i = 0; i < mx_chans; i++)
- local_mx[i * mx_chans + i] = 1.0;
- }
- /* fall through */
-
- case ALL_MIX:
- /* the general case -- possible envs/scalers on every mixer cell */
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- int j, k;
- for (j = 0; j < in_chans; j++)
- for (k = 0; k < out_chans; k++)
- if (envs[j][k])
- local_mx[j * mx_chans + k] = mus_env(envs[j][k]);
- mus_frample_to_file(outf, outc, mus_frample_to_frample(local_mx, mx_chans, mus_file_to_frample(inf, inc, in_data), in_chans, out_data, out_chans));
- }
- if (mx == NULL) free(local_mx);
- break;
-
- case IDENTITY_MONO_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, in_data[0]);
- }
- break;
-
- case IDENTITY_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- mus_frample_to_file(outf, outc, mus_file_to_frample(inf, inc, in_data));
- break;
-
- case SCALED_MONO_MIX:
- {
- mus_float_t scl;
- scl = mx[0];
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- {
- mus_file_to_frample(inf, inc, in_data);
- mus_outa_to_file(outf, outc, scl * in_data[0]);
- }
- }
- break;
-
- case SCALED_MIX:
- for (inc = in_start, outc = out_start; outc < out_end; inc++, outc++)
- mus_frample_to_file(outf, outc, mus_frample_to_frample(mx, mx_chans, mus_file_to_frample(inf, inc, in_data), in_chans, out_data, out_chans));
- break;
-
- }
- free(in_data);
- free(out_data);
- }
-
-
- void mus_file_mix(const char *outfile, const char *infile,
- mus_long_t out_start, mus_long_t out_framples, mus_long_t in_start,
- mus_float_t *mx, int mx_chans,
- mus_any ***envs)
- {
- int in_chans, out_chans, min_chans, mixtype;
-
- out_chans = mus_sound_chans(outfile);
- if (out_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", outfile, out_chans);
-
- in_chans = mus_sound_chans(infile);
- if (in_chans <= 0)
- mus_error(MUS_NO_CHANNELS, S_mus_file_mix ": %s chans: %d", infile, in_chans);
- if (out_chans > in_chans)
- min_chans = in_chans;
- else min_chans = out_chans;
-
- mixtype = mix_file_type(out_chans, in_chans, mx, envs);
- if (mixtype == ALL_MIX)
- {
- mus_any *inf, *outf;
- /* the general case -- possible envs/scalers on every mixer cell */
- outf = mus_continue_sample_to_file(outfile);
- inf = mus_make_file_to_frample(infile);
- mus_file_mix_with_reader_and_writer(outf, inf, out_start, out_framples, in_start, mx, mx_chans, envs);
- mus_free(inf);
- mus_free(outf);
- }
- else
- {
- mus_long_t j = 0;
- int i, m, ofd, ifd;
- mus_float_t scaler;
- mus_any *e;
- mus_float_t **obufs, **ibufs;
- mus_long_t offk, curoutframples;
-
- /* highly optimizable cases */
- obufs = (mus_float_t **)malloc(out_chans * sizeof(mus_float_t *));
- for (i = 0; i < out_chans; i++)
- obufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
-
- ibufs = (mus_float_t **)malloc(in_chans * sizeof(mus_float_t *));
- for (i = 0; i < in_chans; i++)
- ibufs[i] = (mus_float_t *)malloc(clm_file_buffer_size * sizeof(mus_float_t));
-
- ifd = mus_sound_open_input(infile);
- mus_file_seek_frample(ifd, in_start);
- mus_file_read(ifd, in_start, clm_file_buffer_size, in_chans, ibufs);
- ofd = mus_sound_reopen_output(outfile,
- out_chans,
- mus_sound_sample_type(outfile),
- mus_sound_header_type(outfile),
- mus_sound_data_location(outfile));
- curoutframples = mus_sound_framples(outfile);
- mus_file_seek_frample(ofd, out_start);
- mus_file_read(ofd, out_start, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start);
-
- switch (mixtype)
- {
- case IDENTITY_MONO_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += ibufs[0][j];
- }
- break;
-
- case IDENTITY_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- for (i = 0; i < min_chans; i++)
- obufs[i][j] += ibufs[i][j];
- }
- break;
-
- case SCALED_MONO_MIX:
- scaler = mx[0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += (mus_float_t)(scaler * ibufs[0][j]);
- }
- break;
-
- case SCALED_MIX:
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size , out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- for (i = 0; i < min_chans; i++)
- for (m = 0; m < in_chans; m++)
- obufs[i][j] += (mus_float_t)(ibufs[m][j] * mx[m * mx_chans + i]);
- }
- break;
-
- case ENVELOPED_MONO_MIX:
- e = envs[0][0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- obufs[0][j] += (mus_float_t)(mus_env(e) * ibufs[0][j]);
- }
- break;
-
- case ENVELOPED_MIX:
- e = envs[0][0];
- for (offk = 0, j = 0; offk < out_framples; offk++, j++)
- {
- if (j == clm_file_buffer_size)
- {
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- j = 0;
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ofd, out_start + offk, clm_file_buffer_size, out_chans, obufs);
- mus_file_seek_frample(ofd, out_start + offk);
- mus_file_read(ifd, in_start + offk, clm_file_buffer_size, in_chans, ibufs);
- }
- scaler = mus_env(e);
- for (i = 0; i < min_chans; i++)
- obufs[i][j] += (mus_float_t)(scaler * ibufs[i][j]);
- }
- break;
- }
-
- if (j > 0)
- mus_file_write(ofd, 0, j - 1, out_chans, obufs);
- if (curoutframples < (out_framples + out_start))
- curoutframples = out_framples + out_start;
- mus_sound_close_output(ofd, curoutframples * out_chans * mus_bytes_per_sample(mus_sound_sample_type(outfile)));
- mus_sound_close_input(ifd);
- for (i = 0; i < in_chans; i++) free(ibufs[i]);
- free(ibufs);
- for (i = 0; i < out_chans; i++) free(obufs[i]);
- free(obufs);
- }
- }
-
-
-
- /* ---------------- init clm ---------------- */
-
- void mus_initialize(void)
- {
- #define MULAW_ZERO 255
- #define ALAW_ZERO 213
- #define UBYTE_ZERO 128
-
- mus_generator_type = MUS_INITIAL_GEN_TAG;
- sampling_rate = MUS_DEFAULT_SAMPLING_RATE;
- w_rate = (TWO_PI / MUS_DEFAULT_SAMPLING_RATE);
- array_print_length = MUS_DEFAULT_ARRAY_PRINT_LENGTH;
- clm_file_buffer_size = MUS_DEFAULT_FILE_BUFFER_SIZE;
-
- #if HAVE_FFTW3 && HAVE_COMPLEX_TRIG
- last_c_fft_size = 0;
- /* is there a problem if the caller built fftw with --enable-threads?
- * How to tell via configure that we need to initialize the thread stuff in libfftw?
- */
- #endif
-
- sincs = 0;
- locsig_warned = NULL;
-
- sample_type_zero = (int *)calloc(MUS_NUM_SAMPLES, sizeof(int));
- sample_type_zero[MUS_MULAW] = MULAW_ZERO;
- sample_type_zero[MUS_ALAW] = ALAW_ZERO;
- sample_type_zero[MUS_UBYTE] = UBYTE_ZERO;
- #if MUS_LITTLE_ENDIAN
- sample_type_zero[MUS_UBSHORT] = 0x80;
- sample_type_zero[MUS_ULSHORT] = 0x8000;
- #else
- sample_type_zero[MUS_UBSHORT] = 0x8000;
- sample_type_zero[MUS_ULSHORT] = 0x80;
- #endif
- }
|