libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmDspFx.c 208KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832
  1. //| Copyright: (C) 2009-2020 Kevin Larke <contact AT larke DOT org>
  2. //| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
  3. //( { file_desc:"'snap' audio effects processor units." kw:[snap]}
  4. #include "cmPrefix.h"
  5. #include "cmGlobal.h"
  6. #include "cmFloatTypes.h"
  7. #include "cmComplexTypes.h"
  8. #include "cmRpt.h"
  9. #include "cmErr.h"
  10. #include "cmCtx.h"
  11. #include "cmMem.h"
  12. #include "cmMallocDebug.h"
  13. #include "cmLinkedHeap.h"
  14. #include "cmText.h"
  15. #include "cmMath.h"
  16. #include "cmFile.h"
  17. #include "cmFileSys.h"
  18. #include "cmSymTbl.h"
  19. #include "cmJson.h"
  20. #include "cmPrefs.h"
  21. #include "cmDspValue.h"
  22. #include "cmMsgProtocol.h"
  23. #include "cmThread.h"
  24. #include "cmUdpPort.h"
  25. #include "cmUdpNet.h"
  26. #include "cmSerialPort.h"
  27. #include "cmTime.h"
  28. #include "cmAudioSys.h"
  29. #include "cmProcObj.h"
  30. #include "cmDspCtx.h"
  31. #include "cmDspClass.h"
  32. #include "cmDspUi.h"
  33. #include "cmAudioFile.h"
  34. #include "cmProcObj.h"
  35. #include "cmProcTemplateMain.h"
  36. #include "cmProc.h"
  37. #include "cmMidi.h"
  38. #include "cmProc2.h"
  39. #include "cmProc3.h"
  40. #include "cmVectOpsTemplateMain.h"
  41. #include "app/cmPickup.h"
  42. #include "cmDspSys.h"
  43. //------------------------------------------------------------------------------------------------------------
  44. //)
  45. //( { label:cmDspDelay file_desc:"Simple audio delay with feedback." kw:[sunit] }
  46. enum
  47. {
  48. kBypassDyId,
  49. kTimeDyId,
  50. kFbDyId,
  51. kInDyId,
  52. kOutDyId
  53. };
  54. cmDspClass_t _cmDelayDC;
  55. typedef struct
  56. {
  57. cmDspInst_t inst;
  58. cmMDelay* delay;
  59. } cmDspDelay_t;
  60. cmDspInst_t* _cmDspDelayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  61. {
  62. unsigned chs = 1;
  63. cmDspVarArg_t args[] =
  64. {
  65. { "bypass",kBypassDyId,0,0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Bypass enable flag." },
  66. { "time", kTimeDyId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Max delay time in milliseconds" },
  67. { "fb", kFbDyId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Feedback" },
  68. { "in", kInDyId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  69. { "out", kOutDyId, 0, chs, kOutDsvFl | kAudioBufDsvFl, "Audio output." },
  70. { NULL, 0, 0, 0, 0 }
  71. };
  72. cmDspDelay_t* p = cmDspInstAlloc(cmDspDelay_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  73. // set default values for the parameters that were not explicitely set in the va_arg list
  74. cmDspSetDefaultBool( ctx, &p->inst, kBypassDyId,0, 0 );
  75. cmDspSetDefaultUInt( ctx, &p->inst, kTimeDyId, 0, 1000 );
  76. cmDspSetDefaultDouble( ctx, &p->inst ,kFbDyId, 0.0, 0.0 );
  77. cmReal_t dtimeMs = cmDspDefaultUInt(&p->inst,kTimeDyId);
  78. cmReal_t fbCoeff = cmDspDefaultDouble(&p->inst,kFbDyId);
  79. p->delay = cmMDelayAlloc(ctx->cmProcCtx,NULL, cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx), fbCoeff, 1, &dtimeMs, NULL );
  80. return &p->inst;
  81. }
  82. cmDspRC_t _cmDspDelayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  83. {
  84. cmDspRC_t rc = kOkDspRC;
  85. cmDspDelay_t* p = (cmDspDelay_t*)inst;
  86. cmMDelayFree(&p->delay);
  87. //cmCtxFree(&p->ctx);
  88. return rc;
  89. }
  90. cmDspRC_t _cmDspDelayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  91. {
  92. cmDspRC_t rc = kOkDspRC;
  93. rc = cmDspApplyAllDefaults(ctx,inst);
  94. return rc;
  95. }
  96. cmDspRC_t _cmDspDelayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  97. {
  98. cmDspDelay_t* p = (cmDspDelay_t*)inst;
  99. cmDspRC_t rc = kOkDspRC;
  100. unsigned iChIdx = 0;
  101. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInDyId,iChIdx);
  102. unsigned iSmpCnt = cmDspVarRows(inst,kInDyId);
  103. unsigned oChIdx = 0;
  104. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutDyId,oChIdx);
  105. unsigned oSmpCnt = cmDspVarRows(inst,kOutDyId);
  106. bool bypassFl= cmDspBool(inst,kBypassDyId);
  107. cmMDelayExec(p->delay,ip,op,cmMin(iSmpCnt,oSmpCnt),bypassFl);
  108. return rc;
  109. }
  110. cmDspRC_t _cmDspDelayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  111. {
  112. cmDspDelay_t* p = (cmDspDelay_t*)inst;
  113. cmDspRC_t rc= kOkDspRC;
  114. cmDspSetEvent(ctx,inst,evt);
  115. switch( evt->dstVarId )
  116. {
  117. case kBypassDyId:
  118. break;
  119. case kTimeDyId:
  120. p->delay->delayArray[0].delayMs = cmDspDouble(inst,kTimeDyId);
  121. break;
  122. case kFbDyId:
  123. p->delay->fbCoeff = cmDspDouble(inst,kFbDyId);
  124. break;
  125. default:
  126. { assert(0); }
  127. }
  128. return rc;
  129. }
  130. cmDspClass_t* cmDelayClassCons( cmDspCtx_t* ctx )
  131. {
  132. cmDspClassSetup(&_cmDelayDC,ctx,"Delay",
  133. NULL,
  134. _cmDspDelayAlloc,
  135. _cmDspDelayFree,
  136. _cmDspDelayReset,
  137. _cmDspDelayExec,
  138. _cmDspDelayRecv,
  139. NULL,NULL,
  140. "Simple delay.");
  141. return &_cmDelayDC;
  142. }
  143. //------------------------------------------------------------------------------------------------------------
  144. //)
  145. //( { label:cmDspMtDelay file_desc:"Multi-tap audio delay with feedback." kw:[sunit] }
  146. enum
  147. {
  148. kBypassMtId,
  149. kScaleMtId,
  150. kFbMtId,
  151. kInMtId,
  152. kOutMtId,
  153. kBaseMsMtId
  154. };
  155. cmDspClass_t _cmMtDelayDC;
  156. typedef struct
  157. {
  158. cmDspInst_t inst;
  159. cmMDelay* p;
  160. unsigned baseGainMtId;
  161. unsigned tapCnt;
  162. cmReal_t* msV;
  163. cmReal_t* gainV;
  164. unsigned printSymId;
  165. } cmDspMtDelay_t;
  166. // args: bypassFl, time_scale, feedback, tap_ms0, tap_gain0, tapms1, tap_gain1, ....
  167. cmDspInst_t* _cmDspMtDelayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  168. {
  169. va_list vl1;
  170. cmDspVarArg_t args[] =
  171. {
  172. { "bypass",kBypassMtId,0, 0, kInDsvFl | kBoolDsvFl | kReqArgDsvFl, "Bypass enable flag." },
  173. { "scale", kScaleMtId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Scale tap times. (0.0 - 1.0)" },
  174. { "fb", kFbMtId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Feedback" },
  175. { "in", kInMtId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  176. { "out", kOutMtId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output." },
  177. };
  178. // verify that at least one var arg exists
  179. if( va_cnt < 5 || cmIsEvenU(va_cnt) )
  180. {
  181. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The 'multi-tap delay requires at least 5 arguments. Three fixed arguments and groups of two tap specification arguments.");
  182. return NULL;
  183. }
  184. va_copy(vl1,vl);
  185. unsigned reqArgCnt = 3;
  186. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  187. unsigned tapCnt = (va_cnt - reqArgCnt)/2;
  188. cmReal_t* msV = cmMemAllocZ(cmReal_t,tapCnt);
  189. cmReal_t* gainV = cmMemAllocZ(cmReal_t,tapCnt);
  190. unsigned argCnt = fixArgCnt + 2 * tapCnt;
  191. unsigned baseGainMtId = kBaseMsMtId + tapCnt;
  192. cmDspVarArg_t a[ argCnt+1 ];
  193. unsigned i;
  194. // Get the taps and gains
  195. va_arg(vl1,int); // enable
  196. va_arg(vl1,double); // time scale
  197. va_arg(vl1,double); // feedback
  198. for(i=0; i<tapCnt; ++i)
  199. {
  200. msV[i] = va_arg(vl1,double);
  201. gainV[i] = va_arg(vl1,double);
  202. }
  203. // setup the output gain args
  204. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  205. cmDspArgSetupN(ctx, a, argCnt, kBaseMsMtId, tapCnt, "ms", kBaseMsMtId, 0, 0, kInDsvFl | kDoubleDsvFl, "Tap delay times in milliseconds.");
  206. cmDspArgSetupN(ctx, a, argCnt, baseGainMtId, tapCnt, "gain", baseGainMtId, 0, 0, kInDsvFl | kDoubleDsvFl, "Tap delay linear gain.");
  207. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  208. cmDspMtDelay_t* p = cmDspInstAlloc(cmDspMtDelay_t,ctx,classPtr,a,instSymId,id,storeSymId,reqArgCnt,vl1);
  209. p->p = cmMDelayAlloc(ctx->cmProcCtx,NULL,0, 0, 0, 0, NULL, NULL );
  210. p->baseGainMtId = baseGainMtId;
  211. p->tapCnt = tapCnt;
  212. p->msV = msV;
  213. p->gainV = gainV;
  214. p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"_print");
  215. for(i=0; i<tapCnt; ++i)
  216. {
  217. cmDspSetDefaultDouble(ctx,&p->inst,kBaseMsMtId+i, 0.0, msV[i]);
  218. cmDspSetDefaultDouble(ctx,&p->inst,baseGainMtId+i, 0.0, gainV[i]);
  219. }
  220. va_end(vl1);
  221. return &p->inst;
  222. }
  223. cmDspRC_t _cmDspMtDelayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  224. {
  225. cmDspRC_t rc = kOkDspRC;
  226. cmDspMtDelay_t* p = (cmDspMtDelay_t*)inst;
  227. cmMemFree(p->msV);
  228. cmMemFree(p->gainV);
  229. cmMDelayFree(&p->p);
  230. return rc;
  231. }
  232. cmDspRC_t _cmDspMtDelayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  233. {
  234. cmDspRC_t rc = kOkDspRC;
  235. cmDspMtDelay_t* p = (cmDspMtDelay_t*)inst;
  236. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  237. {
  238. cmMDelayInit(p->p,cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx), cmDspDouble(&p->inst,kFbMtId), p->tapCnt, p->msV, p->gainV );
  239. }
  240. return rc;
  241. }
  242. cmDspRC_t _cmDspMtDelayExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  243. {
  244. cmDspMtDelay_t* p = (cmDspMtDelay_t*)inst;
  245. cmDspRC_t rc = kOkDspRC;
  246. unsigned iChIdx = 0;
  247. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInMtId,iChIdx);
  248. unsigned iSmpCnt = cmDspVarRows(inst,kInMtId);
  249. unsigned oChIdx = 0;
  250. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutMtId,oChIdx);
  251. unsigned oSmpCnt = cmDspVarRows(inst,kOutMtId);
  252. bool bypassFl= cmDspBool(inst,kBypassMtId);
  253. if( ip != NULL )
  254. cmMDelayExec(p->p,ip,op,cmMin(iSmpCnt,oSmpCnt),bypassFl);
  255. return rc;
  256. }
  257. cmDspRC_t _cmDspMtDelayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  258. {
  259. cmDspMtDelay_t* p = (cmDspMtDelay_t*)inst;
  260. cmDspRC_t rc= kOkDspRC;
  261. cmDspSetEvent(ctx,inst,evt);
  262. // set tap times
  263. if( kBaseMsMtId <= evt->dstVarId && evt->dstVarId < kBaseMsMtId + p->p->delayCnt )
  264. cmMDelaySetTapMs(p->p,evt->dstVarId - kBaseMsMtId, cmDspDouble(inst,evt->dstVarId));
  265. else
  266. // set tap gains
  267. if( p->baseGainMtId <= evt->dstVarId && evt->dstVarId < p->baseGainMtId + p->p->delayCnt )
  268. cmMDelaySetTapGain(p->p,evt->dstVarId - p->baseGainMtId, cmDspDouble(inst,evt->dstVarId));
  269. else
  270. {
  271. switch( evt->dstVarId )
  272. {
  273. case kScaleMtId:
  274. //cmDspDouble(inst,kScaleMtId);
  275. break;
  276. case kFbMtId:
  277. p->p->fbCoeff = cmDspDouble(inst,kFbMtId);
  278. break;
  279. }
  280. }
  281. return rc;
  282. }
  283. cmDspRC_t _cmDspMtDelayRecvFunc( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned attrSymId, const cmDspValue_t* value )
  284. {
  285. cmDspRC_t rc = kOkDspRC;
  286. cmDspMtDelay_t* p = (cmDspMtDelay_t*)inst;
  287. if( cmDsvIsSymbol(value) && (cmDsvSymbol(value)==p->printSymId) )
  288. {
  289. int i;
  290. cmRptPrintf(ctx->rpt,"taps:%i\n",p->tapCnt);
  291. for(i=0; i<p->tapCnt; ++i)
  292. cmRptPrintf(ctx->rpt,"%f %f\n",p->msV[i],p->gainV[i]);
  293. cmMDelayReport(p->p, ctx->rpt );
  294. }
  295. return rc;
  296. }
  297. cmDspClass_t* cmMtDelayClassCons( cmDspCtx_t* ctx )
  298. {
  299. cmDspClassSetup(&_cmMtDelayDC,ctx,"MtDelay",
  300. NULL,
  301. _cmDspMtDelayAlloc,
  302. _cmDspMtDelayFree,
  303. _cmDspMtDelayReset,
  304. _cmDspMtDelayExec,
  305. _cmDspMtDelayRecv,
  306. NULL,
  307. _cmDspMtDelayRecvFunc,
  308. "Multi-tap delay.");
  309. return &_cmMtDelayDC;
  310. }
  311. //------------------------------------------------------------------------------------------------------------
  312. //)
  313. //( { label:cmDspPShift file_desc:"Time-domain pitch shifter." kw:[sunit] }
  314. enum
  315. {
  316. kBypassPsId,
  317. kRatioPsId,
  318. kInPsId,
  319. kOutPsId
  320. };
  321. cmDspClass_t _cmPShiftDC;
  322. typedef struct
  323. {
  324. cmDspInst_t inst;
  325. //cmCtx* ctx;
  326. cmPitchShift* pshift;
  327. } cmDspPShift_t;
  328. cmDspInst_t* _cmDspPShiftAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  329. {
  330. unsigned chs = 1;
  331. cmDspVarArg_t args[] =
  332. {
  333. { "bypass",kBypassPsId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Bypass enable flag." },
  334. { "ratio", kRatioPsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Ratio" },
  335. { "in", kInPsId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  336. { "out", kOutPsId, 0, chs, kOutDsvFl | kAudioBufDsvFl, "Audio output." },
  337. { NULL, 0, 0, 0, 0 }
  338. };
  339. cmDspPShift_t* p = cmDspInstAlloc(cmDspPShift_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  340. // set default values for the parameters that were not explicitely set in the va_arg list
  341. cmDspSetDefaultBool( ctx, &p->inst, kBypassPsId, 0, 0 );
  342. cmDspSetDefaultDouble( ctx, &p->inst ,kRatioPsId, 0.0, 1.0 );
  343. p->pshift = cmPitchShiftAlloc(ctx->cmProcCtx,NULL,cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx) );
  344. return &p->inst;
  345. }
  346. cmDspRC_t _cmDspPShiftFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  347. {
  348. cmDspRC_t rc = kOkDspRC;
  349. cmDspPShift_t* p = (cmDspPShift_t*)inst;
  350. cmPitchShiftFree(&p->pshift);
  351. //cmCtxFree(&p->ctx);
  352. return rc;
  353. }
  354. cmDspRC_t _cmDspPShiftReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  355. {
  356. cmDspRC_t rc = kOkDspRC;
  357. rc = cmDspApplyAllDefaults(ctx,inst);
  358. return rc;
  359. }
  360. cmDspRC_t _cmDspPShiftExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  361. {
  362. cmDspPShift_t* p = (cmDspPShift_t*)inst;
  363. cmDspRC_t rc = kOkDspRC;
  364. unsigned iChIdx = 0;
  365. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInPsId,iChIdx);
  366. unsigned iSmpCnt = cmDspVarRows(inst,kInPsId);
  367. unsigned oChIdx = 0;
  368. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutPsId,oChIdx);
  369. unsigned oSmpCnt = cmDspVarRows(inst,kOutPsId);
  370. bool bypassFl= cmDspBool(inst,kBypassPsId);
  371. cmPitchShiftExec(p->pshift,ip,op,cmMin(iSmpCnt,oSmpCnt),cmDspDouble(inst,kRatioPsId),bypassFl);
  372. return rc;
  373. }
  374. cmDspRC_t _cmDspPShiftRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  375. {
  376. return cmDspSetEvent(ctx,inst,evt);
  377. }
  378. cmDspClass_t* cmPShiftClassCons( cmDspCtx_t* ctx )
  379. {
  380. cmDspClassSetup(&_cmPShiftDC,ctx,"PShift",
  381. NULL,
  382. _cmDspPShiftAlloc,
  383. _cmDspPShiftFree,
  384. _cmDspPShiftReset,
  385. _cmDspPShiftExec,
  386. _cmDspPShiftRecv,
  387. NULL,NULL,
  388. "Pitch Shifter.");
  389. return &_cmPShiftDC;
  390. }
  391. //------------------------------------------------------------------------------------------------------------
  392. //)
  393. //( { label:cmDspLoopRecd file_desc:"Loop recorder." kw:[sunit] }
  394. enum
  395. {
  396. kTimeLrId,
  397. kPGainLrId,
  398. kRGainLrId,
  399. kBypassLrId,
  400. kPlayLrId,
  401. kRecdLrId,
  402. kRatioLrId,
  403. kInLrId,
  404. kOutLrId
  405. };
  406. cmDspClass_t _cmLoopRecdDC;
  407. typedef struct
  408. {
  409. cmDspInst_t inst;
  410. //cmCtx* ctx;
  411. bool playFl;
  412. cmLoopRecord* lrp;
  413. } cmDspLoopRecd_t;
  414. cmDspInst_t* _cmDspLoopRecdAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  415. {
  416. unsigned chs = 1;
  417. cmDspVarArg_t args[] =
  418. {
  419. { "time", kTimeLrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Max record time in seconds" },
  420. { "pgain", kPGainLrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Pass-through gain."},
  421. { "rgain", kRGainLrId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Recorder out gain."},
  422. { "bypass",kBypassLrId,0, 0, kInDsvFl | kBoolDsvFl, "Bypass flag"},
  423. { "play", kPlayLrId, 0, 0, kInDsvFl | kBoolDsvFl, "Play gate flag" },
  424. { "recd", kRecdLrId, 0, 0, kInDsvFl | kBoolDsvFl, "Recd gate flag" },
  425. { "ratio", kRatioLrId, 0, 0, kInDsvFl | kDoubleDsvFl, "Playback speed ratio"},
  426. { "in", kInLrId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  427. { "out", kOutLrId, 0, chs, kOutDsvFl | kAudioBufDsvFl, "Audio output." },
  428. { NULL, 0, 0, 0, 0 }
  429. };
  430. cmDspLoopRecd_t* p = cmDspInstAlloc(cmDspLoopRecd_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  431. // set default values for the parameters that were not explicitely set in the va_arg list
  432. cmDspSetDefaultDouble( ctx, &p->inst, kTimeLrId, 0, 10 );
  433. cmDspSetDefaultDouble( ctx, &p->inst, kPGainLrId, 0, 1.0 );
  434. cmDspSetDefaultDouble( ctx, &p->inst, kRGainLrId, 0, 1.0 );
  435. cmDspSetDefaultBool( ctx, &p->inst, kBypassLrId, 0, 0 );
  436. cmDspSetDefaultBool( ctx, &p->inst, kPlayLrId, 0, 0 );
  437. cmDspSetDefaultBool( ctx, &p->inst, kRecdLrId, 0, 0 );
  438. cmDspSetDefaultDouble( ctx, &p->inst, kRatioLrId, 0, 1.0);
  439. p->lrp = cmLoopRecordAlloc(ctx->cmProcCtx,NULL,0,0,0 );
  440. return &p->inst;
  441. }
  442. cmDspRC_t _cmDspLoopRecdFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  443. {
  444. cmDspRC_t rc = kOkDspRC;
  445. cmDspLoopRecd_t* p = (cmDspLoopRecd_t*)inst;
  446. cmLoopRecordFree(&p->lrp);
  447. //cmCtxFree(&p->ctx);
  448. return rc;
  449. }
  450. cmDspRC_t _cmDspLoopRecdReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  451. {
  452. cmDspRC_t rc = kOkDspRC;
  453. cmDspLoopRecd_t* p = (cmDspLoopRecd_t*)inst;
  454. rc = cmDspApplyAllDefaults(ctx,inst);
  455. cmReal_t maxRecdTimeSecs = cmDspDefaultDouble(&p->inst,kTimeLrId);
  456. unsigned maxRecdTimeSmps = floor(cmDspSampleRate(ctx) * maxRecdTimeSecs);
  457. unsigned xfadeTimeSmps = floor(cmDspSampleRate(ctx) * 50.0/1000.0);
  458. if( maxRecdTimeSmps != p->lrp->maxRecdSmpCnt || xfadeTimeSmps != p->lrp->xfadeSmpCnt )
  459. cmLoopRecordInit(p->lrp,cmDspSamplesPerCycle(ctx),maxRecdTimeSmps,xfadeTimeSmps);
  460. return rc;
  461. }
  462. cmDspRC_t _cmDspLoopRecdExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  463. {
  464. cmDspLoopRecd_t* p = (cmDspLoopRecd_t*)inst;
  465. cmDspRC_t rc = kOkDspRC;
  466. unsigned iChIdx = 0;
  467. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInLrId,iChIdx);
  468. unsigned iSmpCnt = cmDspVarRows(inst,kInLrId);
  469. unsigned oChIdx = 0;
  470. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutLrId,oChIdx);
  471. unsigned oSmpCnt = cmDspVarRows(inst,kOutLrId);
  472. bool recdFl = cmDspBool(inst,kRecdLrId);
  473. bool bypassFl = cmDspBool(inst,kBypassLrId);
  474. double ratio = cmDspDouble(inst,kRatioLrId);
  475. double rgain = cmDspDouble(inst,kRGainLrId); // recorder output gain
  476. double pgain = cmDspDouble(inst,kPGainLrId); // pass through gain
  477. if( ip != NULL && op != NULL )
  478. cmLoopRecordExec(p->lrp,ip,op,cmMin(iSmpCnt,oSmpCnt), bypassFl, recdFl, p->playFl, ratio, pgain, rgain );
  479. p->playFl = false;
  480. return rc;
  481. }
  482. cmDspRC_t _cmDspLoopRecdRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  483. {
  484. cmDspLoopRecd_t* p = (cmDspLoopRecd_t*)inst;
  485. cmDspRC_t rc = cmDspSetEvent(ctx,inst,evt);
  486. switch(evt->dstVarId)
  487. {
  488. case kPlayLrId:
  489. p->playFl = cmDspBool(inst,kPlayLrId);
  490. break;
  491. }
  492. return rc;
  493. }
  494. cmDspClass_t* cmLoopRecdClassCons( cmDspCtx_t* ctx )
  495. {
  496. cmDspClassSetup(&_cmLoopRecdDC,ctx,"LoopRecd",
  497. NULL,
  498. _cmDspLoopRecdAlloc,
  499. _cmDspLoopRecdFree,
  500. _cmDspLoopRecdReset,
  501. _cmDspLoopRecdExec,
  502. _cmDspLoopRecdRecv,
  503. NULL,NULL,
  504. "Loop recorder.");
  505. return &_cmLoopRecdDC;
  506. }
  507. //------------------------------------------------------------------------------------------------------------
  508. //)
  509. //( { label:cmDspRectify file_desc:"Full-wave rectifier." kw:[sunit] }
  510. enum
  511. {
  512. kBypassRcId,
  513. kCoeffRcId,
  514. kInRcId,
  515. kOutRcId
  516. };
  517. cmDspClass_t _cmRectifyDC;
  518. typedef struct
  519. {
  520. cmDspInst_t inst;
  521. } cmDspRectify_t;
  522. cmDspInst_t* _cmDspRectifyAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  523. {
  524. unsigned chs = 1;
  525. cmDspVarArg_t args[] =
  526. {
  527. { "bypass",kBypassRcId,0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Bypass enable flag." },
  528. { "coeff", kCoeffRcId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Coefficient" },
  529. { "in", kInRcId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  530. { "out", kOutRcId, 0, chs, kOutDsvFl | kAudioBufDsvFl, "Audio output." },
  531. { NULL, 0, 0, 0, 0 }
  532. };
  533. cmDspRectify_t* p = cmDspInstAlloc(cmDspRectify_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  534. // set default values for the parameters that were not explicitely set in the va_arg list
  535. cmDspSetDefaultBool( ctx, &p->inst, kBypassRcId,0, 0 );
  536. cmDspSetDefaultDouble( ctx, &p->inst, kCoeffRcId, 0, 0.0 );
  537. return &p->inst;
  538. }
  539. cmDspRC_t _cmDspRectifyFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  540. {
  541. return kOkDspRC;
  542. }
  543. cmDspRC_t _cmDspRectifyReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  544. {
  545. cmDspRC_t rc = kOkDspRC;
  546. rc = cmDspApplyAllDefaults(ctx,inst);
  547. return rc;
  548. }
  549. cmDspRC_t _cmDspRectifyExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  550. {
  551. unsigned iChIdx = 0;
  552. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInRcId,iChIdx);
  553. unsigned iSmpCnt = cmDspVarRows(inst,kInRcId);
  554. unsigned oChIdx = 0;
  555. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutRcId,oChIdx);
  556. unsigned oSmpCnt = cmDspVarRows(inst,kOutRcId);
  557. bool bypassFl= cmDspBool(inst,kBypassRcId);
  558. unsigned n = cmMin(iSmpCnt,oSmpCnt);
  559. unsigned i;
  560. if( bypassFl )
  561. memcpy(op,ip,n*sizeof(cmSample_t));
  562. else
  563. {
  564. for(i=0; i<n; ++i)
  565. op[i] = ip[i] > 0 ? ip[i] : 0;
  566. }
  567. return kOkDspRC;
  568. }
  569. cmDspRC_t _cmDspRectifyRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  570. {
  571. return cmDspSetEvent(ctx,inst,evt);
  572. }
  573. cmDspClass_t* cmRectifyClassCons( cmDspCtx_t* ctx )
  574. {
  575. cmDspClassSetup(&_cmRectifyDC,ctx,"Rectify",
  576. NULL,
  577. _cmDspRectifyAlloc,
  578. _cmDspRectifyFree,
  579. _cmDspRectifyReset,
  580. _cmDspRectifyExec,
  581. _cmDspRectifyRecv,
  582. NULL,NULL,
  583. "Half-wave rectifier.");
  584. return &_cmRectifyDC;
  585. }
  586. //------------------------------------------------------------------------------------------------------------
  587. //)
  588. //( { label:cmDspGateDetect file_desc:"Track the onset and offset of an incoming signal." kw:[sunit] }
  589. enum
  590. {
  591. kWndMsGdId,
  592. kOnThreshPctGdId,
  593. kOnThreshDbGdId,
  594. kOffThreshDbGdId,
  595. kInGdId,
  596. kGateGdId,
  597. kRmsGdId,
  598. kMeanGdId
  599. };
  600. cmDspClass_t _cmGateDetectDC;
  601. typedef struct
  602. {
  603. cmDspInst_t inst;
  604. //cmCtx* ctx;
  605. cmShiftBuf* sbp;
  606. cmGateDetect* gdp;
  607. } cmDspGateDetect_t;
  608. cmDspInst_t* _cmDspGateDetectAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  609. {
  610. cmDspVarArg_t args[] =
  611. {
  612. { "wnd", kWndMsGdId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Window length in milliseconds." },
  613. { "onpct", kOnThreshPctGdId,0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Onset slope threshold [0.0 - 1.0]." },
  614. { "ondb", kOnThreshDbGdId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Onset threshold dB [-Inf to 0]" },
  615. { "offdb", kOffThreshDbGdId,0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Offset threshold dB [-Inf to 0]" },
  616. { "in", kInGdId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  617. { "gate", kGateGdId, 0, 0, kOutDsvFl | kBoolDsvFl, "Gate state output." },
  618. { "rms", kRmsGdId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Signal level RMS"},
  619. { "mean", kMeanGdId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Derr mean."},
  620. { NULL, 0, 0, 0, 0 }
  621. };
  622. cmDspGateDetect_t* p = cmDspInstAlloc(cmDspGateDetect_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  623. p->sbp = cmShiftBufAlloc(ctx->cmProcCtx,NULL,0,0,0);
  624. p->gdp = cmGateDetectAlloc(ctx->cmProcCtx,NULL,0,0,0,0);
  625. // set default values for the parameters that were not explicitely set in the va_arg list
  626. cmDspSetDefaultDouble( ctx, &p->inst, kWndMsGdId, 0, 42 );
  627. cmDspSetDefaultDouble( ctx, &p->inst, kOnThreshPctGdId, 0, 0.8 );
  628. cmDspSetDefaultDouble( ctx, &p->inst, kOnThreshDbGdId, 0, -30.0 );
  629. cmDspSetDefaultDouble( ctx, &p->inst, kOffThreshDbGdId, 0, -60.0 );
  630. return &p->inst;
  631. }
  632. cmDspRC_t _cmDspGateDetectFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  633. {
  634. cmDspGateDetect_t* p = (cmDspGateDetect_t*)inst;
  635. cmGateDetectFree(&p->gdp);
  636. cmShiftBufFree(&p->sbp);
  637. //cmCtxFree(&p->ctx);
  638. return kOkDspRC;
  639. }
  640. cmDspRC_t _cmDspGateDetectReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  641. {
  642. cmDspGateDetect_t* p = (cmDspGateDetect_t*)inst;
  643. cmDspRC_t rc = kOkDspRC;
  644. if((rc = cmDspApplyAllDefaults(ctx,inst)) != kOkDspRC )
  645. return rc;
  646. double wndMs = cmDspDouble(inst,kWndMsGdId);
  647. double sr = cmDspSampleRate(ctx);
  648. unsigned wndSmpCnt = floor(wndMs * sr / 1000.0);
  649. if( cmShiftBufInit(p->sbp, cmDspSamplesPerCycle(ctx), wndSmpCnt, wndSmpCnt/4 ) != cmOkRC )
  650. return cmErrMsg(&ctx->cmCtx->err,kInstResetFailDspRC,"The gate detector shift buffer initialization failed.");
  651. if( cmGateDetectInit(p->gdp, cmDspSamplesPerCycle(ctx), cmDspDouble(inst,kOnThreshPctGdId), cmDspDouble(inst,kOnThreshDbGdId), cmDspDouble(inst,kOffThreshDbGdId) ) != cmOkRC )
  652. return cmErrMsg(&ctx->cmCtx->err,kInstResetFailDspRC,"The gate detector shift buffer initialization failed.");
  653. return rc;
  654. }
  655. cmDspRC_t _cmDspGateDetectExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  656. {
  657. cmDspGateDetect_t* p = (cmDspGateDetect_t*)inst;
  658. unsigned iChIdx = 0;
  659. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInGdId,iChIdx);
  660. unsigned iSmpCnt = cmDspVarRows(inst,kInGdId);
  661. while( cmShiftBufExec(p->sbp, ip, iSmpCnt ) )
  662. {
  663. cmGateDetectExec(p->gdp,p->sbp->outV, p->sbp->outN );
  664. cmDspSetDouble(ctx,inst,kRmsGdId,p->gdp->rms);
  665. cmDspSetDouble(ctx,inst,kMeanGdId,p->gdp->mean);
  666. if( p->gdp->deltaFl )
  667. cmDspSetBool( ctx,inst,kGateGdId,p->gdp->gateFl);
  668. }
  669. return kOkDspRC;
  670. }
  671. cmDspRC_t _cmDspGateDetectRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  672. {
  673. cmDspRC_t rc;
  674. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  675. return rc;
  676. switch(evt->dstVarId)
  677. {
  678. case kWndMsGdId:
  679. break;
  680. case kOnThreshPctGdId:
  681. break;
  682. case kOnThreshDbGdId:
  683. break;
  684. case kOffThreshDbGdId:
  685. break;
  686. case kInGdId:
  687. break;
  688. }
  689. return rc;
  690. }
  691. cmDspClass_t* cmGateDetectClassCons( cmDspCtx_t* ctx )
  692. {
  693. cmDspClassSetup(&_cmGateDetectDC,ctx,"GateDetect",
  694. NULL,
  695. _cmDspGateDetectAlloc,
  696. _cmDspGateDetectFree,
  697. _cmDspGateDetectReset,
  698. _cmDspGateDetectExec,
  699. _cmDspGateDetectRecv,
  700. NULL,NULL,
  701. "Gate detector.");
  702. return &_cmGateDetectDC;
  703. }
  704. //------------------------------------------------------------------------------------------------------------
  705. //)
  706. //( { label:cmDspAutoGain file_desc:"Normalize a set of audio input signals to acheive a consistent level." kw:[sunit] }
  707. // The purpose of this object is to calculate, store and retrieve gain coefficents
  708. // for a set of audio channels. The gain coefficients are designed to balance the
  709. // volume of each channel relative to the others. During gain calibration
  710. // a sample of each channel is taken and it's average volume is determined.
  711. // After an example of all channels has been received a new set of gain coefficients
  712. // is calculated which decreases the volume of loud channels and increases the
  713. // volume of quiet channels.
  714. //
  715. // The gain coefficents are made available via a set of 'gain-###' output ports.
  716. //
  717. // This object acts as an interface to the cmAutoGain processor.
  718. //
  719. // As input it takes a channel configuration JSON file of the form:
  720. // {
  721. // ch_array :
  722. // [ ["ch","ssi","pitch","midi","gain"]
  723. // [ 0, 0, "C4", 60, 1.0 ]
  724. // ....
  725. // [ n 0, "C5", 72, 1.0 ]
  726. // ]
  727. // }
  728. //
  729. // Each array in 'ch_array' gives the configuration of a channel.
  730. //
  731. //
  732. // It also requires a JSON resource object of the form
  733. // gdParms:
  734. // {
  735. // medCnt: 5
  736. // avgCnt: 9
  737. // suprCnt: 6
  738. // offCnt: 3
  739. // suprCoeff: 1.400000
  740. // onThreshDb: -53.000000
  741. // offThreshDb: -80.000000
  742. // }
  743. //
  744. // These arguments are used to configure the cmAutoGain Proessor gate detector function.
  745. //
  746. // During runtime the object accepts the following action selector symbol id's:
  747. // a. start - begin a new calibration session
  748. // b. proc - end a calibration session and calculate new gain coeff's
  749. // c. cancel - cancel a calibration session
  750. // d. write - write the channel configuration file
  751. // e. print - print the current auto gain calibration state
  752. //
  753. // After a 'start' msg the object accepts channel id's throught its 'id' input port.
  754. // Each 'id' identifies the channel which it will process next.
  755. // Upon reception of a channel id the object routes subsequent audio to its
  756. // internal cmAutoGain processor until it receives the next channel id
  757. // or a 'proc' or 'cancel' symbol.
  758. //==========================================================================================================================================
  759. enum
  760. {
  761. kChCntAgId,
  762. kHopAgId,
  763. kMedNAgId,
  764. kAvgNAgId,
  765. kSupNAgId,
  766. kOffNAgId,
  767. kSupCoefAgId,
  768. kOnThrAgId,
  769. kOffThrAgId,
  770. kSelAgId,
  771. kIdAgId,
  772. kInBaseAgId
  773. };
  774. typedef struct
  775. {
  776. cmDspInst_t inst;
  777. cmAutoGain* agp;
  778. unsigned gainBaseAgId;
  779. unsigned chCnt;
  780. unsigned chIdx;
  781. unsigned startSymId;
  782. unsigned procSymId;
  783. unsigned cancelSymId;
  784. unsigned writeSymId;
  785. unsigned printSymId;
  786. } cmDspAutoGain_t;
  787. cmDspClass_t _cmAutoGainDC;
  788. cmDspInst_t* _cmDspAutoGainAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  789. {
  790. cmDspVarArg_t args[] =
  791. {
  792. { "chCnt",kChCntAgId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Audio channel count."},
  793. { "hop", kHopAgId, 0, 0, kDoubleDsvFl | kReqArgDsvFl, "RMS hop in milliseconds."},
  794. { "med", kMedNAgId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Median filter hop count."},
  795. { "avg", kAvgNAgId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Average filter hop count."},
  796. { "sup", kSupNAgId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Supression filter hop count."},
  797. { "off", kOffNAgId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Offset filter hop count."},
  798. { "supC", kSupCoefAgId,0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Suppression coefficent."},
  799. { "onThr",kOnThrAgId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Onset threshold in dB."},
  800. { "offThr",kOffThrAgId,0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Offset threshold in dB."},
  801. { "sel", kSelAgId, 0, 0, kInDsvFl | kSymDsvFl | kNoArgDsvFl, "Action Selector: start | proc | cancel." },
  802. { "id", kIdAgId, 0, 0, kInDsvFl | kIntDsvFl | kNoArgDsvFl, "Channel id input."},
  803. };
  804. va_list vl1;
  805. unsigned i;
  806. // verify that at least one var arg exists
  807. if( va_cnt < 1 )
  808. {
  809. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The AutoGain constructor must be given the audio channel count as its first argument.");
  810. return NULL;
  811. }
  812. // copy the va_list so that it can be used again in cmDspInstAlloc()
  813. va_copy(vl1,vl);
  814. // get the first var arg which should be a filename
  815. unsigned chCnt = va_arg(vl,unsigned);
  816. if( chCnt == 0 )
  817. {
  818. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The AutoGain constructor requires at least 1 audio channel.");
  819. va_end(vl1);
  820. return NULL;
  821. }
  822. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  823. unsigned argCnt = fixArgCnt + 2 * chCnt;
  824. unsigned gainBaseAgId = kInBaseAgId + chCnt;
  825. cmDspVarArg_t a[ argCnt+1 ];
  826. assert( fixArgCnt == kInBaseAgId );
  827. // setup the output gain args
  828. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  829. cmDspArgSetupN(ctx, a, argCnt, kInBaseAgId, chCnt, "in", kInBaseAgId, 0, 0, kInDsvFl | kAudioBufDsvFl, "audio in");
  830. cmDspArgSetupN(ctx, a, argCnt, gainBaseAgId, chCnt, "gain", gainBaseAgId, 0, 0, kOutDsvFl | kDoubleDsvFl, "calibrated channel gain");
  831. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  832. // instantiate the object
  833. cmDspAutoGain_t* p = cmDspInstAlloc(cmDspAutoGain_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1);
  834. // assign the current gain coefficients
  835. for(i=0; i<chCnt; ++i)
  836. cmDspSetDefaultDouble( ctx, &p->inst, gainBaseAgId + i, 0.0, 1.0);
  837. // allocate the auto gain calculation proc
  838. p->agp = cmAutoGainAlloc(ctx->cmProcCtx,NULL,0,0,0,0,NULL);
  839. p->chCnt = chCnt;
  840. p->chIdx = cmInvalidIdx;
  841. p->gainBaseAgId= gainBaseAgId;
  842. p->startSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"start");
  843. p->procSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"proc");
  844. p->cancelSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"cancel");
  845. p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"print");
  846. cmDspSetDefaultSymbol( ctx, &p->inst, kSelAgId, p->cancelSymId );
  847. cmDspSetDefaultInt( ctx, &p->inst, kIdAgId, 0, cmInvalidId );
  848. va_end(vl1);
  849. return &p->inst;
  850. }
  851. cmDspRC_t _cmDspAutoGainFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  852. {
  853. cmDspAutoGain_t* p = (cmDspAutoGain_t*)inst;
  854. cmAutoGainFree(&p->agp);
  855. return kOkDspRC;
  856. }
  857. cmDspRC_t _cmDspAutoGainReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  858. {
  859. cmDspRC_t rc = kOkDspRC;
  860. rc = cmDspApplyAllDefaults(ctx,inst);
  861. return rc;
  862. }
  863. cmDspRC_t _cmDspAutoGainExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  864. {
  865. cmDspAutoGain_t* p = (cmDspAutoGain_t*)inst;
  866. unsigned curInChIdx = cmDspInt( inst, kIdAgId);
  867. if( cmDspSymbol( inst, kSelAgId ) == p->startSymId && curInChIdx != cmInvalidId )
  868. {
  869. unsigned inChVarId = kInBaseAgId+curInChIdx;
  870. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,inChVarId,0);
  871. unsigned iSmpCnt = cmDspVarRows(inst,inChVarId);
  872. cmAutoGainProcCh( p->agp, ip, iSmpCnt );
  873. }
  874. return kOkDspRC;
  875. }
  876. cmDspRC_t _cmDspAutoGainInit( cmDspCtx_t* ctx, cmDspInst_t* inst )
  877. {
  878. cmDspAutoGain_t* p = (cmDspAutoGain_t*)inst;
  879. cmGateDetectParams gd;
  880. unsigned i;
  881. // collect the params into a cmGateDetectParams recd
  882. gd.medCnt = cmDspUInt( inst, kMedNAgId );
  883. gd.avgCnt = cmDspUInt( inst, kAvgNAgId );
  884. gd.suprCnt = cmDspUInt( inst, kSupNAgId );
  885. gd.offCnt = cmDspUInt( inst, kOffNAgId );
  886. gd.suprCoeff = cmDspDouble( inst, kSupCoefAgId );
  887. gd.onThreshDb = cmDspDouble( inst, kOnThrAgId );
  888. gd.offThreshDb = cmDspDouble( inst, kOffThrAgId );
  889. // setup the internal auto-gain object
  890. if( cmAutoGainInit(p->agp, cmDspSamplesPerCycle(ctx), cmDspSampleRate(ctx), cmDspDouble(inst,kHopAgId), p->chCnt, &gd ) != cmOkRC )
  891. return cmDspInstErr(ctx,inst,kSubSysFailDspRC,"The internal auto-gain instance could not be initialized.");
  892. // send out gain's of 1.0 so that the input audio is not
  893. // biased by any existing scaling.
  894. for(i=0; i<p->chCnt; ++i)
  895. cmDspSetDouble( ctx, inst, p->gainBaseAgId+i, 1.0);
  896. return kOkDspRC;
  897. }
  898. cmDspRC_t _cmDspAutoGainRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  899. {
  900. cmDspAutoGain_t* p = (cmDspAutoGain_t*)inst;
  901. cmDspRC_t rc = kOkDspRC;
  902. switch( evt->dstVarId )
  903. {
  904. case kSelAgId:
  905. {
  906. // store the current 'sel' state
  907. unsigned prvSymId = cmDspSymbol(inst,kSelAgId);
  908. // update it 'sel' to the new state
  909. cmDspSetEvent(ctx,inst,evt);
  910. // get the new state
  911. unsigned newSymId = cmDspSymbol(inst,kSelAgId);
  912. //
  913. // if PRINTing was requested
  914. //
  915. if( newSymId == p->printSymId )
  916. {
  917. cmRptPrintf(&ctx->cmCtx->rpt,"Auto-Gain Report\n");
  918. cmAutoGainPrint( p->agp, &ctx->cmCtx->rpt );
  919. goto doneLabel;
  920. }
  921. //
  922. // if calibration was CANCELLED
  923. //
  924. if( newSymId == p->cancelSymId )
  925. {
  926. cmDspSetInt( ctx, inst, kIdAgId, cmInvalidId );
  927. cmRptPrintf(&ctx->cmCtx->rpt,"cancelled\n");
  928. goto doneLabel;
  929. }
  930. //
  931. // if calibration STARTup was requested - initialize the autogain proc
  932. //
  933. if( newSymId == p->startSymId )
  934. {
  935. _cmDspAutoGainInit(ctx,inst);
  936. cmRptPrintf(&ctx->cmCtx->rpt,"started\n");
  937. goto doneLabel;
  938. }
  939. //
  940. // if calibration PROCessing was requested
  941. //
  942. if( newSymId == p->procSymId && prvSymId == p->startSymId )
  943. {
  944. cmRptPrintf(&ctx->cmCtx->rpt,"proc\n");
  945. // set the current channel id to 'cmInvalidId' to stop calls to
  946. // cmAutoGainProcCh() in _cmDspAutoGainExec()
  947. cmDspSetInt( ctx, inst, kIdAgId, cmInvalidId );
  948. // update the auto gain coefficients
  949. if( cmAutoGainCalcGains(p->agp) == cmOkRC )
  950. {
  951. // send the new auto gain coefficients to the output ports
  952. unsigned i;
  953. for(i=0; i<p->chCnt; ++i)
  954. cmDspSetDouble( ctx, inst, p->gainBaseAgId+i, p->agp->chArray[i].gain);
  955. }
  956. goto doneLabel;
  957. }
  958. }
  959. break;
  960. case kIdAgId:
  961. cmDspSetEvent(ctx,inst,evt);
  962. if( cmDspSymbol(inst,kSelAgId) == p->startSymId )
  963. {
  964. cmRptPrintf(&ctx->cmCtx->rpt,"id:%i\n", cmDspInt(inst,kIdAgId));
  965. cmAutoGainStartCh(p->agp, p->chIdx = cmDspInt(inst,kIdAgId));
  966. }
  967. break;
  968. default:
  969. { assert(0); }
  970. }
  971. doneLabel:
  972. return rc;
  973. }
  974. cmDspClass_t* cmAutoGainClassCons( cmDspCtx_t* ctx )
  975. {
  976. cmDspClassSetup(&_cmAutoGainDC,ctx,"AutoGain",
  977. NULL,
  978. _cmDspAutoGainAlloc,
  979. _cmDspAutoGainFree,
  980. _cmDspAutoGainReset,
  981. _cmDspAutoGainExec,
  982. _cmDspAutoGainRecv,
  983. NULL,NULL,
  984. "Auto-gain calibrator.");
  985. return &_cmAutoGainDC;
  986. }
  987. //------------------------------------------------------------------------------------------------------------
  988. //)
  989. //( { label:cmDspEnvFollow file_desc:"Generate a control signal from by analyzing the power envelope of an incoming audio signal." kw:[sunit] }
  990. enum
  991. {
  992. kHopMsEfId, // RMS window length in milliseconds
  993. kMedCntEfId, //
  994. kAvgCntEfId, //
  995. kSuprCntEfId, //
  996. kOffCntEfId, //
  997. kSuprCoefEfId, //
  998. kOnThrDbEfId, //
  999. kOffThrDbEfId, //
  1000. kMaxDbEfId,
  1001. kInEfId,
  1002. kGateEfId,
  1003. kRmsEfId,
  1004. kLevelEfId,
  1005. kOnEfId,
  1006. kOffEfId
  1007. };
  1008. cmDspClass_t _cmEnvFollowDC;
  1009. typedef struct
  1010. {
  1011. cmDspInst_t inst;
  1012. cmShiftBuf* sbp;
  1013. cmGateDetect2* gdp;
  1014. } cmDspEnvFollow_t;
  1015. cmDspInst_t* _cmDspEnvFollowAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1016. {
  1017. cmDspVarArg_t args[] =
  1018. {
  1019. { "wnd", kHopMsEfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "RMS Window length"},
  1020. { "med", kMedCntEfId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Median filter length." },
  1021. { "avg", kAvgCntEfId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Averaging filter length." },
  1022. { "sup", kSuprCntEfId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Supression filter length." },
  1023. { "off", kOffCntEfId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Offset detection window length" },
  1024. { "supc", kSuprCoefEfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Suppression shape coefficient" },
  1025. { "ondb", kOnThrDbEfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Onset threshold dB." },
  1026. { "offdb", kOffThrDbEfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Offset threshold dB" },
  1027. { "maxdb", kMaxDbEfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Max reference dB" },
  1028. { "in", kInEfId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input" },
  1029. { "gate", kGateEfId, 0, 0, kOutDsvFl | kBoolDsvFl, "Gate state output." },
  1030. { "rms", kRmsEfId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Signal level RMS"},
  1031. { "level", kLevelEfId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Signal level 0.0-1.0 as scale between offset thresh dB and max dB"},
  1032. { "ons", kOnEfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Onset counter"},
  1033. { "offs", kOffEfId, 0, 0, kOutDsvFl | kUIntDsvFl, "Offset counter"},
  1034. { NULL, 0, 0, 0, 0 }
  1035. };
  1036. cmDspEnvFollow_t* p = cmDspInstAlloc(cmDspEnvFollow_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl);
  1037. p->sbp = cmShiftBufAlloc(ctx->cmProcCtx,NULL,0,0,0);
  1038. p->gdp = cmGateDetectAlloc2(ctx->cmProcCtx,NULL,0,NULL);
  1039. // set default values for the parameters that were not explicitely set in the va_arg list
  1040. cmDspSetDefaultDouble( ctx, &p->inst, kHopMsEfId, 0, 12 );
  1041. cmDspSetDefaultUInt( ctx, &p->inst, kMedCntEfId, 0, 5 );
  1042. cmDspSetDefaultUInt( ctx, &p->inst, kAvgCntEfId, 0, 9 );
  1043. cmDspSetDefaultUInt( ctx, &p->inst, kSuprCntEfId, 0, 6 );
  1044. cmDspSetDefaultUInt( ctx, &p->inst, kOffCntEfId, 0, 3 );
  1045. cmDspSetDefaultDouble( ctx, &p->inst, kSuprCoefEfId, 0, 1.4 );
  1046. cmDspSetDefaultDouble( ctx, &p->inst, kOnThrDbEfId, 0, -45 );
  1047. cmDspSetDefaultDouble( ctx, &p->inst, kOffThrDbEfId, 0, -80 );
  1048. cmDspSetDefaultDouble( ctx, &p->inst, kMaxDbEfId, 0, -10.0 );
  1049. cmDspSetDefaultUInt( ctx, &p->inst, kOnEfId, 0, 0 );
  1050. cmDspSetDefaultUInt( ctx, &p->inst, kOffEfId, 0, 0 );
  1051. return &p->inst;
  1052. }
  1053. cmDspRC_t _cmDspEnvFollowFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1054. {
  1055. cmDspEnvFollow_t* p = (cmDspEnvFollow_t*)inst;
  1056. cmGateDetectFree2(&p->gdp);
  1057. cmShiftBufFree(&p->sbp);
  1058. return kOkDspRC;
  1059. }
  1060. cmDspRC_t _cmDspEnvFollowReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1061. {
  1062. cmDspEnvFollow_t* p = (cmDspEnvFollow_t*)inst;
  1063. cmDspRC_t rc = kOkDspRC;
  1064. if((rc = cmDspApplyAllDefaults(ctx,inst)) != kOkDspRC )
  1065. return rc;
  1066. cmGateDetectParams r;
  1067. r.medCnt = cmDspUInt( inst, kMedCntEfId );
  1068. r.avgCnt = cmDspUInt( inst, kAvgCntEfId );
  1069. r.suprCnt = cmDspUInt( inst, kSuprCntEfId );
  1070. r.offCnt = cmDspUInt( inst, kOffCntEfId );
  1071. r.suprCoeff = cmDspDouble( inst, kSuprCoefEfId );
  1072. r.onThreshDb = cmDspDouble( inst, kOnThrDbEfId );
  1073. r.offThreshDb = cmDspDouble( inst, kOffThrDbEfId );
  1074. double sr = cmDspSampleRate(ctx);
  1075. double hopSmpCnt = floor(sr * cmDspDouble(inst,kHopMsEfId) / 1000 );
  1076. unsigned wndSmpCnt = floor(r.medCnt * hopSmpCnt);
  1077. if( cmShiftBufInit(p->sbp, cmDspSamplesPerCycle(ctx), wndSmpCnt, hopSmpCnt ) != cmOkRC )
  1078. return cmDspInstErr(ctx,inst,kInstResetFailDspRC,"The gate detector shift buffer initialization failed.");
  1079. if( cmGateDetectInit2(p->gdp, cmDspSamplesPerCycle(ctx), &r ) != cmOkRC )
  1080. return cmDspInstErr(ctx,inst,kInstResetFailDspRC,"The gate detector shift buffer initialization failed.");
  1081. return rc;
  1082. }
  1083. cmDspRC_t _cmDspEnvFollowExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1084. {
  1085. cmDspEnvFollow_t* p = (cmDspEnvFollow_t*)inst;
  1086. unsigned iChIdx = 0;
  1087. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInEfId,iChIdx);
  1088. unsigned iSmpCnt = cmDspVarRows(inst,kInEfId);
  1089. double maxDb = cmDspDouble(inst,kMaxDbEfId);
  1090. double offDb = cmDspDouble(inst,kOffThrDbEfId);
  1091. while( cmShiftBufExec(p->sbp, ip, iSmpCnt ) )
  1092. {
  1093. cmGateDetectExec2(p->gdp,p->sbp->outV, p->sbp->outN );
  1094. // RMS is going out at the audio rate - maybe there should be an option
  1095. // to send it only when the gate changes - this could significantly
  1096. // cut down on unnecessary transmission if the RMS is only used
  1097. // when the gate changes
  1098. cmDspSetDouble(ctx,inst,kRmsEfId, p->gdp->rms );
  1099. double rmsDb = p->gdp->rms < 0.00001 ? -100.0 : 20.0 * log10(p->gdp->rms);
  1100. double level = maxDb <= offDb ? 0 : fabs((offDb - cmMax( offDb, cmMin( maxDb, rmsDb ))) / (maxDb - offDb));
  1101. cmDspSetDouble(ctx,inst,kLevelEfId, level );
  1102. if( p->gdp->onFl || p->gdp->offFl )
  1103. {
  1104. cmDspSetBool(ctx, inst, kGateEfId, p->gdp->gateFl);
  1105. if( p->gdp->onFl )
  1106. cmDspSetUInt( ctx, inst, kOnEfId, cmDspUInt(inst,kOnEfId) + 1 );
  1107. if( p->gdp->offFl )
  1108. cmDspSetUInt( ctx, inst, kOffEfId, cmDspUInt(inst,kOffEfId) + 1 );
  1109. }
  1110. }
  1111. return kOkDspRC;
  1112. }
  1113. cmDspRC_t _cmDspEnvFollowRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1114. {
  1115. cmDspRC_t rc;
  1116. cmDspEnvFollow_t* p = (cmDspEnvFollow_t*)inst;
  1117. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  1118. {
  1119. switch( evt->dstVarId )
  1120. {
  1121. case kOnThrDbEfId:
  1122. cmGateDetectSetOnThreshDb2(p->gdp, cmDspDouble(inst,kOnThrDbEfId) );
  1123. break;
  1124. case kOffThrDbEfId:
  1125. cmGateDetectSetOffThreshDb2(p->gdp, cmDspDouble(inst,kOffThrDbEfId) );
  1126. break;
  1127. }
  1128. }
  1129. return rc;
  1130. }
  1131. cmDspClass_t* cmEnvFollowClassCons( cmDspCtx_t* ctx )
  1132. {
  1133. cmDspClassSetup(&_cmEnvFollowDC,ctx,"EnvFollow",
  1134. NULL,
  1135. _cmDspEnvFollowAlloc,
  1136. _cmDspEnvFollowFree,
  1137. _cmDspEnvFollowReset,
  1138. _cmDspEnvFollowExec,
  1139. _cmDspEnvFollowRecv,
  1140. NULL,NULL,
  1141. "Envelope follower and gate detector.");
  1142. return &_cmEnvFollowDC;
  1143. }
  1144. //------------------------------------------------------------------------------------------------------------
  1145. //)
  1146. //( { label:cmDspXfader file_desc:"Gate controlled fader bank." kw:[sunit] }
  1147. // Fade in and out an arbitrary number of audio signals based on gate signals.
  1148. // When the gate is high the signal fades in and when the gate is low the signal fades out.
  1149. // Constructor Args:
  1150. // Required: Count of input and output channels.
  1151. // Optional: Fade time in milliseconds.
  1152. //
  1153. // Inputs:
  1154. // bool Control gates
  1155. // audio Input audio.
  1156. // Outputs:
  1157. // audio Output audio
  1158. // double Channel gains.
  1159. enum
  1160. {
  1161. kChCntXfId,
  1162. kFadeTimeMsXfId,
  1163. kMstrGateXfId,
  1164. kFadeInTimeMsXfId,
  1165. kFadeOutTimeMsXfId,
  1166. kResetXfId,
  1167. kOnXfId,
  1168. kOffXfId,
  1169. kGateBaseXfId,
  1170. };
  1171. cmDspClass_t _cmXfaderDC;
  1172. typedef struct
  1173. {
  1174. cmDspInst_t inst;
  1175. cmXfader* xfdp;
  1176. unsigned inBaseXfId;
  1177. unsigned outBaseXfId;
  1178. unsigned stateBaseXfId;
  1179. unsigned gainBaseXfId;
  1180. unsigned chCnt;
  1181. bool* chGateV;
  1182. unsigned onSymId;
  1183. unsigned offSymId;
  1184. } cmDspXfader_t;
  1185. cmDspInst_t* _cmDspXfaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1186. {
  1187. cmDspVarArg_t args[] =
  1188. {
  1189. { "chs", kChCntXfId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Input and Output channel count"},
  1190. { "ms", kFadeTimeMsXfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Fade time in milliseonds."},
  1191. { "mgate", kMstrGateXfId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Master gate - can be used to set all gates."},
  1192. { "ims", kFadeInTimeMsXfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Fade in time in milliseonds."},
  1193. { "oms", kFadeOutTimeMsXfId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Fade out time in milliseonds."},
  1194. { "reset", kResetXfId, 0, 0, kInDsvFl | kBoolDsvFl, "Jump to gate states rather than fade."},
  1195. { "on", kOnXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'on' when all ch's transition from off to on."},
  1196. { "off", kOffXfId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'off' when all ch's transition from on to off."},
  1197. };
  1198. if( va_cnt < 1 )
  1199. {
  1200. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The Xfader object must be given a channel count argument.");
  1201. return NULL;
  1202. }
  1203. va_list vl1;
  1204. va_copy(vl1,vl);
  1205. unsigned chCnt = va_arg(vl,int);
  1206. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  1207. unsigned argCnt = fixArgCnt + 5*chCnt;
  1208. unsigned inBaseXfId = kGateBaseXfId + chCnt;
  1209. unsigned outBaseXfId = inBaseXfId + chCnt;
  1210. unsigned stateBaseXfId = outBaseXfId + chCnt;
  1211. unsigned gainBaseXfId = stateBaseXfId + chCnt;
  1212. cmDspVarArg_t a[ argCnt+1 ];
  1213. // setup the input gate detectors and the output gain args
  1214. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  1215. cmDspArgSetupN(ctx, a, argCnt, kGateBaseXfId, chCnt, "gate", kGateBaseXfId, 0, 0, kInDsvFl | kBoolDsvFl, "gate flags");
  1216. cmDspArgSetupN(ctx, a, argCnt, inBaseXfId, chCnt, "in", inBaseXfId, 0, 0, kInDsvFl | kAudioBufDsvFl, "audio input");
  1217. cmDspArgSetupN(ctx, a, argCnt, outBaseXfId, chCnt, "out", outBaseXfId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "audio output");
  1218. cmDspArgSetupN(ctx, a, argCnt, stateBaseXfId, chCnt, "state",stateBaseXfId, 0, 0, kOutDsvFl | kBoolDsvFl, "current fader state");
  1219. cmDspArgSetupN(ctx, a, argCnt, gainBaseXfId, chCnt, "gain", gainBaseXfId, 0, 0, kOutDsvFl | kDoubleDsvFl, "gain output");
  1220. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  1221. cmDspXfader_t* p = cmDspInstAlloc(cmDspXfader_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1);
  1222. double fadeTimeMs = cmDspDouble(&p->inst, kFadeTimeMsXfId );
  1223. p->xfdp = cmXfaderAlloc(ctx->cmProcCtx,NULL,cmDspSampleRate(ctx), chCnt, fadeTimeMs);
  1224. p->inBaseXfId = inBaseXfId;
  1225. p->outBaseXfId = outBaseXfId;
  1226. p->stateBaseXfId = stateBaseXfId;
  1227. p->gainBaseXfId = gainBaseXfId;
  1228. p->chCnt = chCnt;
  1229. p->chGateV = cmMemAllocZ(bool,p->chCnt);
  1230. p->onSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"on");
  1231. p->offSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"off");
  1232. // set default values for the parameters that were not explicitely set in the va_arg list
  1233. cmDspSetDefaultDouble( ctx, &p->inst, kFadeTimeMsXfId, 0, 100 );
  1234. cmDspSetDefaultBool( ctx, &p->inst, kMstrGateXfId, false, false);
  1235. cmDspSetDefaultSymbol( ctx, &p->inst, kOnXfId, p->onSymId );
  1236. cmDspSetDefaultSymbol( ctx, &p->inst, kOffXfId, p->offSymId );
  1237. int i;
  1238. for(i=0; i<chCnt; ++i)
  1239. cmDspSetDefaultBool( ctx, &p->inst, stateBaseXfId+i, false, false );
  1240. va_end(vl1);
  1241. return &p->inst;
  1242. }
  1243. cmDspRC_t _cmDspXfaderFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1244. {
  1245. cmDspXfader_t* p = (cmDspXfader_t*)inst;
  1246. cmMemFree(p->chGateV);
  1247. cmXfaderFree(&p->xfdp);
  1248. return kOkDspRC;
  1249. }
  1250. cmDspRC_t _cmDspXfaderReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1251. {
  1252. cmDspRC_t rc = kOkDspRC;
  1253. rc = cmDspApplyAllDefaults(ctx,inst);
  1254. cmDspXfader_t* p = (cmDspXfader_t*)inst;
  1255. // TODO: zeroing of output audio buffers should be built into cmDspApplyAllDefaults().
  1256. unsigned i;
  1257. for(i=0; i<p->chCnt; ++i)
  1258. cmDspZeroAudioBuf(ctx,inst,p->outBaseXfId + i);
  1259. return rc;
  1260. }
  1261. cmDspRC_t _cmDspXfaderExec(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1262. {
  1263. cmDspRC_t rc = cmOkRC;
  1264. cmDspXfader_t* p = (cmDspXfader_t*)inst;
  1265. unsigned i;
  1266. // update the internal cross fader by providing it with new gate settings and generate new gain values
  1267. cmXfaderExec( p->xfdp, cmDspSamplesPerCycle(ctx), p->chGateV, p->chCnt );
  1268. for(i=0; i<p->chCnt; ++i)
  1269. {
  1270. unsigned n = cmDspAudioBufSmpCount(ctx,inst,p->outBaseXfId+i,0);
  1271. cmSample_t* op = cmDspAudioBuf(ctx,inst,p->outBaseXfId+i,0);
  1272. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,p->inBaseXfId+i,0);
  1273. cmSample_t gain = (cmSample_t)p->xfdp->chArray[i].ep_gain;
  1274. if( op != NULL )
  1275. {
  1276. if( ip == NULL )
  1277. cmVOS_Zero(op,n);
  1278. else
  1279. cmVOS_MultVVS(op,n,ip,gain);
  1280. }
  1281. if( p->xfdp->chArray[i].onFl )
  1282. {
  1283. cmDspSetBool(ctx,inst,p->stateBaseXfId+i,true);
  1284. }
  1285. if( p->xfdp->chArray[i].offFl )
  1286. {
  1287. cmDspSetBool(ctx,inst,p->stateBaseXfId+i,false);
  1288. }
  1289. // send the gain output
  1290. cmDspSetDouble(ctx,inst,p->gainBaseXfId+i,gain);
  1291. }
  1292. if( p->xfdp->onFl )
  1293. cmDspSetSymbol(ctx,inst,kOnXfId,p->onSymId);
  1294. if( p->xfdp->offFl )
  1295. cmDspSetSymbol(ctx,inst,kOffXfId,p->offSymId);
  1296. return rc;
  1297. }
  1298. cmDspRC_t _cmDspXfaderRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1299. {
  1300. cmDspRC_t rc;
  1301. cmDspXfader_t* p = (cmDspXfader_t*)inst;
  1302. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  1303. return rc;
  1304. switch( evt->dstVarId )
  1305. {
  1306. case kFadeTimeMsXfId:
  1307. // if this is an xfade time event then transfer the new xfade time to the xfade proc
  1308. cmXfaderSetXfadeTime(p->xfdp,cmDspDouble(inst,kFadeTimeMsXfId));
  1309. break;
  1310. case kMstrGateXfId:
  1311. {
  1312. bool fl = cmDspBool(inst,kMstrGateXfId);
  1313. unsigned i;
  1314. for(i=0; i<p->chCnt; ++i)
  1315. p->chGateV[i] = fl;
  1316. }
  1317. break;
  1318. case kFadeInTimeMsXfId:
  1319. cmXfaderSetXfadeInTime(p->xfdp,cmDspDouble(inst,kFadeInTimeMsXfId));
  1320. break;
  1321. case kFadeOutTimeMsXfId:
  1322. cmXfaderSetXfadeOutTime(p->xfdp,cmDspDouble(inst,kFadeOutTimeMsXfId));
  1323. break;
  1324. case kResetXfId:
  1325. {
  1326. cmXfaderExec( p->xfdp, cmDspSamplesPerCycle(ctx), p->chGateV, p->chCnt );
  1327. cmXfaderJumpToDestinationGain(p->xfdp);
  1328. // force the chGateV[] to match the xfaders state
  1329. int i;
  1330. for(i=0; i<p->chCnt; ++i)
  1331. {
  1332. bool gateFl = p->xfdp->chArray[i].gateFl;
  1333. p->chGateV[i] = gateFl;
  1334. cmDspSetBool( ctx,inst,p->stateBaseXfId + i, gateFl);
  1335. cmDspSetDouble(ctx,inst,p->gainBaseXfId + i, gateFl ? 1.0 : 0.0 );
  1336. }
  1337. }
  1338. break;
  1339. }
  1340. // record gate changes into p->chGateV[] for later use in _cmDspXfaderExec().
  1341. if( kGateBaseXfId <= evt->dstVarId && evt->dstVarId < kGateBaseXfId + p->chCnt )
  1342. {
  1343. p->chGateV[ evt->dstVarId - kGateBaseXfId ] = cmDspBool( inst, evt->dstVarId );
  1344. }
  1345. return rc;
  1346. }
  1347. cmDspClass_t* cmXfaderClassCons( cmDspCtx_t* ctx )
  1348. {
  1349. cmDspClassSetup(&_cmXfaderDC,ctx,"Xfader",
  1350. NULL,
  1351. _cmDspXfaderAlloc,
  1352. _cmDspXfaderFree,
  1353. _cmDspXfaderReset,
  1354. _cmDspXfaderExec,
  1355. _cmDspXfaderRecv,
  1356. NULL,NULL,
  1357. "Cross fade gain generator.");
  1358. return &_cmXfaderDC;
  1359. }
  1360. //------------------------------------------------------------------------------------------------------------
  1361. //)
  1362. //( { label:cmDspChCfg file_desc:"Configure a 'fluxo' channel." kw:[sunit] }
  1363. enum
  1364. {
  1365. kFnCcId,
  1366. kSelCcId,
  1367. kDoneCcId,
  1368. kGainBaseCcId
  1369. };
  1370. cmDspClass_t _cmChCfgDC;
  1371. typedef struct
  1372. {
  1373. cmDspInst_t inst;
  1374. cmChCfg* ccp;
  1375. unsigned midiBaseCcId;
  1376. unsigned hzBaseCcId;
  1377. unsigned chBaseCcId;
  1378. unsigned nsflBaseCcId;
  1379. unsigned nshzBaseCcId;
  1380. unsigned printSymId;
  1381. unsigned writeSymId;
  1382. unsigned nsCmdSymId;
  1383. unsigned hzCmdSymId;
  1384. unsigned resetSymId;
  1385. } cmDspChCfg_t;
  1386. cmDspInst_t* _cmDspChCfgAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1387. {
  1388. cmDspVarArg_t args[] =
  1389. {
  1390. { "fn", kFnCcId, 0, 0, kStrzDsvFl| kReqArgDsvFl, "Channel configuration JSON file name."},
  1391. { "sel", kSelCcId, 0, 0, kInDsvFl | kSymDsvFl, "Action selector: print | write | ns | reset"},
  1392. { "done", kDoneCcId,0, 0, kOutDsvFl | kSymDsvFl, "Trigger following action."}
  1393. };
  1394. if( va_cnt < 1 )
  1395. {
  1396. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The channel configuration object must be given a file name argument.");
  1397. return NULL;
  1398. }
  1399. va_list vl1;
  1400. va_copy(vl1,vl);
  1401. const cmChar_t* chCfgFn = va_arg(vl,cmChar_t*);
  1402. cmChCfg* ccp = cmChCfgAlloc( ctx->cmProcCtx, NULL, ctx->cmCtx, chCfgFn );
  1403. if( ccp == NULL || ccp->chCnt==0 )
  1404. {
  1405. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The channel configuration object could not be initialized with the file name '%s'.",cmStringNullGuard(chCfgFn));
  1406. return NULL;
  1407. }
  1408. unsigned chCnt = ccp->chCnt;
  1409. unsigned nsChCnt = ccp->nsChCnt;
  1410. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  1411. unsigned argCnt = fixArgCnt + 5*chCnt + nsChCnt;
  1412. unsigned midiBaseCcId = kGainBaseCcId + chCnt;
  1413. unsigned hzBaseCcId = midiBaseCcId + chCnt;
  1414. unsigned chBaseCcId = hzBaseCcId + chCnt;
  1415. unsigned nsflBaseCcId = chBaseCcId + chCnt;
  1416. unsigned nshzBaseCcId = nsflBaseCcId + chCnt;
  1417. cmDspChCfg_t* p = NULL;
  1418. cmDspVarArg_t a[ argCnt+1 ];
  1419. unsigned i,j;
  1420. // setup the input gate detectors and the output gain args
  1421. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  1422. cmDspArgSetupN(ctx, a, argCnt, kGainBaseCcId, chCnt, "gain", kGainBaseCcId, 0, 0, kSendDfltDsvFl | kInDsvFl | kOutDsvFl | kDoubleDsvFl, "Gain input and output.");
  1423. cmDspArgSetupN(ctx, a, argCnt, midiBaseCcId, chCnt, "midi", midiBaseCcId, 0, 0, kSendDfltDsvFl | kOutDsvFl | kUIntDsvFl, "MIDI pitch output");
  1424. cmDspArgSetupN(ctx, a, argCnt, hzBaseCcId, chCnt, "hz", hzBaseCcId, 0, 0, kSendDfltDsvFl | kOutDsvFl | kDoubleDsvFl, "pitch output in Hz");
  1425. cmDspArgSetupN(ctx, a, argCnt, chBaseCcId, chCnt, "ch", chBaseCcId, 0, 0, kSendDfltDsvFl | kOutDsvFl | kUIntDsvFl , "Audio channel index");
  1426. cmDspArgSetupN(ctx, a, argCnt, nsflBaseCcId, chCnt, "nsfl", nsflBaseCcId, 0, 0, kOutDsvFl | kBoolDsvFl, "noise shaper enables");
  1427. cmDspArgSetupN(ctx, a, argCnt, nshzBaseCcId, nsChCnt, "nshz", nshzBaseCcId, 0, 0, kOutDsvFl | kDoubleDsvFl, "noise-shaper pitch output in Hz");
  1428. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  1429. if((p = cmDspInstAlloc(cmDspChCfg_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1)) == NULL )
  1430. return NULL;
  1431. p->ccp = ccp;
  1432. p->midiBaseCcId = midiBaseCcId;
  1433. p->hzBaseCcId = hzBaseCcId;
  1434. p->chBaseCcId = chBaseCcId;
  1435. p->nsflBaseCcId = nsflBaseCcId;
  1436. p->nshzBaseCcId = nshzBaseCcId;
  1437. p->writeSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"write");
  1438. p->printSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"print");
  1439. p->nsCmdSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"ns");
  1440. p->hzCmdSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"hz");
  1441. p->resetSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"reset");
  1442. for(i=0,j=0; i<chCnt; ++i)
  1443. {
  1444. double hz = cmMidiToHz(ccp->chArray[i].midi);
  1445. cmDspSetDefaultDouble(ctx, &p->inst, kGainBaseCcId + i, 0.0, ccp->chArray[i].gain);
  1446. cmDspSetDefaultUInt( ctx, &p->inst, p->midiBaseCcId + i, 0, ccp->chArray[i].midi );
  1447. cmDspSetDefaultDouble(ctx, &p->inst, p->hzBaseCcId + i, 0.0, hz );
  1448. cmDspSetDefaultUInt( ctx, &p->inst, p->chBaseCcId + i, 0, ccp->chArray[i].ch );
  1449. cmDspSetDefaultBool( ctx, &p->inst, p->nsflBaseCcId+i, false, false );
  1450. if( ccp->chArray[i].nsFl )
  1451. {
  1452. cmDspSetDefaultDouble(ctx,&p->inst, p->nshzBaseCcId+j, 0.0, hz);
  1453. ++j;
  1454. }
  1455. }
  1456. cmDspSetDefaultSymbol(ctx, &p->inst, kDoneCcId, cmInvalidId );
  1457. cmDspSetDefaultSymbol(ctx, &p->inst, kSelCcId, cmInvalidId );
  1458. return &p->inst;
  1459. }
  1460. cmDspRC_t _cmDspChCfgFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1461. {
  1462. cmDspChCfg_t* p = (cmDspChCfg_t*)inst;
  1463. cmChCfgFree(&p->ccp);
  1464. return kOkDspRC;
  1465. }
  1466. cmDspRC_t _cmDspChCfgReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1467. {
  1468. cmDspRC_t rc = kOkDspRC;
  1469. rc = cmDspApplyAllDefaults(ctx,inst);
  1470. return rc;
  1471. }
  1472. cmDspRC_t _cmDspChCfgRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1473. {
  1474. cmDspRC_t rc;
  1475. cmDspChCfg_t* p = (cmDspChCfg_t*)inst;
  1476. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  1477. {
  1478. if( evt->dstVarId == kSelCcId )
  1479. {
  1480. unsigned selId = cmDspSymbol(inst,kSelCcId);
  1481. if( selId == p->resetSymId )
  1482. {
  1483. _cmDspChCfgReset(ctx,inst,evt);
  1484. }
  1485. else
  1486. if( selId == p->hzCmdSymId )
  1487. {
  1488. unsigned i;
  1489. // snd the hz
  1490. for(i=0; i<p->ccp->chCnt; ++i)
  1491. cmDspSetDouble(ctx,inst,p->hzBaseCcId+i,cmDspDouble(inst,p->hzBaseCcId+i));
  1492. }
  1493. else
  1494. if( selId == p->nsCmdSymId )
  1495. {
  1496. cmRptPrintf(ctx->rpt,"ChCfg:NS\n");
  1497. unsigned i;
  1498. // send the ns flags
  1499. for(i=0; i<p->ccp->chCnt; ++i)
  1500. cmDspSetBool(ctx,inst,p->nsflBaseCcId+i,p->ccp->chArray[i].nsFl);
  1501. // snd the ns hz
  1502. for(i=0; i<p->ccp->nsChCnt; ++i)
  1503. cmDspSetDouble(ctx,inst,p->nshzBaseCcId+i,cmDspDouble(inst,p->nshzBaseCcId+i));
  1504. cmDspSetSymbol(ctx,inst,kDoneCcId,p->nsCmdSymId);
  1505. }
  1506. else
  1507. if( selId == p->printSymId )
  1508. {
  1509. cmRptPrintf(&ctx->cmCtx->rpt,"Channel Cfg Report\n");
  1510. cmChCfgPrint(p->ccp, ctx->rpt );
  1511. }
  1512. else
  1513. {
  1514. if( selId == p->writeSymId )
  1515. {
  1516. unsigned i;
  1517. cmRptPrintf(&ctx->cmCtx->rpt,"writing\n");
  1518. // copy the gain values into the internal chCfg object ...
  1519. for(i=0; i<p->ccp->chCnt; ++i)
  1520. p->ccp->chArray[i].gain = cmDspDouble(inst,kGainBaseCcId+i);
  1521. // ... and write the object
  1522. cmChCfgWrite(p->ccp);
  1523. }
  1524. }
  1525. }
  1526. }
  1527. return rc;
  1528. }
  1529. cmDspClass_t* cmChCfgClassCons( cmDspCtx_t* ctx )
  1530. {
  1531. cmDspClassSetup(&_cmChCfgDC,ctx,"ChCfg",
  1532. NULL,
  1533. _cmDspChCfgAlloc,
  1534. _cmDspChCfgFree,
  1535. _cmDspChCfgReset,
  1536. NULL,
  1537. _cmDspChCfgRecv,
  1538. NULL,NULL,
  1539. "PP Channel Configuration Object.");
  1540. return &_cmChCfgDC;
  1541. }
  1542. //------------------------------------------------------------------------------------------------------------
  1543. //)
  1544. //( { label:cmDspChordDetect file_desc:"Detect a predefined chord based on signal gates." kw:[sunit] }
  1545. enum
  1546. {
  1547. kRsrcCdId,
  1548. kMaxTimeSpanCdId,
  1549. kMinNoteCntCdId,
  1550. kDetectCdId,
  1551. kCountCdId,
  1552. kGateBaseCdId
  1553. };
  1554. cmDspClass_t _cmChordDetectDC;
  1555. typedef struct
  1556. {
  1557. cmDspInst_t inst;
  1558. cmChordDetect* cdp;
  1559. unsigned rmsBaseCdId;
  1560. unsigned chCnt;
  1561. bool* chGateV; // chGateV[ chCnt ]
  1562. cmReal_t* chRmsV; // chRmsV[ chCnt ]
  1563. unsigned* chEnaV; // chEnaV[ chCnt ]
  1564. unsigned count;
  1565. } cmDspChordDetect_t;
  1566. cmDspInst_t* _cmDspChordDetectAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1567. {
  1568. cmDspVarArg_t args[] =
  1569. {
  1570. { "rsrc", kRsrcCdId, 0, 0, kStrzDsvFl | kReqArgDsvFl, "Channel enable flag array."},
  1571. { "span", kMaxTimeSpanCdId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Max. onset time span."},
  1572. { "notes", kMinNoteCntCdId, 0, 0, kInDsvFl | kUIntDsvFl | kOptArgDsvFl, "Min. note count per chord."},
  1573. { "detect", kDetectCdId, 0, 0, kOutDsvFl | kBoolDsvFl, "Chord detect flag."},
  1574. { "count", kCountCdId, 0, 0, kOutDsvFl | kUIntDsvFl, "Count of chords detected since last reset."}
  1575. };
  1576. if( va_cnt < 1 )
  1577. {
  1578. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The chord detector must be given a channel enable flags array resource argument .");
  1579. return NULL;
  1580. }
  1581. va_list vl1;
  1582. va_copy(vl1,vl);
  1583. const cmChar_t* rsrc = va_arg(vl,const cmChar_t*);
  1584. unsigned* enaV = NULL;
  1585. unsigned chCnt = 0;
  1586. if( cmDspRsrcUIntArray( ctx->dspH, &chCnt, &enaV, rsrc, NULL ) != kOkDspRC )
  1587. {
  1588. va_end(vl1);
  1589. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The chord detector channel index resource '%s' could not be read.",cmStringNullGuard(rsrc));
  1590. return NULL;
  1591. }
  1592. //cmRptPrintf(ctx->rpt,"cd %s chs:%i\n",rsrc,chCnt);
  1593. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  1594. unsigned argCnt = fixArgCnt + 2*chCnt;
  1595. unsigned rmsBaseCdId = kGateBaseCdId + chCnt;
  1596. cmDspVarArg_t a[ argCnt+1 ];
  1597. unsigned i;
  1598. cmDspChordDetect_t* p;
  1599. // setup the input gate detectors and the output gain args
  1600. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  1601. cmDspArgSetupN(ctx, a, argCnt, kGateBaseCdId, chCnt, "gate", kGateBaseCdId, 0, 0, kInDsvFl | kOutDsvFl | kBoolDsvFl, "Channel gate input and output.");
  1602. cmDspArgSetupN(ctx, a, argCnt, rmsBaseCdId, chCnt, "rms", rmsBaseCdId, 0, 0, kInDsvFl | kOutDsvFl | kDoubleDsvFl, "Channel RMS input and output");
  1603. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  1604. if((p = cmDspInstAlloc(cmDspChordDetect_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1)) == NULL )
  1605. return NULL;
  1606. double dfltMaxTimeSpanMs = 50.0;
  1607. unsigned dfltMinNoteCnt = 2;
  1608. cmDspSetDefaultDouble( ctx, &p->inst, kMaxTimeSpanCdId, 0.0, dfltMaxTimeSpanMs );
  1609. cmDspSetDefaultUInt( ctx, &p->inst, kMinNoteCntCdId, 0, dfltMinNoteCnt );
  1610. cmDspSetDefaultBool( ctx, &p->inst, kDetectCdId, false, false );
  1611. cmDspSetDefaultUInt( ctx, &p->inst, kCountCdId, 0, 0 );
  1612. for(i=0; i<chCnt; ++i)
  1613. {
  1614. cmDspSetDefaultBool( ctx, &p->inst, kGateBaseCdId + i, false, false );
  1615. cmDspSetDefaultDouble(ctx, &p->inst, rmsBaseCdId + i, 0.0, 0.0 );
  1616. }
  1617. p->cdp = cmChordDetectAlloc( ctx->cmProcCtx, NULL, cmDspSampleRate(ctx), chCnt, cmDspDouble(&p->inst,kMaxTimeSpanCdId), cmDspUInt(&p->inst,kMinNoteCntCdId) );
  1618. p->rmsBaseCdId = rmsBaseCdId;
  1619. p->chCnt = chCnt;
  1620. p->chGateV = cmMemAllocZ(bool, chCnt);
  1621. p->chRmsV = cmMemAllocZ(cmReal_t, chCnt);
  1622. p->chEnaV = enaV;
  1623. va_end(vl1);
  1624. return &p->inst;
  1625. }
  1626. cmDspRC_t _cmDspChordDetectFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1627. {
  1628. cmDspChordDetect_t* p = (cmDspChordDetect_t*)inst;
  1629. cmChordDetectFree(&p->cdp);
  1630. cmMemFree(p->chGateV);
  1631. cmMemFree(p->chRmsV);
  1632. return kOkDspRC;
  1633. }
  1634. cmDspRC_t _cmDspChordDetectReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1635. {
  1636. cmDspRC_t rc = kOkDspRC;
  1637. rc = cmDspApplyAllDefaults(ctx,inst);
  1638. return rc;
  1639. }
  1640. cmDspRC_t _cmDspChordDetectExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1641. {
  1642. cmDspRC_t rc = kOkDspRC;
  1643. cmDspChordDetect_t* p = (cmDspChordDetect_t*)inst;
  1644. cmChordDetectExec(p->cdp, cmDspSamplesPerCycle(ctx), p->chGateV, p->chRmsV, p->chCnt );
  1645. if( p->cdp->detectFl )
  1646. {
  1647. unsigned i;
  1648. for(i=0; i<p->chCnt; ++i)
  1649. {
  1650. bool fl = p->cdp->chArray[i].chordFl;
  1651. cmDspSetBool( ctx, inst, kGateBaseCdId + i, fl );
  1652. cmDspSetDouble( ctx, inst, p->rmsBaseCdId + i, fl ? p->cdp->chArray[i].candRMS : 0 );
  1653. }
  1654. cmDspSetBool(ctx, inst, kDetectCdId, true);
  1655. cmDspSetUInt(ctx, inst, kCountCdId, cmDspUInt(inst,kCountCdId) + 1 );
  1656. }
  1657. cmVOB_Zero(p->chGateV,p->chCnt);
  1658. cmVOR_Zero(p->chRmsV,p->chCnt);
  1659. return rc;
  1660. }
  1661. cmDspRC_t _cmDspChordDetectRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1662. {
  1663. cmDspRC_t rc = kOkDspRC;
  1664. cmDspChordDetect_t* p = (cmDspChordDetect_t*)inst;
  1665. if( kGateBaseCdId <= evt->dstVarId && evt->dstVarId < kGateBaseCdId + p->chCnt )
  1666. {
  1667. unsigned idx = evt->dstVarId - kGateBaseCdId;
  1668. if( p->chEnaV[idx] )
  1669. p->chGateV[ idx ] = cmDsvGetBool(evt->valuePtr);
  1670. //cmRptPrintf(ctx->rpt,"cd gate:%i e:%i v:%i\n",idx,p->chEnaV[idx],p->chGateV[idx]);
  1671. }
  1672. else
  1673. if( p->rmsBaseCdId <= evt->dstVarId && evt->dstVarId < p->rmsBaseCdId + p->chCnt )
  1674. {
  1675. unsigned idx = evt->dstVarId - p->rmsBaseCdId;
  1676. if( p->chEnaV[idx] )
  1677. p->chRmsV[ idx ] = cmDsvGetReal( evt->valuePtr );
  1678. }
  1679. else
  1680. {
  1681. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  1682. {
  1683. switch( evt->dstVarId )
  1684. {
  1685. case kMaxTimeSpanCdId:
  1686. cmChordDetectSetSpanMs(p->cdp,cmDspDouble(inst,kMaxTimeSpanCdId));
  1687. break;
  1688. case kMinNoteCntCdId:
  1689. p->cdp->minNotesPerChord = cmDspUInt(inst,kMinNoteCntCdId);
  1690. break;
  1691. }
  1692. }
  1693. }
  1694. return rc;
  1695. }
  1696. cmDspClass_t* cmChordDetectClassCons( cmDspCtx_t* ctx )
  1697. {
  1698. cmDspClassSetup(&_cmChordDetectDC,ctx,"ChordDetect",
  1699. NULL,
  1700. _cmDspChordDetectAlloc,
  1701. _cmDspChordDetectFree,
  1702. _cmDspChordDetectReset,
  1703. _cmDspChordDetectExec,
  1704. _cmDspChordDetectRecv,
  1705. NULL,NULL,
  1706. "Chord detector.");
  1707. return &_cmChordDetectDC;
  1708. }
  1709. //------------------------------------------------------------------------------------------------------------
  1710. //)
  1711. //( { label:cmDspFader file_desc:"Single channel gate controlled fader." kw:[sunit] }
  1712. enum
  1713. {
  1714. kTimeFaId,
  1715. kGateFaId,
  1716. kInFaId,
  1717. kGainFaId,
  1718. kOutFaId
  1719. };
  1720. cmDspClass_t _cmFaderDC;
  1721. typedef struct
  1722. {
  1723. cmDspInst_t inst;
  1724. cmFader* fdp;
  1725. } cmDspFader_t;
  1726. cmDspInst_t* _cmDspFaderAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1727. {
  1728. cmDspVarArg_t args[] =
  1729. {
  1730. { "time", kTimeFaId, 0, 0, kDoubleDsvFl | kOptArgDsvFl, "Fade time in milliseconds."},
  1731. { "gate", kGateFaId, 0, 0, kInDsvFl | kBoolDsvFl, "Gate control signal."},
  1732. { "in", kInFaId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input."},
  1733. { "gain", kGainFaId, 0, 0, kOutDsvFl | kDoubleDsvFl, "gain output."},
  1734. { "out", kOutFaId, 0, 0, kOutDsvFl | kAudioBufDsvFl, "Audio out."},
  1735. { NULL, 0, 0, 0, 0, NULL }
  1736. };
  1737. cmDspFader_t* p;
  1738. if((p = cmDspInstAlloc(cmDspFader_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  1739. return NULL;
  1740. double dfltFadeTimeMs = 100.0;
  1741. cmDspSetDefaultDouble( ctx, &p->inst, kTimeFaId, 0.0, dfltFadeTimeMs );
  1742. p->fdp = cmFaderAlloc(ctx->cmProcCtx, NULL, cmDspSampleRate(ctx), dfltFadeTimeMs );
  1743. return &p->inst;
  1744. }
  1745. cmDspRC_t _cmDspFaderFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1746. {
  1747. cmDspFader_t* p = (cmDspFader_t*)inst;
  1748. cmFaderFree(&p->fdp);
  1749. return kOkDspRC;
  1750. }
  1751. cmDspRC_t _cmDspFaderReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1752. {
  1753. cmDspRC_t rc = kOkDspRC;
  1754. cmDspFader_t* p = (cmDspFader_t*)inst;
  1755. rc = cmDspApplyAllDefaults(ctx,inst);
  1756. cmDspZeroAudioBuf(ctx,inst,kOutFaId);
  1757. cmFaderSetFadeTime(p->fdp,cmDspDouble(inst,kTimeFaId));
  1758. return rc;
  1759. }
  1760. cmDspRC_t _cmDspFaderExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1761. {
  1762. cmDspRC_t rc = kOkDspRC;
  1763. cmDspFader_t* p = (cmDspFader_t*)inst;
  1764. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutFaId,0);
  1765. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutFaId,0);
  1766. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInFaId,0);
  1767. cmFaderExec(p->fdp,n,cmDspBool(inst,kGateFaId),false,ip,op);
  1768. cmDspSetDouble(ctx,inst,kGainFaId,p->fdp->gain);
  1769. return rc;
  1770. }
  1771. cmDspRC_t _cmDspFaderRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1772. {
  1773. cmDspRC_t rc = kOkDspRC;
  1774. cmDspFader_t* p = (cmDspFader_t*)inst;
  1775. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  1776. {
  1777. if( evt->dstVarId == kTimeFaId )
  1778. cmFaderSetFadeTime(p->fdp,cmDspDouble(inst,kTimeFaId));
  1779. }
  1780. return rc;
  1781. }
  1782. cmDspClass_t* cmFaderClassCons( cmDspCtx_t* ctx )
  1783. {
  1784. cmDspClassSetup(&_cmFaderDC,ctx,"Fader",
  1785. NULL,
  1786. _cmDspFaderAlloc,
  1787. _cmDspFaderFree,
  1788. _cmDspFaderReset,
  1789. _cmDspFaderExec,
  1790. _cmDspFaderRecv,
  1791. NULL,NULL,
  1792. "Audio fade in/out controller.");
  1793. return &_cmFaderDC;
  1794. }
  1795. //------------------------------------------------------------------------------------------------------------
  1796. //)
  1797. //( { label:cmDspNoteSelect file_desc:"'fluxo' gate based logic controller." kw:[sunit fluxo] }
  1798. enum
  1799. {
  1800. kChCntNsId,
  1801. kTrigNsId,
  1802. kDoneNsId,
  1803. kGateBaseNsId
  1804. };
  1805. enum
  1806. {
  1807. kGroupNonNsId,
  1808. kGroup0NsId,
  1809. kGroup1NsId
  1810. };
  1811. cmDspClass_t _cmNoteSelectDC;
  1812. typedef struct
  1813. {
  1814. cmDspInst_t inst;
  1815. unsigned chCnt;
  1816. unsigned rmsBaseNsId;
  1817. unsigned gate0BaseNsId;
  1818. unsigned gate1BaseNsId;
  1819. unsigned gate2BaseNsId;
  1820. unsigned gate3BaseNsId;
  1821. unsigned gate4BaseNsId;
  1822. bool* chGateV; // chGateV[chCnt]
  1823. cmReal_t* chRmsV; // chRmsV[ chCnt ];
  1824. unsigned* chGroupV; // chGroupV[ chCnt ] (0=non-chord 1=low/high 2=middle)
  1825. unsigned count;
  1826. unsigned doneSymId;
  1827. } cmDspNoteSelect_t;
  1828. cmDspInst_t* _cmDspNoteSelectAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  1829. {
  1830. cmDspVarArg_t args[] =
  1831. {
  1832. { "ch_cnt", kChCntNsId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count."},
  1833. { "trig", kTrigNsId, 0, 0, kInDsvFl | kBoolDsvFl, "Trigger note selection."},
  1834. { "done", kDoneNsId, 0, 0, kOutDsvFl | kSymDsvFl, "Sends 'done' after new set of outputs have been sent."},
  1835. };
  1836. if( va_cnt < 1 )
  1837. {
  1838. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The note selector must be given a channel count argument .");
  1839. return NULL;
  1840. }
  1841. va_list vl1;
  1842. unsigned CD0chanN = 0;
  1843. unsigned CD1chanN = 0;
  1844. unsigned* CD0chan = NULL;
  1845. unsigned* CD1chan = NULL;
  1846. const cmChar_t* CD0rsrc = "CD0chan";
  1847. const cmChar_t* CD1rsrc = "CD1chan";
  1848. if( cmDspRsrcUIntArray( ctx->dspH, &CD0chanN, &CD0chan, CD0rsrc, NULL ) != kOkDspRC )
  1849. {
  1850. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The chord detector channel index resource '%s' could not be read.",cmStringNullGuard(CD0rsrc));
  1851. return NULL;
  1852. }
  1853. if( cmDspRsrcUIntArray( ctx->dspH, &CD1chanN, &CD1chan, CD1rsrc, NULL ) != kOkDspRC )
  1854. {
  1855. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The chord detector channel index resource '%s' could not be read.",cmStringNullGuard(CD1rsrc));
  1856. return NULL;
  1857. }
  1858. va_copy(vl1,vl);
  1859. unsigned chCnt = va_arg(vl,unsigned);
  1860. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  1861. unsigned argCnt = fixArgCnt + 7*chCnt;
  1862. unsigned rmsBaseNsId = kGateBaseNsId + 1 * chCnt;
  1863. unsigned gate0BaseNsId = kGateBaseNsId + 2 * chCnt;
  1864. unsigned gate1BaseNsId = kGateBaseNsId + 3 * chCnt;
  1865. unsigned gate2BaseNsId = kGateBaseNsId + 4 * chCnt;
  1866. unsigned gate3BaseNsId = kGateBaseNsId + 5 * chCnt;
  1867. unsigned gate4BaseNsId = kGateBaseNsId + 6 * chCnt;
  1868. cmDspVarArg_t a[ argCnt+1 ];
  1869. unsigned i;
  1870. cmDspNoteSelect_t* p;
  1871. // setup the input gate detectors and the output gain args
  1872. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  1873. cmDspArgSetupN(ctx, a, argCnt, kGateBaseNsId, chCnt, "gate", kGateBaseNsId, 0, 0, kInDsvFl | kBoolDsvFl, "Channel gate input.");
  1874. cmDspArgSetupN(ctx, a, argCnt, rmsBaseNsId, chCnt, "rms", rmsBaseNsId, 0, 0, kInDsvFl | kDoubleDsvFl, "Channel RMS input");
  1875. cmDspArgSetupN(ctx, a, argCnt, gate0BaseNsId, chCnt, "gate-0", gate0BaseNsId, 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 0 output.");
  1876. cmDspArgSetupN(ctx, a, argCnt, gate1BaseNsId, chCnt, "gate-1", gate1BaseNsId, 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 1 output.");
  1877. cmDspArgSetupN(ctx, a, argCnt, gate2BaseNsId, chCnt, "gate-2", gate2BaseNsId, 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 2 output.");
  1878. cmDspArgSetupN(ctx, a, argCnt, gate3BaseNsId, chCnt, "gate-3", gate3BaseNsId, 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 3 output.");
  1879. cmDspArgSetupN(ctx, a, argCnt, gate4BaseNsId, chCnt, "gate-4", gate4BaseNsId, 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 4 output.");
  1880. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  1881. if((p = cmDspInstAlloc(cmDspNoteSelect_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1)) == NULL )
  1882. return NULL;
  1883. cmDspSetDefaultBool( ctx, &p->inst, kTrigNsId, false, false );
  1884. cmDspSetDefaultSymbol( ctx, &p->inst, kDoneNsId, cmInvalidId );
  1885. p->rmsBaseNsId = rmsBaseNsId;
  1886. p->gate0BaseNsId = gate0BaseNsId;
  1887. p->gate1BaseNsId = gate1BaseNsId;
  1888. p->gate2BaseNsId = gate2BaseNsId;
  1889. p->gate3BaseNsId = gate3BaseNsId;
  1890. p->gate4BaseNsId = gate4BaseNsId;
  1891. p->chCnt = chCnt;
  1892. p->chGateV = cmMemAllocZ(bool,chCnt);
  1893. p->chRmsV = cmMemAllocZ(cmReal_t,chCnt);
  1894. p->chGroupV = cmMemAllocZ(unsigned,chCnt);
  1895. p->doneSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"done");
  1896. for(i=0; i<CD0chanN; ++i)
  1897. {
  1898. if( CD0chan[i] >= chCnt )
  1899. cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The chord detector resource array '%s' value %i is out of range %i.",cmStringNullGuard(CD0rsrc),CD0chan[i],chCnt);
  1900. else
  1901. p->chGroupV[ CD0chan[i] ] = kGroup0NsId;
  1902. }
  1903. for(i=0; i<CD1chanN; ++i)
  1904. {
  1905. if( CD1chan[i] >= chCnt )
  1906. cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The chord detector resource array '%s' value %i is out of range %i.",cmStringNullGuard(CD1rsrc),CD1chan[i],chCnt);
  1907. else
  1908. p->chGroupV[ CD1chan[i] ] = kGroup1NsId;
  1909. }
  1910. for(i=0; i<chCnt; ++i)
  1911. {
  1912. cmDspSetDefaultDouble(ctx, &p->inst, rmsBaseNsId+i, 0.0, 0.0 );
  1913. cmDspSetDefaultBool( ctx, &p->inst, gate0BaseNsId+i, false, false );
  1914. cmDspSetDefaultBool( ctx, &p->inst, gate1BaseNsId+i, false, false );
  1915. cmDspSetDefaultBool( ctx, &p->inst, gate2BaseNsId+i, false, false );
  1916. cmDspSetDefaultBool( ctx, &p->inst, gate3BaseNsId+i, false, false );
  1917. // the non-chord channel selections should always be on
  1918. cmDspSetDefaultBool( ctx, &p->inst, gate4BaseNsId+i, false, p->chGroupV[i] == kGroupNonNsId );
  1919. }
  1920. va_end(vl1);
  1921. return &p->inst;
  1922. }
  1923. cmDspRC_t _cmDspNoteSelectFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1924. {
  1925. cmDspNoteSelect_t* p = (cmDspNoteSelect_t*)inst;
  1926. cmMemFree(p->chGateV);
  1927. cmMemFree(p->chRmsV);
  1928. cmMemFree(p->chGroupV);
  1929. return kOkDspRC;
  1930. }
  1931. cmDspRC_t _cmDspNoteSelectReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1932. {
  1933. cmDspRC_t rc = kOkDspRC;
  1934. cmDspNoteSelect_t* p = (cmDspNoteSelect_t*)inst;
  1935. rc = cmDspApplyAllDefaults(ctx,inst);
  1936. cmVOR_Zero(p->chRmsV,p->chCnt);
  1937. return rc;
  1938. }
  1939. cmDspRC_t _cmDspNoteSelectRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  1940. {
  1941. cmDspRC_t rc = kOkDspRC;
  1942. cmDspNoteSelect_t* p = (cmDspNoteSelect_t*)inst;
  1943. // store incoming gate values
  1944. if( kGateBaseNsId <= evt->dstVarId && evt->dstVarId < kGateBaseNsId + p->chCnt )
  1945. p->chGateV[ evt->dstVarId - kGateBaseNsId ] = cmDsvGetBool(evt->valuePtr);
  1946. else
  1947. // store incoming RMS values
  1948. if( p->rmsBaseNsId <= evt->dstVarId && evt->dstVarId < p->rmsBaseNsId + p->chCnt )
  1949. p->chRmsV[ evt->dstVarId - p->rmsBaseNsId ] = cmDsvGetReal( evt->valuePtr );
  1950. else
  1951. {
  1952. // if a chord detection was triggered
  1953. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && evt->dstVarId == kTrigNsId )
  1954. {
  1955. unsigned i;
  1956. cmReal_t maxRms = 0;
  1957. unsigned maxIdx = cmInvalidIdx;
  1958. for(i=1; i<p->chCnt; ++i)
  1959. {
  1960. // if this channel had an onset and is a possible chord note and is the max RMS chord note
  1961. if( p->chGroupV[i] != kGroupNonNsId && p->chGateV[i] && (maxIdx==cmInvalidIdx || p->chRmsV[i] > maxRms) )
  1962. {
  1963. maxRms = p->chRmsV[i];
  1964. maxIdx = i;
  1965. }
  1966. }
  1967. for(i=0; i<p->chCnt; ++i)
  1968. {
  1969. bool fl = p->chGroupV[i] != kGroupNonNsId;
  1970. bool chosenFl = fl && i==maxIdx;
  1971. bool otherFl = fl && i!=maxIdx && p->chGateV[i];
  1972. bool cd0Fl = p->chGroupV[i]==kGroup0NsId && (!otherFl) && (!chosenFl);
  1973. bool cd1Fl = p->chGroupV[i]==kGroup1NsId && (!otherFl) && (!chosenFl);
  1974. // gate set 0: set output gate for max chord note
  1975. cmDspSetBool(ctx,inst,p->gate0BaseNsId+i, chosenFl );
  1976. // gate set 1: set output gate for non-max chord notes
  1977. cmDspSetBool(ctx,inst,p->gate1BaseNsId+i, otherFl );
  1978. // gate set 2: set output gate for non-chord notes
  1979. cmDspSetBool(ctx,inst,p->gate2BaseNsId+i, cd0Fl );
  1980. // gate set 3: set output gate for non-chord notes
  1981. cmDspSetBool(ctx,inst,p->gate3BaseNsId+i, cd1Fl);
  1982. // gate set 4: set output gate for non-chord notes
  1983. cmDspSetBool(ctx,inst,p->gate4BaseNsId+i, !fl );
  1984. }
  1985. // send the 'done' symbol to notify the gate receivers that the
  1986. // new set of gates is complete
  1987. cmDspSetSymbol(ctx,inst,kDoneNsId, p->doneSymId);
  1988. // zero the RMS vector
  1989. cmVOR_Zero(p->chRmsV,p->chCnt);
  1990. }
  1991. }
  1992. return rc;
  1993. }
  1994. cmDspClass_t* cmNoteSelectClassCons( cmDspCtx_t* ctx )
  1995. {
  1996. cmDspClassSetup(&_cmNoteSelectDC,ctx,"NoteSelect",
  1997. NULL,
  1998. _cmDspNoteSelectAlloc,
  1999. _cmDspNoteSelectFree,
  2000. _cmDspNoteSelectReset,
  2001. NULL,
  2002. _cmDspNoteSelectRecv,
  2003. NULL,NULL,
  2004. "Chord detector.");
  2005. return &_cmNoteSelectDC;
  2006. }
  2007. //------------------------------------------------------------------------------------------------------------
  2008. //)
  2009. //( { label:cmDspNetNoteSelect file_desc:"'fluxo' transmit gate information over the UDP network." kw:[sunit fluxo] }
  2010. enum
  2011. {
  2012. kTrigNnId,
  2013. kDoneNnId,
  2014. kGateBaseNnId
  2015. };
  2016. cmDspClass_t _cmNetNoteSelectDC;
  2017. #define _cmNetNoteSelPortCnt (10)
  2018. typedef struct
  2019. {
  2020. cmDspInst_t inst;
  2021. unsigned chCnt;
  2022. unsigned rmsBaseNnId;
  2023. unsigned gateBaseNNId[ _cmNetNoteSelPortCnt ];
  2024. bool* chGateV; // chGateV[chCnt]
  2025. cmReal_t* chRmsV; // chRmsV[ chCnt ];
  2026. unsigned* portChCntV; // portChCntV[ 10 ]
  2027. unsigned* portBaseIdV; // portBaseIdV[ 10 ]
  2028. unsigned* chPortV; // chPortV[ chCnt ]
  2029. unsigned* chPortIdxV; // chPortIdxV[ chCnt ]
  2030. unsigned* ncPortV; // ncPortV[ chCnt ]
  2031. unsigned* ncPortIdxV; // ncPortIdxV[ chCnt ]
  2032. unsigned count;
  2033. unsigned doneSymId;
  2034. } cmDspNetNoteSelect_t;
  2035. cmDspInst_t* _cmDspNetNoteSelectAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2036. {
  2037. unsigned chCnt = 0;
  2038. const cmChar_t* label = NULL;
  2039. const cmChar_t* chPortRsrc = "nsChSelChV";
  2040. unsigned* chPortV = NULL;
  2041. const cmChar_t* chPortIdxRsrc = "nsChSelChIdxV";
  2042. unsigned* chPortIdxV = NULL;
  2043. const cmChar_t* ncPortRsrc = "nsNcSelChV";
  2044. unsigned* ncPortV = NULL;
  2045. const cmChar_t* ncPortIdxRsrc = "nsNcSelChIdxV";
  2046. unsigned* ncPortIdxV = NULL;
  2047. unsigned i,j,n;
  2048. cmDspVarArg_t args[] =
  2049. {
  2050. { "trig", kTrigNnId, 0, 0, kInDsvFl | kBoolDsvFl, "Trigger note selection."},
  2051. { "done", kDoneNnId, 0, 0, kOutDsvFl | kSymDsvFl, "Sends 'done' after new set of outputs have been sent."},
  2052. };
  2053. if( cmDspRsrcUIntArray( ctx->dspH, &chCnt, &chPortV, label = chPortRsrc, NULL ) != kOkDspRC )
  2054. {
  2055. cmDspClassErr(ctx,classPtr,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",label);
  2056. return NULL;
  2057. }
  2058. if( cmDspRsrcUIntArray( ctx->dspH, &n, &chPortIdxV, label = chPortIdxRsrc, NULL ) != kOkDspRC )
  2059. {
  2060. cmDspClassErr(ctx,classPtr,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",label);
  2061. return NULL;
  2062. }
  2063. assert(n == chCnt );
  2064. if( cmDspRsrcUIntArray( ctx->dspH, &n, &ncPortV, label = ncPortRsrc, NULL ) != kOkDspRC )
  2065. {
  2066. cmDspClassErr(ctx,classPtr,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",label);
  2067. return NULL;
  2068. }
  2069. assert(n == chCnt );
  2070. if( cmDspRsrcUIntArray( ctx->dspH, &n, &ncPortIdxV, label = ncPortIdxRsrc, NULL ) != kOkDspRC )
  2071. {
  2072. cmDspClassErr(ctx,classPtr,kRsrcNotFoundDspRC,"The resource '%s' could not be read.",label);
  2073. return NULL;
  2074. }
  2075. assert(n == chCnt );
  2076. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  2077. unsigned rmsBaseNnId = kGateBaseNnId + chCnt;
  2078. // get the count of ch's on each port
  2079. unsigned* portChCntV = cmLhAllocZ( ctx->lhH, unsigned, _cmNetNoteSelPortCnt );
  2080. unsigned* portBaseIdV = cmLhAllocZ( ctx->lhH, unsigned, _cmNetNoteSelPortCnt );
  2081. for(i=0; i<_cmNetNoteSelPortCnt; ++i)
  2082. {
  2083. // get the count of ch's in the ith gate output port
  2084. portChCntV[i] = cmVOU_Count( chPortV, chCnt, i ) + cmVOU_Count( ncPortV, chCnt, i );
  2085. // ports 1 and 6 are duplicates of ports 0 and 5
  2086. if( i == 1 || i == 6 )
  2087. portChCntV[i] = portChCntV[i-1];
  2088. // set the base port id for this port
  2089. if( i > 0 )
  2090. portBaseIdV[i] = portBaseIdV[i-1] + portChCntV[i-1];
  2091. else
  2092. portBaseIdV[ i ] = rmsBaseNnId + chCnt;
  2093. }
  2094. unsigned argCnt = fixArgCnt + (2*chCnt) + cmVOU_Sum(portChCntV,_cmNetNoteSelPortCnt );
  2095. cmDspVarArg_t a[ argCnt+1 ];
  2096. cmDspNetNoteSelect_t* p;
  2097. // setup the input gate detectors and the output gain args
  2098. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  2099. cmDspArgSetupN(ctx, a, argCnt, kGateBaseNnId, chCnt, "gate", kGateBaseNnId, 0, 0, kInDsvFl | kBoolDsvFl, "Channel gate input.");
  2100. cmDspArgSetupN(ctx, a, argCnt, rmsBaseNnId, chCnt, "rms", rmsBaseNnId, 0, 0, kInDsvFl | kDoubleDsvFl, "Channel RMS input");
  2101. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[0], portChCntV[0], "gate-0", portBaseIdV[0], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 0 output.");
  2102. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[1], portChCntV[1], "gate-1", portBaseIdV[1], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 1 output.");
  2103. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[2], portChCntV[2], "gate-2", portBaseIdV[2], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 2 output.");
  2104. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[3], portChCntV[3], "gate-3", portBaseIdV[3], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 3 output.");
  2105. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[4], portChCntV[4], "gate-4", portBaseIdV[4], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 4 output.");
  2106. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[5], portChCntV[5], "gate-5", portBaseIdV[5], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 5 output.");
  2107. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[6], portChCntV[6], "gate-6", portBaseIdV[6], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 6 output.");
  2108. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[7], portChCntV[7], "gate-7", portBaseIdV[7], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 7 output.");
  2109. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[8], portChCntV[8], "gate-8", portBaseIdV[8], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 8 output.");
  2110. cmDspArgSetupN(ctx, a, argCnt, portBaseIdV[9], portChCntV[9], "gate-9", portBaseIdV[9], 0, 0, kOutDsvFl | kBoolDsvFl, "Channel gate set 9 output.");
  2111. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  2112. if((p = cmDspInstAlloc(cmDspNetNoteSelect_t,ctx,classPtr,a,instSymId,id,storeSymId,0,vl)) == NULL )
  2113. return NULL;
  2114. cmDspSetDefaultBool( ctx, &p->inst, kTrigNnId, false, false );
  2115. cmDspSetDefaultSymbol( ctx, &p->inst, kDoneNnId, cmInvalidId );
  2116. p->rmsBaseNnId = rmsBaseNnId;
  2117. p->chCnt = chCnt;
  2118. p->chGateV = cmMemAllocZ(bool,chCnt);
  2119. p->chRmsV = cmMemAllocZ(cmReal_t,chCnt);
  2120. p->portChCntV = portChCntV;
  2121. p->portBaseIdV = portBaseIdV;
  2122. p->doneSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"done");
  2123. p->chPortV = chPortV;
  2124. p->chPortIdxV = chPortIdxV;
  2125. p->ncPortV = ncPortV;
  2126. p->ncPortIdxV = ncPortIdxV;
  2127. for(i=0; i<chCnt; ++i)
  2128. {
  2129. cmDspSetDefaultBool( ctx, &p->inst, kGateBaseNnId+i, false, false );
  2130. cmDspSetDefaultDouble(ctx, &p->inst, rmsBaseNnId+i, 0.0, 0.0 );
  2131. }
  2132. for(i=0; i<_cmNetNoteSelPortCnt; ++i)
  2133. for(j=0; j<p->portChCntV[i]; ++j)
  2134. cmDspSetDefaultBool( ctx, &p->inst, p->portBaseIdV[i]+j, false, false );
  2135. return &p->inst;
  2136. }
  2137. cmDspRC_t _cmDspNetNoteSelectFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2138. {
  2139. cmDspNetNoteSelect_t* p = (cmDspNetNoteSelect_t*)inst;
  2140. cmMemFree(p->chGateV);
  2141. cmMemFree(p->chRmsV);
  2142. return kOkDspRC;
  2143. }
  2144. cmDspRC_t _cmDspNetNoteSelectReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2145. {
  2146. cmDspRC_t rc = kOkDspRC;
  2147. cmDspNetNoteSelect_t* p = (cmDspNetNoteSelect_t*)inst;
  2148. rc = cmDspApplyAllDefaults(ctx,inst);
  2149. cmVOR_Zero(p->chRmsV,p->chCnt);
  2150. return rc;
  2151. }
  2152. cmDspRC_t _cmDspNetNoteSelectRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2153. {
  2154. cmDspRC_t rc = kOkDspRC;
  2155. cmDspNetNoteSelect_t* p = (cmDspNetNoteSelect_t*)inst;
  2156. // store incoming gate values
  2157. if( kGateBaseNnId <= evt->dstVarId && evt->dstVarId < kGateBaseNnId + p->chCnt )
  2158. {
  2159. p->chGateV[ evt->dstVarId - kGateBaseNnId ] = cmDsvGetBool(evt->valuePtr);
  2160. //unsigned idx = evt->dstVarId - kGateBaseNnId;
  2161. //cmRptPrintf(ctx->rpt,"ns gate:%i %i\n",idx, p->chGateV[ idx ]);
  2162. }
  2163. else
  2164. // store incoming RMS values
  2165. if( p->rmsBaseNnId <= evt->dstVarId && evt->dstVarId < p->rmsBaseNnId + p->chCnt )
  2166. {
  2167. p->chRmsV[ evt->dstVarId - p->rmsBaseNnId ] = cmDsvGetReal( evt->valuePtr );
  2168. }
  2169. else
  2170. {
  2171. // if a chord detection was triggered
  2172. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC && evt->dstVarId == kTrigNnId )
  2173. {
  2174. unsigned i;
  2175. cmReal_t maxRms = 0;
  2176. unsigned maxIdx = cmInvalidIdx;
  2177. for(i=1; i<p->chCnt; ++i)
  2178. {
  2179. // if this channel had an onset and is a possible chord note and is the max RMS chord note
  2180. if( p->chGateV[i] && (maxIdx==cmInvalidIdx || p->chRmsV[i] > maxRms) )
  2181. {
  2182. maxRms = p->chRmsV[i];
  2183. maxIdx = i;
  2184. }
  2185. }
  2186. for(i=0; i<p->chCnt; ++i)
  2187. {
  2188. bool chosenFl = i==maxIdx;
  2189. bool otherFl = i!=maxIdx && p->chGateV[i];
  2190. bool nonFl = chosenFl==false && otherFl==false;
  2191. unsigned k;
  2192. // if this is a chord channel
  2193. if( p->chPortV[i] != cmInvalidIdx )
  2194. {
  2195. // get the port associated with this chord note
  2196. k = p->chPortV[i];
  2197. assert( k+1 < _cmNetNoteSelPortCnt );
  2198. assert( p->chPortIdxV[i] < p->portChCntV[k] && p->chPortIdxV[i] < p->portChCntV[k+1] );
  2199. // set the chosen and other gate outputs based on the state of
  2200. // chosenFl and otherFl
  2201. cmDspSetBool(ctx,inst,p->portBaseIdV[ k ] + p->chPortIdxV[i],chosenFl);
  2202. cmDspSetBool(ctx,inst,p->portBaseIdV[ k+1 ] + p->chPortIdxV[i],otherFl);
  2203. }
  2204. // all channels have a 'single' note channel
  2205. assert( p->ncPortV[i] != cmInvalidIdx );
  2206. k = p->ncPortV[i];
  2207. assert( k < _cmNetNoteSelPortCnt );
  2208. assert( p->ncPortIdxV[i] < p->portChCntV[k] );
  2209. cmDspSetBool(ctx,inst,p->portBaseIdV[k] + p->ncPortIdxV[i],nonFl);
  2210. }
  2211. // send the 'done' symbol to notify the gate receivers that the
  2212. // new set of gates is complete
  2213. cmDspSetSymbol(ctx,inst,kDoneNnId, p->doneSymId);
  2214. // zero the RMS vector
  2215. cmVOR_Zero(p->chRmsV,p->chCnt);
  2216. }
  2217. }
  2218. return rc;
  2219. }
  2220. cmDspClass_t* cmNetNoteSelectClassCons( cmDspCtx_t* ctx )
  2221. {
  2222. cmDspClassSetup(&_cmNetNoteSelectDC,ctx,"NetNoteSelect",
  2223. NULL,
  2224. _cmDspNetNoteSelectAlloc,
  2225. _cmDspNetNoteSelectFree,
  2226. _cmDspNetNoteSelectReset,
  2227. NULL,
  2228. _cmDspNetNoteSelectRecv,
  2229. NULL,NULL,
  2230. "Chord detector.");
  2231. return &_cmNetNoteSelectDC;
  2232. }
  2233. //------------------------------------------------------------------------------------------------------------
  2234. //)
  2235. //( { label:cmDspCombFilt file_desc:"Comb and Inverse comb filter." kw:[sunit] }
  2236. enum
  2237. {
  2238. kBypassCfId,
  2239. kMinHzCfId,
  2240. kFbFlCfId,
  2241. kHzCfId,
  2242. kAlphaCfId,
  2243. kInCfId,
  2244. kOutCfId
  2245. };
  2246. cmDspClass_t _cmCombFiltDC;
  2247. typedef struct
  2248. {
  2249. cmDspInst_t inst;
  2250. cmCombFilt* cfp;
  2251. } cmDspCombFilt_t;
  2252. cmDspInst_t* _cmDspCombFiltAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2253. {
  2254. cmDspVarArg_t args[] =
  2255. {
  2256. { "bypass",kBypassCfId, 0, 0, kInDsvFl | kBoolDsvFl | kReqArgDsvFl, "Bypass enable flag." },
  2257. { "minhz", kMinHzCfId, 0, 0, kDoubleDsvFl | kReqArgDsvFl, "Minimum frequency limit."},
  2258. { "fb", kFbFlCfId, 0, 0, kInDsvFl | kBoolDsvFl | kReqArgDsvFl, "Configure the filter in feedback mode."},
  2259. { "hz", kHzCfId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Lowest comb frequency." },
  2260. { "alpha", kAlphaCfId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Filter coefficent."},
  2261. { "in", kInCfId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input."},
  2262. { "out", kOutCfId, 0, 1, kOutDsvFl| kAudioBufDsvFl, "Audio out."},
  2263. { NULL, 0, 0, 0, 0, NULL }
  2264. };
  2265. cmDspCombFilt_t* p;
  2266. if((p = cmDspInstAlloc(cmDspCombFilt_t,ctx,classPtr,args,instSymId,id,storeSymId,va_cnt,vl)) == NULL )
  2267. return NULL;
  2268. p->cfp = cmCombFiltAlloc(ctx->cmProcCtx, NULL,
  2269. cmDspSampleRate(ctx),
  2270. cmDspBool(&p->inst,kFbFlCfId),
  2271. cmDspDouble(&p->inst,kMinHzCfId),
  2272. cmDspDouble(&p->inst,kAlphaCfId),
  2273. cmDspDouble(&p->inst,kHzCfId),
  2274. cmDspBool(&p->inst,kBypassCfId));
  2275. return &p->inst;
  2276. }
  2277. cmDspRC_t _cmDspCombFiltFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2278. {
  2279. cmDspCombFilt_t* p = (cmDspCombFilt_t*)inst;
  2280. cmCombFiltFree(&p->cfp);
  2281. return kOkDspRC;
  2282. }
  2283. cmDspRC_t _cmDspCombFiltReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2284. {
  2285. cmDspRC_t rc = kOkDspRC;
  2286. cmDspCombFilt_t* p = (cmDspCombFilt_t*)inst;
  2287. rc = cmDspApplyAllDefaults(ctx,inst);
  2288. cmDspZeroAudioBuf(ctx,inst,kOutCfId);
  2289. cmCombFiltInit(p->cfp,
  2290. cmDspSampleRate(ctx),
  2291. cmDspBool(inst,kFbFlCfId),
  2292. cmDspDouble(inst,kMinHzCfId),
  2293. cmDspDouble(inst,kAlphaCfId),
  2294. cmDspDouble(inst,kHzCfId),
  2295. cmDspBool(inst,kBypassCfId));
  2296. return rc;
  2297. }
  2298. cmDspRC_t _cmDspCombFiltExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2299. {
  2300. cmDspRC_t rc = kOkDspRC;
  2301. cmDspCombFilt_t* p = (cmDspCombFilt_t*)inst;
  2302. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutCfId,0);
  2303. cmSample_t* op = cmDspAudioBuf(ctx,inst,kOutCfId,0);
  2304. const cmSample_t* ip = cmDspAudioBuf(ctx,inst,kInCfId,0);
  2305. cmCombFiltExec(p->cfp,ip,op,n);
  2306. return rc;
  2307. }
  2308. cmDspRC_t _cmDspCombFiltRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2309. {
  2310. cmDspRC_t rc = kOkDspRC;
  2311. cmDspCombFilt_t* p = (cmDspCombFilt_t*)inst;
  2312. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  2313. {
  2314. switch( evt->dstVarId )
  2315. {
  2316. case kHzCfId:
  2317. cmCombFiltSetHz(p->cfp,cmDspDouble(inst,evt->dstVarId));
  2318. //printf("%s hz:%f\n",cmSymTblLabel(ctx->stH,inst->symId),cmDspDouble(inst,evt->dstVarId));
  2319. break;
  2320. case kAlphaCfId:
  2321. cmCombFiltSetAlpha(p->cfp,cmDspDouble(inst,evt->dstVarId));
  2322. break;
  2323. case kBypassCfId:
  2324. p->cfp->bypassFl = cmDspBool(inst,evt->dstVarId);
  2325. break;
  2326. }
  2327. }
  2328. return rc;
  2329. }
  2330. cmDspClass_t* cmCombFiltClassCons( cmDspCtx_t* ctx )
  2331. {
  2332. cmDspClassSetup(&_cmCombFiltDC,ctx,"CombFilt",
  2333. NULL,
  2334. _cmDspCombFiltAlloc,
  2335. _cmDspCombFiltFree,
  2336. _cmDspCombFiltReset,
  2337. _cmDspCombFiltExec,
  2338. _cmDspCombFiltRecv,
  2339. NULL,NULL,
  2340. "Comb Filter");
  2341. return &_cmCombFiltDC;
  2342. }
  2343. //------------------------------------------------------------------------------------------------------------
  2344. //)
  2345. //( { label:cmDspScalarOp file_desc:"Perform arithmetic functions on scalar values." kw:[sunit] }
  2346. enum
  2347. {
  2348. kPortCntSoId,
  2349. kOpSoId,
  2350. kOutSoId,
  2351. kBaseOpdSoId
  2352. };
  2353. cmDspClass_t _cmScalarOpDC;
  2354. struct cmDspScalarOp_str;
  2355. typedef cmDspRC_t (*_cmDspScalarOpFunc_t)(cmDspCtx_t* ctx, cmDspInst_t* inst );
  2356. typedef struct cmDspScalar_str
  2357. {
  2358. cmDspInst_t inst;
  2359. _cmDspScalarOpFunc_t func;
  2360. unsigned inPortCnt;
  2361. bool allActiveFl;
  2362. } cmDspScalarOp_t;
  2363. cmDspRC_t _cmDspScalarOpFuncMult(cmDspCtx_t* ctx, cmDspInst_t* inst )
  2364. {
  2365. cmDspScalarOp_t* p = (cmDspScalarOp_t*)inst;
  2366. double val = 1.0;
  2367. unsigned i;
  2368. for(i=0; i<p->inPortCnt; ++i)
  2369. val *= cmDspDouble( inst, kBaseOpdSoId+i );
  2370. cmDspSetDouble( ctx, inst, kOutSoId, val );
  2371. return kOkDspRC;
  2372. }
  2373. cmDspRC_t _cmDspScalarOpFuncAdd(cmDspCtx_t* ctx, cmDspInst_t* inst )
  2374. {
  2375. cmDspScalarOp_t* p = (cmDspScalarOp_t*)inst;
  2376. double val = 0;
  2377. unsigned i;
  2378. for(i=0; i<p->inPortCnt; ++i)
  2379. val += cmDspDouble( inst, kBaseOpdSoId+i );
  2380. cmDspSetDouble( ctx, inst, kOutSoId, val );
  2381. return kOkDspRC;
  2382. }
  2383. // var args syntax: "<in_port_cnt> <op_string> <opd_label_0> <opd_dflt_val_0> <opd_label_1> <opd_dflt_val_1> ... <opd_label_n> <opd_dflt_val_n>
  2384. cmDspInst_t* _cmDspScalarOpAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2385. {
  2386. cmDspVarArg_t args[] =
  2387. {
  2388. { "cnt", kPortCntSoId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Input port count" },
  2389. { "op", kOpSoId, 0, 0, kStrzDsvFl | kReqArgDsvFl, "Operation symbol as a string."},
  2390. { "out", kOutSoId, 0, 0, kDoubleDsvFl | kOutDsvFl, "Operation output."},
  2391. };
  2392. cmDspScalarOp_t* p;
  2393. if( va_cnt < 2 )
  2394. {
  2395. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'ScalarOp' constructor must have a count of input ports and operation identifier string.");
  2396. return NULL;
  2397. }
  2398. va_list vl1;
  2399. va_copy(vl1,vl);
  2400. unsigned inPortCnt = va_arg(vl,unsigned);
  2401. const cmChar_t* opIdStr = va_arg(vl,const cmChar_t*);
  2402. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  2403. unsigned argCnt = fixArgCnt + inPortCnt;
  2404. cmDspVarArg_t a[ argCnt+1 ];
  2405. double dfltVal[ inPortCnt ];
  2406. unsigned i;
  2407. _cmDspScalarOpFunc_t fp = NULL;
  2408. bool allActiveFl = false;
  2409. // validate the count of input ports
  2410. if( inPortCnt == 0 )
  2411. {
  2412. cmDspClassErr(ctx,classPtr,kVarNotValidDspRC,"The 'ScalarOp' constructor input port argument must be non-zero.");
  2413. goto errLabel;
  2414. }
  2415. if( opIdStr != NULL )
  2416. {
  2417. switch( opIdStr[0] )
  2418. {
  2419. case '*':
  2420. fp = _cmDspScalarOpFuncMult;
  2421. break;
  2422. case '+':
  2423. fp = _cmDspScalarOpFuncAdd;
  2424. break;
  2425. }
  2426. // if the second character of the operator string is '$' then all input ports trigger an output
  2427. if( strlen( opIdStr ) > 0 && opIdStr[1]=='$' )
  2428. allActiveFl = true;
  2429. }
  2430. // validate the operation function
  2431. if( fp == NULL )
  2432. {
  2433. cmDspClassErr(ctx,classPtr,kVarNotValidDspRC,"The 'ScalarOp' constructor operation string id '%s' did not match a known operation.",cmStringNullGuard(opIdStr));
  2434. goto errLabel;
  2435. }
  2436. // setup the fixed args
  2437. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  2438. for(i=0; i<inPortCnt; ++i)
  2439. {
  2440. // get the operand label
  2441. const cmChar_t* label = va_arg(vl,const cmChar_t*);
  2442. // get the operand default value
  2443. dfltVal[i] = va_arg(vl,double);
  2444. // setup the arg recd
  2445. cmDspArgSetup(ctx,a + fixArgCnt + i, label, cmInvalidId, kBaseOpdSoId+i,0,0,kDoubleDsvFl|kInDsvFl,"Operand");
  2446. }
  2447. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  2448. if((p = cmDspInstAlloc(cmDspScalarOp_t,ctx,classPtr,a,instSymId,id,storeSymId,2,vl1)) == NULL )
  2449. goto errLabel;
  2450. for(i=0; i<inPortCnt; ++i)
  2451. cmDspSetDefaultDouble(ctx,&p->inst,kBaseOpdSoId+i,0.0,dfltVal[i]);
  2452. p->inPortCnt = inPortCnt;
  2453. p->func = fp;
  2454. p->allActiveFl = allActiveFl;
  2455. va_end(vl1);
  2456. return &p->inst;
  2457. errLabel:
  2458. va_end(vl1);
  2459. return NULL;
  2460. }
  2461. cmDspRC_t _cmDspScalarOpReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2462. {
  2463. cmDspRC_t rc = kOkDspRC;
  2464. rc = cmDspApplyAllDefaults(ctx,inst);
  2465. return rc;
  2466. }
  2467. cmDspRC_t _cmDspScalarOpRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2468. {
  2469. cmDspRC_t rc = kOkDspRC;
  2470. cmDspScalarOp_t* p = (cmDspScalarOp_t*)inst;
  2471. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  2472. {
  2473. if( evt->dstVarId == kBaseOpdSoId || p->allActiveFl )
  2474. p->func(ctx,inst);
  2475. }
  2476. return rc;
  2477. }
  2478. cmDspClass_t* cmScalarOpClassCons( cmDspCtx_t* ctx )
  2479. {
  2480. cmDspClassSetup(&_cmScalarOpDC,ctx,"ScalarOp",
  2481. NULL,
  2482. _cmDspScalarOpAlloc,
  2483. NULL,
  2484. _cmDspScalarOpReset,
  2485. NULL,
  2486. _cmDspScalarOpRecv,
  2487. NULL,NULL,
  2488. "Scalar Operations");
  2489. return &_cmScalarOpDC;
  2490. }
  2491. //------------------------------------------------------------------------------------------------------------
  2492. //)
  2493. //( { label:cmDspGroupSel file_desc:"Select one group of audio channels from a set of audio channel groups." kw:[sunit] }
  2494. enum
  2495. {
  2496. kChCntGsId,
  2497. kGroupCntGsId,
  2498. kChsPerGroupGsId,
  2499. kBaseGateGsId,
  2500. };
  2501. cmDspClass_t _cmGroupSelDC;
  2502. typedef struct
  2503. {
  2504. cmDspInst_t inst;
  2505. unsigned chCnt;
  2506. unsigned groupCnt;
  2507. cmGroupSel* gsp;
  2508. unsigned baseRmsGsId;
  2509. unsigned baseOutGsId;
  2510. } cmDspGroupSel_t;
  2511. cmDspInst_t* _cmDspGroupSelAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2512. {
  2513. cmDspVarArg_t args[] =
  2514. {
  2515. { "chCnt", kChCntGsId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count." },
  2516. { "groupCnt", kGroupCntGsId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Group count." },
  2517. { "chsPerGroup", kChsPerGroupGsId, 0, 0, kUIntDsvFl | kInDsvFl | kReqArgDsvFl, "Channels per group." }
  2518. };
  2519. if( va_cnt < 2 )
  2520. {
  2521. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'GroupSel' constructor must have a channel and group count.");
  2522. return NULL;
  2523. }
  2524. va_list vl1;
  2525. va_copy(vl1,vl);
  2526. cmDspGroupSel_t* p;
  2527. unsigned i;
  2528. unsigned chCnt = va_arg(vl,unsigned);
  2529. unsigned groupCnt = va_arg(vl,unsigned);
  2530. unsigned outCnt = chCnt * groupCnt;
  2531. unsigned fixArgCnt = sizeof(args)/sizeof(args[0]);
  2532. unsigned baseRmsGsId = kBaseGateGsId + chCnt;
  2533. unsigned baseOutGsId = baseRmsGsId + chCnt;
  2534. unsigned argCnt = baseOutGsId + outCnt;
  2535. cmDspVarArg_t a[ argCnt + 1 ];
  2536. cmDspArgCopy( a, argCnt, 0, args, fixArgCnt );
  2537. cmDspArgSetupN(ctx, a, argCnt, kBaseGateGsId, chCnt, "gate", kBaseGateGsId, 0, 0, kInDsvFl | kBoolDsvFl, "Channel gate input.");
  2538. cmDspArgSetupN(ctx, a, argCnt, baseRmsGsId, chCnt, "rms", baseRmsGsId, 0, 0, kInDsvFl | kDoubleDsvFl, "Channel RMS input");
  2539. for(i=0; i<groupCnt; ++i)
  2540. {
  2541. int labelCharCnt = 31;
  2542. char label[ labelCharCnt + 1 ];
  2543. snprintf(label,labelCharCnt,"gate-%i",i);
  2544. cmDspArgSetupN(ctx, a, argCnt, baseOutGsId + (i*chCnt), chCnt, label, baseOutGsId + (i*chCnt), 0, 0, kOutDsvFl | kBoolDsvFl, "Output gates");
  2545. }
  2546. cmDspArgSetupNull( a+argCnt); // set terminating arg. flag
  2547. if((p = cmDspInstAlloc(cmDspGroupSel_t,ctx,classPtr,a,instSymId,id,storeSymId,va_cnt,vl1)) == NULL )
  2548. {
  2549. va_end(vl1);
  2550. return NULL;
  2551. }
  2552. p->chCnt = chCnt;
  2553. p->groupCnt = groupCnt;
  2554. p->gsp = cmGroupSelAlloc(ctx->cmProcCtx, NULL, 0, 0, 0 );
  2555. p->baseRmsGsId = baseRmsGsId;
  2556. p->baseOutGsId = baseOutGsId;
  2557. for(i=0; i<chCnt; ++i)
  2558. {
  2559. cmDspSetDefaultBool( ctx, &p->inst, kBaseGateGsId, false, false );
  2560. cmDspSetDefaultDouble(ctx,&p->inst, baseRmsGsId, 0.0, 0.0 );
  2561. }
  2562. for(i=0; i<outCnt; ++i)
  2563. cmDspSetDefaultBool( ctx, &p->inst, baseOutGsId, false, false );
  2564. va_end(vl1);
  2565. return &p->inst;
  2566. }
  2567. cmDspRC_t _cmDspGroupSelFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2568. {
  2569. cmDspGroupSel_t* p = (cmDspGroupSel_t*)inst;
  2570. cmGroupSelFree(&p->gsp);
  2571. return kOkDspRC;
  2572. }
  2573. cmDspRC_t _cmDspGroupSelReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2574. {
  2575. cmDspRC_t rc = kOkDspRC;
  2576. cmDspGroupSel_t* p = (cmDspGroupSel_t*)inst;
  2577. rc = cmDspApplyAllDefaults(ctx,inst);
  2578. cmGroupSelInit(p->gsp,p->chCnt,p->groupCnt,cmDspUInt(&p->inst,kChsPerGroupGsId));
  2579. return rc;
  2580. }
  2581. cmDspRC_t _cmDspGroupSelExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2582. {
  2583. cmDspRC_t rc = kOkDspRC;
  2584. cmDspGroupSel_t* p = (cmDspGroupSel_t*)inst;
  2585. if( cmGroupSelExec(p->gsp) == cmOkRC && p->gsp->updateFl )
  2586. {
  2587. unsigned i,j;
  2588. for(i=0; i<p->groupCnt; ++i)
  2589. {
  2590. cmGroupSelGrp* gp = p->gsp->groupArray + i;
  2591. if( gp->releaseFl )
  2592. {
  2593. for(j=0; j<gp->chIdxCnt; ++j)
  2594. cmDspSetBool(ctx,inst,p->baseOutGsId + (i*p->chCnt) + gp->chIdxArray[j], false);
  2595. }
  2596. if( gp->createFl )
  2597. {
  2598. for(j=0; j<gp->chIdxCnt; ++j)
  2599. cmDspSetBool(ctx,inst,p->baseOutGsId + (i*p->chCnt) + gp->chIdxArray[j], true);
  2600. }
  2601. }
  2602. }
  2603. return rc;
  2604. }
  2605. cmDspRC_t _cmDspGroupSelRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2606. {
  2607. cmDspRC_t rc = kOkDspRC;
  2608. cmDspGroupSel_t* p = (cmDspGroupSel_t*)inst;
  2609. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  2610. {
  2611. if( evt->dstVarId == kChsPerGroupGsId )
  2612. p->gsp->chsPerGroup = cmDspUInt(inst, kChsPerGroupGsId );
  2613. else
  2614. if( kBaseGateGsId <= evt->dstVarId && evt->dstVarId < (kBaseGateGsId + p->chCnt) )
  2615. cmGroupSetChannelGate(p->gsp, evt->dstVarId - kBaseGateGsId, cmDspDouble(inst,evt->dstVarId));
  2616. else
  2617. if( p->baseRmsGsId <= evt->dstVarId && evt->dstVarId < (p->baseRmsGsId + p->chCnt) )
  2618. cmGroupSetChannelRMS(p->gsp, evt->dstVarId - p->baseRmsGsId, cmDspDouble(inst,evt->dstVarId));
  2619. }
  2620. return rc;
  2621. }
  2622. cmDspClass_t* cmGroupSelClassCons( cmDspCtx_t* ctx )
  2623. {
  2624. cmDspClassSetup(&_cmGroupSelDC,ctx,"GroupSel",
  2625. NULL,
  2626. _cmDspGroupSelAlloc,
  2627. _cmDspGroupSelFree,
  2628. _cmDspGroupSelReset,
  2629. _cmDspGroupSelExec,
  2630. _cmDspGroupSelRecv,
  2631. NULL,NULL,
  2632. "Group selector.");
  2633. return &_cmGroupSelDC;
  2634. }
  2635. //------------------------------------------------------------------------------------------------------------
  2636. //)
  2637. //( { label:cmDspNofM file_desc:"Select N channels from a set of M channels based on their current gate states." kw:[sunit] }
  2638. enum
  2639. {
  2640. kInChCntNmId,
  2641. kOutChCntNmId,
  2642. kFadeTimeNmId,
  2643. kBaseGateNmId,
  2644. };
  2645. cmDspClass_t _cmAudioNofM_DC;
  2646. typedef struct
  2647. {
  2648. cmDspInst_t inst;
  2649. unsigned inChCnt;
  2650. unsigned outChCnt;
  2651. cmAudioNofM* nmp;
  2652. unsigned baseInNmId;
  2653. unsigned baseOutNmId;
  2654. unsigned baseGainNmId;
  2655. } cmDspAudioNofM_t;
  2656. cmDspInst_t* _cmDspAudioNofM_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2657. {
  2658. if( va_cnt < 2 )
  2659. {
  2660. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'AudioNofM' constructor must given input and output channel counts.");
  2661. return NULL;
  2662. }
  2663. va_list vl1;
  2664. va_copy(vl1,vl);
  2665. int inChCnt = va_arg(vl,int);
  2666. int outChCnt = va_arg(vl,int);
  2667. unsigned baseInNmId = kBaseGateNmId + inChCnt;
  2668. unsigned baseOutNmId = baseInNmId + inChCnt;
  2669. unsigned baseGainNmId= baseOutNmId + outChCnt;
  2670. unsigned i;
  2671. cmDspAudioNofM_t* p = cmDspInstAllocV(cmDspAudioNofM_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  2672. 1, "ichs", kInChCntNmId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Input channel count.",
  2673. 1, "ochs", kOutChCntNmId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Output channel count.",
  2674. 1, "time", kFadeTimeNmId, 0, 0, kDoubleDsvFl | kOptArgDsvFl | kInDsvFl, "Fade time in milliseconds.",
  2675. inChCnt, "gate", kBaseGateNmId, 0, 0, kBoolDsvFl | kInDsvFl, "Gate inputs.",
  2676. inChCnt, "in", baseInNmId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input",
  2677. outChCnt, "out", baseOutNmId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
  2678. outChCnt, "gain", baseGainNmId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Gain output",
  2679. 0 );
  2680. cmDspSetDefaultDouble( ctx, &p->inst, kFadeTimeNmId, 0.0, 25.0 );
  2681. p->inChCnt = inChCnt;
  2682. p->outChCnt = outChCnt;
  2683. p->nmp = cmAudioNofMAlloc(ctx->cmProcCtx,NULL,0,0,0,0);
  2684. p->baseInNmId = baseInNmId;
  2685. p->baseOutNmId = baseOutNmId;
  2686. p->baseGainNmId = baseGainNmId;
  2687. for(i=0; i<outChCnt; ++i)
  2688. cmDspSetDefaultDouble( ctx, &p->inst, baseGainNmId + i, 0.0, 0.0 );
  2689. va_end(vl1);
  2690. return &p->inst;
  2691. }
  2692. cmDspRC_t _cmDspAudioNofM_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2693. {
  2694. cmDspAudioNofM_t* p = (cmDspAudioNofM_t*)inst;
  2695. cmAudioNofMFree(&p->nmp);
  2696. return kOkDspRC;
  2697. }
  2698. cmDspRC_t _cmDspAudioNofM_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2699. {
  2700. cmDspRC_t rc = kOkDspRC;
  2701. cmDspAudioNofM_t* p = (cmDspAudioNofM_t*)inst;
  2702. unsigned i;
  2703. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  2704. {
  2705. for(i=0; i<p->outChCnt; ++i)
  2706. cmDspZeroAudioBuf(ctx,inst,p->baseOutNmId+i);
  2707. cmAudioNofMInit(p->nmp, cmDspSampleRate(ctx), p->inChCnt, p->outChCnt, cmDspDouble(&p->inst, kFadeTimeNmId ));
  2708. }
  2709. return rc;
  2710. }
  2711. cmDspRC_t _cmDspAudioNofM_Exec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2712. {
  2713. cmDspRC_t rc = kOkDspRC;
  2714. cmDspAudioNofM_t* p = (cmDspAudioNofM_t*)inst;
  2715. unsigned i;
  2716. const cmSample_t* x[ p->inChCnt ];
  2717. cmSample_t* y[ p->outChCnt ];
  2718. unsigned n = 0;
  2719. for(i=0; i<p->inChCnt; ++i)
  2720. {
  2721. if( i==0 )
  2722. n = cmDspAudioBufSmpCount(ctx,inst,p->baseInNmId+i,0);
  2723. else
  2724. { assert( n == cmDspAudioBufSmpCount(ctx,inst,p->baseInNmId+i,0)); }
  2725. x[i] = cmDspAudioBuf(ctx,inst,p->baseInNmId+i,0);
  2726. }
  2727. for(i=0; i<p->outChCnt; ++i)
  2728. {
  2729. y[i] = cmDspAudioBuf(ctx,inst,p->baseOutNmId+i,0);
  2730. assert( n == cmDspAudioBufSmpCount(ctx,inst,p->baseOutNmId+i,0));
  2731. cmVOS_Zero(y[i],n);
  2732. }
  2733. cmAudioNofMExec(p->nmp,x,p->inChCnt,y,p->outChCnt,n);
  2734. for(i=0; i<p->outChCnt; ++i)
  2735. {
  2736. cmAudioNofM_In* ip = p->nmp->outArray[i].list;
  2737. double v = 0;
  2738. for(; ip != NULL; ip=ip->link)
  2739. v += ip->fader->gain;
  2740. cmDspSetDouble(ctx, inst,p->baseGainNmId + i,v );
  2741. }
  2742. return rc;
  2743. }
  2744. cmDspRC_t _cmDspAudioNofM_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2745. {
  2746. cmDspRC_t rc = kOkDspRC;
  2747. cmDspAudioNofM_t* p = (cmDspAudioNofM_t*)inst;
  2748. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  2749. {
  2750. if( kBaseGateNmId <= evt->dstVarId && evt->dstVarId <= kBaseGateNmId + p->inChCnt )
  2751. cmAudioNofMSetChannelGate( p->nmp, evt->dstVarId - kBaseGateNmId, cmDspBool(inst,evt->dstVarId) );
  2752. }
  2753. return rc;
  2754. }
  2755. cmDspClass_t* cmAudioNofMClassCons( cmDspCtx_t* ctx )
  2756. {
  2757. cmDspClassSetup(&_cmAudioNofM_DC,ctx,"AudioNofM",
  2758. NULL,
  2759. _cmDspAudioNofM_Alloc,
  2760. _cmDspAudioNofM_Free,
  2761. _cmDspAudioNofM_Reset,
  2762. _cmDspAudioNofM_Exec,
  2763. _cmDspAudioNofM_Recv,
  2764. NULL,NULL,
  2765. "Audio N of M Switch");
  2766. return &_cmAudioNofM_DC;
  2767. }
  2768. //------------------------------------------------------------------------------------------------------------
  2769. //)
  2770. //( { label:cmDspRingMod file_desc:"Ring modulator." kw:[sunit] }
  2771. enum
  2772. {
  2773. kInChCntRmId,
  2774. kBypassRmId,
  2775. kGainRmId,
  2776. kOutRmId,
  2777. kBaseInRmId
  2778. };
  2779. cmDspClass_t _cmRingModDC;
  2780. typedef struct
  2781. {
  2782. cmDspInst_t inst;
  2783. unsigned inChCnt;
  2784. } cmDspRingMod_t;
  2785. cmDspInst_t* _cmDspRingModAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2786. {
  2787. if( va_cnt < 1 )
  2788. {
  2789. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'RingMod' constructor must given an input channel counts.");
  2790. return NULL;
  2791. }
  2792. va_list vl1;
  2793. va_copy(vl1,vl);
  2794. int inChCnt = va_arg(vl,int);
  2795. cmDspRingMod_t* p = cmDspInstAllocV(cmDspRingMod_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  2796. 1, "ichs", kInChCntRmId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Input channel count.",
  2797. 1, "bypass",kBypassRmId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Bypass enable",
  2798. 1, "gain", kGainRmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Output gain (default:1.0)",
  2799. 1, "out", kOutRmId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
  2800. inChCnt, "in", kBaseInRmId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input",
  2801. 0 );
  2802. cmDspSetDefaultBool( ctx, &p->inst, kBypassRmId, false, false );
  2803. cmDspSetDefaultDouble( ctx, &p->inst, kGainRmId, 0.0, 1.0 );
  2804. p->inChCnt = inChCnt;
  2805. va_end(vl1);
  2806. return &p->inst;
  2807. }
  2808. cmDspRC_t _cmDspRingModReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2809. {
  2810. cmDspRC_t rc = kOkDspRC;
  2811. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  2812. {
  2813. cmDspZeroAudioBuf(ctx,inst,kOutRmId);
  2814. }
  2815. return rc;
  2816. }
  2817. cmDspRC_t _cmDspRingModExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2818. {
  2819. cmDspRC_t rc = kOkDspRC;
  2820. cmDspRingMod_t* p = (cmDspRingMod_t*)inst;
  2821. unsigned i,j;
  2822. cmSample_t* y = cmDspAudioBuf(ctx,inst,kOutRmId, 0);
  2823. const cmSample_t* x0 = cmDspAudioBuf(ctx,inst,kBaseInRmId,0);
  2824. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutRmId,0);
  2825. double gain = cmDspDouble(inst,kGainRmId);
  2826. bool bypassFl = cmDspBool(inst,kBypassRmId);
  2827. for(i=1; i<p->inChCnt; ++i)
  2828. {
  2829. assert( n == cmDspAudioBufSmpCount(ctx,inst,kBaseInRmId+i,0));
  2830. const cmSample_t* x1 = cmDspAudioBuf(ctx,inst,kBaseInRmId+i,0);
  2831. if( bypassFl )
  2832. {
  2833. for(j=0; j<n; ++j)
  2834. y[j] = x0[j] + x1[j];
  2835. }
  2836. else
  2837. {
  2838. for(j=0; j<n; ++j)
  2839. y[j] = x0[j] * x1[j] * gain;
  2840. }
  2841. x0 = y;
  2842. }
  2843. return rc;
  2844. }
  2845. cmDspRC_t _cmDspRingModRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2846. {
  2847. return cmDspSetEvent(ctx,inst,evt);
  2848. }
  2849. cmDspClass_t* cmRingModClassCons( cmDspCtx_t* ctx )
  2850. {
  2851. cmDspClassSetup(&_cmRingModDC,ctx,"RingMod",
  2852. NULL,
  2853. _cmDspRingModAlloc,
  2854. NULL,
  2855. _cmDspRingModReset,
  2856. _cmDspRingModExec,
  2857. _cmDspRingModRecv,
  2858. NULL,NULL,
  2859. "Ring modulator");
  2860. return &_cmRingModDC;
  2861. }
  2862. //------------------------------------------------------------------------------------------------------------
  2863. //)
  2864. //( { label:cmDspMsgDelay file_desc:"Delay an arbitrary value." kw:[sunit] }
  2865. enum
  2866. {
  2867. kMaxCntMdId,
  2868. kDelayMdId,
  2869. kClearMdId,
  2870. kInMdId,
  2871. kOutMdId,
  2872. };
  2873. cmDspClass_t _cmMsgDelayDC;
  2874. typedef struct cmDspMsgDelayEle_str
  2875. {
  2876. unsigned outTimeSmp;
  2877. cmDspValue_t value;
  2878. struct cmDspMsgDelayEle_str* link;
  2879. } cmDspMsgDelayEle_t;
  2880. typedef struct
  2881. {
  2882. cmDspInst_t inst;
  2883. unsigned maxCnt;
  2884. cmDspMsgDelayEle_t* array; // array[maxCnt];
  2885. cmDspMsgDelayEle_t* avail;
  2886. cmDspMsgDelayEle_t* active;
  2887. } cmDspMsgDelay_t;
  2888. cmDspInst_t* _cmDspMsgDelayAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  2889. {
  2890. cmDspMsgDelay_t* p = cmDspInstAllocV(cmDspMsgDelay_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  2891. 1, "maxcnt", kMaxCntMdId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Maximum count of elements in the delay",
  2892. 1, "delay", kDelayMdId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Delay time in millisecond.",
  2893. 1, "clear", kClearMdId, 0, 0, kInDsvFl | kTypeDsvMask, "Clear delay",
  2894. 1, "in", kInMdId, 0, 0, kInDsvFl | kUIntDsvFl, "Msg input",
  2895. 1, "out", kOutMdId, 0, 0, kOutDsvFl | kUIntDsvFl, "Msg output",
  2896. 0 );
  2897. if( p == NULL )
  2898. return NULL;
  2899. cmDspSetDefaultDouble( ctx, &p->inst, kDelayMdId, 0.0, 0.0 );
  2900. cmDspSetDefaultBool( ctx, &p->inst, kOutMdId, false, false );
  2901. p->maxCnt = cmDspUInt(&p->inst,kMaxCntMdId);
  2902. p->array = cmMemAllocZ(cmDspMsgDelayEle_t, p->maxCnt );
  2903. return &p->inst;
  2904. }
  2905. cmDspRC_t _cmDspMsgDelayFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2906. {
  2907. cmDspMsgDelay_t* p = (cmDspMsgDelay_t*)inst;
  2908. cmMemFree(p->array);
  2909. return kOkDspRC;
  2910. }
  2911. // insert a value in the delay list
  2912. cmDspRC_t _cmDspMsgDelayInsert( cmDspCtx_t* ctx, cmDspMsgDelay_t* p, unsigned delayTimeSmp, const cmDspValue_t* valPtr )
  2913. {
  2914. cmDspRC_t rc = kOkDspRC;
  2915. // protect against pre-reset calls
  2916. if( p->avail == NULL && p->active == NULL )
  2917. return kOkDspRC;
  2918. // if there are no available delay elements
  2919. if( p->avail == NULL )
  2920. return cmDspInstErr(ctx,&p->inst,kInvalidStateDspRC,"The message delay has exhausted it's internal message store.");
  2921. // we only do the simplest kind of copying to avoid allocating memory
  2922. // TODO: fix this
  2923. if( cmDsvIsMtx(valPtr) || cmIsFlag(valPtr->flags,kProxyDsvFl))
  2924. return cmDspInstErr(ctx,&p->inst,kInvalidArgDspRC,"The message delay cannot yet store matrix or proxy types.");
  2925. // get a pointer to the next available element
  2926. cmDspMsgDelayEle_t* np = p->avail;
  2927. // remove the new ele from the avail list
  2928. p->avail = np->link;
  2929. // calc the new ele's exec time
  2930. np->outTimeSmp = ctx->cycleCnt * cmDspSamplesPerCycle(ctx) + delayTimeSmp;
  2931. // copy the msg value into the delay line element
  2932. // TODO: this should be a real copy that supports all types
  2933. np->value = *valPtr;
  2934. cmDspMsgDelayEle_t* ep = p->active;
  2935. cmDspMsgDelayEle_t* pp = NULL;
  2936. // if the active list is empty ...
  2937. if( ep == NULL )
  2938. {
  2939. // ... make the avail element the first on the list
  2940. p->active = np;
  2941. np->link = NULL;
  2942. }
  2943. else
  2944. {
  2945. // iterate through the list and find the active links which
  2946. // the new ele falls between based on its execution time
  2947. while(ep != NULL )
  2948. {
  2949. // ep's exec time is greater than the new ele's exec time
  2950. if( ep->outTimeSmp > np->outTimeSmp )
  2951. {
  2952. // insert the new ele in the active list before 'ep'
  2953. if( pp == NULL )
  2954. {
  2955. np->link = p->active;
  2956. p->active = np;
  2957. }
  2958. else
  2959. {
  2960. np->link = pp->link;
  2961. pp->link = np;
  2962. }
  2963. break;
  2964. }
  2965. pp = ep;
  2966. ep = ep->link;
  2967. }
  2968. // if the new element is last on the list
  2969. if( ep == NULL )
  2970. {
  2971. assert(pp != NULL && pp->link == NULL);
  2972. pp->link = np;
  2973. np->link = NULL;
  2974. }
  2975. }
  2976. return rc;
  2977. }
  2978. void _cmDspMsgDelayClear(cmDspInst_t* inst )
  2979. {
  2980. unsigned i;
  2981. cmDspMsgDelay_t* p = (cmDspMsgDelay_t*)inst;
  2982. unsigned maxCnt = cmDspUInt(inst,kMaxCntMdId);
  2983. p->active = NULL;
  2984. p->avail = NULL;
  2985. // put all ele's on the available list
  2986. for(i=0; i<maxCnt; ++i)
  2987. {
  2988. p->array[i].link = p->avail;
  2989. p->avail = p->array + i;
  2990. }
  2991. }
  2992. cmDspRC_t _cmDspMsgDelayReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  2993. {
  2994. cmDspRC_t rc = kOkDspRC;
  2995. if((rc = cmDspApplyDefault(ctx,inst,kDelayMdId)) == kOkDspRC )
  2996. {
  2997. _cmDspMsgDelayClear(inst);
  2998. }
  2999. return rc;
  3000. }
  3001. cmDspRC_t _cmDspMsgDelayExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* e )
  3002. {
  3003. cmDspRC_t rc = kOkDspRC;
  3004. cmDspMsgDelay_t* p = (cmDspMsgDelay_t*)inst;
  3005. unsigned framesPerCycle = cmDspSamplesPerCycle(ctx);
  3006. unsigned begTimeSmp = ctx->cycleCnt * framesPerCycle;
  3007. unsigned endTimeSmp = begTimeSmp + framesPerCycle;
  3008. while( p->active != NULL )
  3009. {
  3010. if( p->active->outTimeSmp >= endTimeSmp )
  3011. break;
  3012. cmDspMsgDelayEle_t* ep = p->active;
  3013. // remove the element from the active list and place it on the available list.
  3014. p->active = p->active->link; // advance the active list
  3015. ep->link = p->avail; // put the cur. element on the avail list
  3016. p->avail = ep; //
  3017. // output the element value
  3018. if((rc = cmDspValueSet(ctx,inst,kOutMdId,&ep->value,0)) != kOkDspRC )
  3019. return cmDspInstErr(ctx,inst,rc,"Message delay output failed.");
  3020. }
  3021. return rc;
  3022. }
  3023. cmDspRC_t _cmDspMsgDelayRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3024. {
  3025. cmDspRC_t rc = kOkDspRC;
  3026. cmDspMsgDelay_t* p = (cmDspMsgDelay_t*)inst;
  3027. switch( evt->dstVarId )
  3028. {
  3029. case kDelayMdId:
  3030. rc = cmDspSetEvent(ctx,inst,evt);
  3031. break;
  3032. case kClearMdId:
  3033. _cmDspMsgDelayClear(inst);
  3034. break;
  3035. case kInMdId:
  3036. {
  3037. unsigned delayTimeSmp = floor(cmDspDouble(&p->inst,kDelayMdId) * cmDspSampleRate(ctx) / 1000.0);
  3038. rc = _cmDspMsgDelayInsert(ctx,p,delayTimeSmp,evt->valuePtr);
  3039. }
  3040. break;
  3041. }
  3042. return rc;
  3043. }
  3044. cmDspClass_t* cmMsgDelayClassCons( cmDspCtx_t* ctx )
  3045. {
  3046. cmDspClassSetup(&_cmMsgDelayDC,ctx,"MsgDelay",
  3047. NULL,
  3048. _cmDspMsgDelayAlloc,
  3049. _cmDspMsgDelayFree,
  3050. _cmDspMsgDelayReset,
  3051. _cmDspMsgDelayExec,
  3052. _cmDspMsgDelayRecv,
  3053. NULL,NULL,
  3054. "Message Delay");
  3055. return &_cmMsgDelayDC;
  3056. }
  3057. //------------------------------------------------------------------------------------------------------------
  3058. //)
  3059. //( { label:cmDspLine file_desc:"Programmable line generator." kw:[sunit] }
  3060. enum
  3061. {
  3062. kBegLnId,
  3063. kEndLnId,
  3064. kDurLnId,
  3065. kCmdLnId,
  3066. kRateLnId,
  3067. kOutLnId,
  3068. };
  3069. cmDspClass_t _cmLineDC;
  3070. typedef struct cmDspLineEle_str
  3071. {
  3072. unsigned outTimeSmp;
  3073. cmDspValue_t value;
  3074. struct cmDspLineEle_str* link;
  3075. } cmDspLineEle_t;
  3076. typedef struct
  3077. {
  3078. cmDspInst_t inst;
  3079. unsigned onSymId;
  3080. unsigned offSymId;
  3081. unsigned resetSymId;
  3082. unsigned curSmpIdx;
  3083. double phase;
  3084. bool onFl;
  3085. } cmDspLine_t;
  3086. cmDspInst_t* _cmDspLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3087. {
  3088. cmDspLine_t* p = cmDspInstAllocV(cmDspLine_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3089. 1, "beg", kBegLnId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Begin value.",
  3090. 1, "end", kEndLnId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "End value.",
  3091. 1, "dur", kDurLnId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Duration (ms)",
  3092. 1, "cmd", kCmdLnId, 0, 0, kInDsvFl | kSymDsvFl | kOptArgDsvFl, "Command: on | off | reset",
  3093. 1, "rate", kRateLnId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Output messages per second",
  3094. 1, "out", kOutLnId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output",
  3095. 0 );
  3096. if( p == NULL )
  3097. return NULL;
  3098. cmDspSetDefaultDouble( ctx, &p->inst, kOutLnId, 0.0, cmDspDefaultDouble(&p->inst,kBegLnId) );
  3099. cmDspSetDefaultDouble( ctx, &p->inst, kRateLnId, 0.0, 0.0 );
  3100. p->onSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"on");
  3101. p->offSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"off");
  3102. p->resetSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"reset");
  3103. return &p->inst;
  3104. }
  3105. cmDspRC_t _cmDspLineFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3106. {
  3107. return kOkDspRC;
  3108. }
  3109. cmDspRC_t _cmDspLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3110. {
  3111. cmDspLine_t* p = (cmDspLine_t*)inst;
  3112. p->curSmpIdx = 0;
  3113. p->onFl = false;
  3114. p->phase = 0;
  3115. return cmDspApplyAllDefaults(ctx,inst);
  3116. }
  3117. cmDspRC_t _cmDspLineExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* e )
  3118. {
  3119. cmDspRC_t rc = kOkDspRC;
  3120. cmDspLine_t* p = (cmDspLine_t*)inst;
  3121. if( p->onFl == false )
  3122. return kOkDspRC;
  3123. unsigned sPc = cmDspSamplesPerCycle(ctx);
  3124. double beg = cmDspDouble(inst,kBegLnId);
  3125. double end = cmDspDouble(inst,kEndLnId);
  3126. double rate = cmDspDouble(inst,kRateLnId);
  3127. double ms = cmDspDouble(inst,kDurLnId);
  3128. double durSmpCnt = floor(ms * cmDspSampleRate(ctx) / 1000);
  3129. double out = beg + (end - beg) * p->curSmpIdx / durSmpCnt;
  3130. double phsMax = rate==0 ? sPc : cmDspSampleRate(ctx) / rate;
  3131. // we can never output with a period shorter than
  3132. // the length of one audio buffer
  3133. if( phsMax < sPc )
  3134. phsMax = sPc;
  3135. if( beg < end )
  3136. {
  3137. if( out >= end )
  3138. {
  3139. out = end;
  3140. p->onFl = false;
  3141. }
  3142. }
  3143. else
  3144. {
  3145. if( out <= end )
  3146. {
  3147. out = end;
  3148. p->onFl = false;
  3149. }
  3150. }
  3151. p->phase += sPc;
  3152. if( p->phase >= sPc )
  3153. {
  3154. cmDspSetDouble(ctx,inst,kOutLnId,out);
  3155. p->phase -= sPc;
  3156. }
  3157. p->curSmpIdx += sPc;
  3158. return rc;
  3159. }
  3160. cmDspRC_t _cmDspLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3161. {
  3162. cmDspRC_t rc = kOkDspRC;
  3163. cmDspLine_t* p = (cmDspLine_t*)inst;
  3164. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  3165. {
  3166. switch( evt->dstVarId )
  3167. {
  3168. case kCmdLnId:
  3169. {
  3170. unsigned symId = cmDspSymbol(inst,kCmdLnId);
  3171. if( symId == p->onSymId )
  3172. p->onFl = true;
  3173. else
  3174. if( symId == p->offSymId )
  3175. p->onFl = false;
  3176. else
  3177. if( symId == p->resetSymId )
  3178. {
  3179. p->curSmpIdx = 0;
  3180. p->onFl = true;
  3181. }
  3182. }
  3183. break;
  3184. }
  3185. }
  3186. return rc;
  3187. }
  3188. cmDspClass_t* cmLineClassCons( cmDspCtx_t* ctx )
  3189. {
  3190. cmDspClassSetup(&_cmLineDC,ctx,"Line",
  3191. NULL,
  3192. _cmDspLineAlloc,
  3193. _cmDspLineFree,
  3194. _cmDspLineReset,
  3195. _cmDspLineExec,
  3196. _cmDspLineRecv,
  3197. NULL,NULL,
  3198. "Line");
  3199. return &_cmLineDC;
  3200. }
  3201. //------------------------------------------------------------------------------------------------------------
  3202. //)
  3203. //( { label:cmDspAdsr file_desc:"ADSR envelope generator." kw:[sunit] }
  3204. enum
  3205. {
  3206. kTrigModeAdId,
  3207. kMinLvlAdId,
  3208. kDlyMsAdId,
  3209. kAtkMsAdId,
  3210. kAtkLvlAdId,
  3211. kDcyMsAdId,
  3212. kSusLvlAdId,
  3213. kSusMsAdId,
  3214. kRlsMsAdId,
  3215. kTScaleAdId,
  3216. kAScaleAdId,
  3217. kGateAdId,
  3218. kRmsAdId,
  3219. kOutAdId,
  3220. kCmdAdId
  3221. };
  3222. cmDspClass_t _cmAdsrDC;
  3223. typedef struct
  3224. {
  3225. cmDspInst_t inst;
  3226. cmAdsr* p;
  3227. } cmDspAdsr_t;
  3228. cmDspInst_t* _cmDspAdsrAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3229. {
  3230. cmDspAdsr_t* p = cmDspInstAllocV(cmDspAdsr_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3231. 1, "trig", kTrigModeAdId, 0, 0, kBoolDsvFl | kInDsvFl | kOptArgDsvFl, "Trigger mode (offset ignored).",
  3232. 1, "min", kMinLvlAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Minimum level (dflt:0.0).",
  3233. 1, "dly", kDlyMsAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Delay milliseconds.",
  3234. 1, "atk", kAtkMsAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Attack milliseconds.",
  3235. 1, "alvl", kAtkLvlAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Attack Level.",
  3236. 1, "dcy", kDcyMsAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Decay milliseconds.",
  3237. 1, "sus", kSusLvlAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Sustain Level.",
  3238. 1, "hold", kSusMsAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Sustain Ms (trig mode only).",
  3239. 1, "rls", kRlsMsAdId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl, "Release milliseconds.",
  3240. 1, "tscale",kTScaleAdId, 0, 0, kDoubleDsvFl | kInDsvFl, "Time scale.",
  3241. 1, "ascale",kAScaleAdId, 0, 0, kDoubleDsvFl | kInDsvFl, "Amplitude scale.",
  3242. 1, "gate", kGateAdId, 0, 0, kBoolDsvFl | kInDsvFl, "Gate input.",
  3243. 1, "rms", kRmsAdId, 0, 0, kDoubleDsvFl | kInDsvFl, "RMS input.",
  3244. 1, "out", kOutAdId, 0, 0, kDoubleDsvFl | kOutDsvFl, "Level output.",
  3245. 1, "cmd", kCmdAdId, 0, 0, kSymDsvFl | kInDsvFl, "Command input.",
  3246. 0 );
  3247. cmDspSetDefaultBool( ctx, &p->inst, kTrigModeAdId, false, false );
  3248. cmDspSetDefaultDouble( ctx, &p->inst, kMinLvlAdId, 0.0, 0.0 );
  3249. cmDspSetDefaultDouble( ctx, &p->inst, kDlyMsAdId, 0.0, 0.0 );
  3250. cmDspSetDefaultDouble( ctx, &p->inst, kAtkMsAdId, 0.0, 5.0 );
  3251. cmDspSetDefaultDouble( ctx, &p->inst, kAtkLvlAdId, 0.0, 1.0 );
  3252. cmDspSetDefaultDouble( ctx, &p->inst, kDcyMsAdId, 0.0, 10.0 );
  3253. cmDspSetDefaultDouble( ctx, &p->inst, kSusLvlAdId, 0.0, 0.8 );
  3254. cmDspSetDefaultDouble( ctx, &p->inst, kSusMsAdId, 0.0, 50.0);
  3255. cmDspSetDefaultDouble( ctx, &p->inst, kRlsMsAdId, 0.0, 20.0 );
  3256. cmDspSetDefaultDouble( ctx, &p->inst, kTScaleAdId, 0.0, 1.0 );
  3257. cmDspSetDefaultDouble( ctx, &p->inst, kAScaleAdId, 0.0, 1.0 );
  3258. cmDspSetDefaultBool( ctx, &p->inst, kGateAdId, false,false);
  3259. cmDspSetDefaultDouble( ctx, &p->inst, kRmsAdId, 0.0, 0.0);
  3260. cmDspSetDefaultDouble( ctx, &p->inst, kOutAdId, 0.0, cmDspDouble(&p->inst,kMinLvlAdId));
  3261. p->p = cmAdsrAlloc(ctx->cmProcCtx,NULL,false,0,0,0,0,0,0,0,0,0);
  3262. return &p->inst;
  3263. }
  3264. cmDspRC_t _cmDspAdsrFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3265. {
  3266. cmDspAdsr_t* p = (cmDspAdsr_t*)inst;
  3267. cmAdsrFree(&p->p);
  3268. return kOkDspRC;
  3269. }
  3270. cmDspRC_t _cmDspAdsrReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3271. {
  3272. cmDspRC_t rc = kOkDspRC;
  3273. cmDspAdsr_t* p = (cmDspAdsr_t*)inst;
  3274. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  3275. {
  3276. bool trigFl= cmDspBool( inst, kTrigModeAdId );
  3277. cmReal_t minL = cmDspDouble( inst, kMinLvlAdId );
  3278. cmReal_t dlyMs = cmDspDouble( inst, kDlyMsAdId );
  3279. cmReal_t atkMs = cmDspDouble( inst, kAtkMsAdId );
  3280. cmReal_t atkL = cmDspDouble( inst, kAtkLvlAdId );
  3281. cmReal_t dcyMs = cmDspDouble( inst, kDcyMsAdId );
  3282. cmReal_t susMs = cmDspDouble( inst, kSusMsAdId );
  3283. cmReal_t susL = cmDspDouble( inst, kSusLvlAdId );
  3284. cmReal_t rlsMs = cmDspDouble( inst, kRlsMsAdId );
  3285. cmAdsrInit( p->p, cmDspSampleRate(ctx), trigFl, minL, dlyMs, atkMs, atkL, dcyMs, susMs, susL, rlsMs );
  3286. }
  3287. return rc;
  3288. }
  3289. cmDspRC_t _cmDspAdsrExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3290. {
  3291. cmDspRC_t rc = kOkDspRC;
  3292. cmDspAdsr_t* p = (cmDspAdsr_t*)inst;
  3293. bool gateFl = cmDspBool( inst, kGateAdId );
  3294. //double rms = cmDspDouble(inst,kRmsAdId);
  3295. double tscale = cmDspDouble(inst,kTScaleAdId);
  3296. double ascale = cmDspDouble(inst,kAScaleAdId);
  3297. //
  3298. // HACK HACK HACK HACK
  3299. // HACK HACK HACK HACK
  3300. // HACK HACK HACK HACK see the accompanying hack in cmProc3.c cmAdsrExec()
  3301. // HACK HACK HACK HACK
  3302. // HACK HACK HACK HACK
  3303. //
  3304. // double db = rms<0.00001 ? -100.0 : 20.0*log10(rms);
  3305. // double dbMax = -15.0;
  3306. // double dbMin = -58.0;
  3307. //
  3308. // db = cmMin(dbMax,cmMax(dbMin,db));
  3309. // double scale = (db - dbMin) / (dbMax-dbMin);
  3310. cmReal_t out = cmAdsrExec( p->p, cmDspSamplesPerCycle(ctx), gateFl, tscale, ascale );
  3311. rc = cmDspSetDouble( ctx, inst, kOutAdId, out );
  3312. return rc;
  3313. }
  3314. cmDspRC_t _cmDspAdsrRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3315. {
  3316. cmDspRC_t rc = kOkDspRC;
  3317. cmDspAdsr_t* p = (cmDspAdsr_t*)inst;
  3318. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  3319. return rc;
  3320. if( evt->dstVarId == kCmdAdId )
  3321. {
  3322. cmAdsrReport(p->p,ctx->rpt);
  3323. return rc;
  3324. }
  3325. cmReal_t v = cmDspDouble(inst,evt->dstVarId);
  3326. switch( evt->dstVarId )
  3327. {
  3328. case kTrigModeAdId:
  3329. p->p->trigModeFl = cmDspBool(inst, kTrigModeAdId);
  3330. break;
  3331. case kMinLvlAdId:
  3332. cmAdsrSetLevel(p->p, v, kDlyAdsrId );
  3333. break;
  3334. case kDlyMsAdId:
  3335. cmAdsrSetTime(p->p, v, kDlyAdsrId );
  3336. break;
  3337. case kAtkMsAdId:
  3338. cmAdsrSetTime(p->p, v, kAtkAdsrId );
  3339. break;
  3340. case kAtkLvlAdId:
  3341. cmAdsrSetLevel(p->p, v, kAtkAdsrId );
  3342. break;
  3343. case kDcyMsAdId:
  3344. cmAdsrSetTime(p->p, v, kDcyAdsrId );
  3345. break;
  3346. case kSusMsAdId:
  3347. cmAdsrSetTime(p->p, v, kSusAdsrId );
  3348. break;
  3349. case kSusLvlAdId:
  3350. cmAdsrSetLevel(p->p, v, kSusAdsrId );
  3351. break;
  3352. case kRlsMsAdId:
  3353. cmAdsrSetTime(p->p, v, kRlsAdsrId );
  3354. break;
  3355. }
  3356. return rc;
  3357. }
  3358. cmDspClass_t* cmAdsrClassCons( cmDspCtx_t* ctx )
  3359. {
  3360. cmDspClassSetup(&_cmAdsrDC,ctx,"Adsr",
  3361. NULL,
  3362. _cmDspAdsrAlloc,
  3363. _cmDspAdsrFree,
  3364. _cmDspAdsrReset,
  3365. _cmDspAdsrExec,
  3366. _cmDspAdsrRecv,
  3367. NULL,NULL,
  3368. "ADSR Envelope Generator");
  3369. return &_cmAdsrDC;
  3370. }
  3371. //------------------------------------------------------------------------------------------------------------
  3372. //)
  3373. //( { label:cmDspAdsr file_desc:"Audio dynamics compressor." kw:[sunit] }
  3374. enum
  3375. {
  3376. kBypassCmId,
  3377. kThreshDbCmId,
  3378. kRatioCmId,
  3379. kAtkMsCmId,
  3380. kRlsMsCmId,
  3381. kInGainCmId,
  3382. kOutGainCmId,
  3383. kWndMsCmId,
  3384. kMaxWndMsCmId,
  3385. kInCmId,
  3386. kOutCmId,
  3387. kEnvCmId
  3388. };
  3389. cmDspClass_t _cmCompressorDC;
  3390. typedef struct
  3391. {
  3392. cmDspInst_t inst;
  3393. cmCompressor* p;
  3394. } cmDspCompressor_t;
  3395. cmDspInst_t* _cmDspCompressorAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3396. {
  3397. cmDspCompressor_t* p = cmDspInstAllocV(cmDspCompressor_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3398. 1, "bypass",kBypassCmId, 0, 0, kInDsvFl | kBoolDsvFl | kReqArgDsvFl, "Bypass enable",
  3399. 1, "thr", kThreshDbCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Threshold in dB.",
  3400. 1, "ratio", kRatioCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Ratio numerator.",
  3401. 1, "atk", kAtkMsCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Attack milliseconds",
  3402. 1, "rls", kRlsMsCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Release milliseconds",
  3403. 1, "igain", kInGainCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Input gain.",
  3404. 1, "ogain", kOutGainCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Makeup Gain",
  3405. 1, "wnd", kWndMsCmId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "RMS window milliseconds.",
  3406. 1, "maxwnd",kMaxWndMsCmId, 0, 0, kDoubleDsvFl | kOptArgDsvFl, "Max. RMS window milliseconds.",
  3407. 1, "in", kInCmId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input",
  3408. 1, "out", kOutCmId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
  3409. 1, "env", kEnvCmId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Envelope out",
  3410. 0 );
  3411. p->p = cmCompressorAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false );
  3412. cmDspSetDefaultBool( ctx, &p->inst, kBypassCmId, false, false );
  3413. cmDspSetDefaultDouble( ctx, &p->inst, kAtkMsCmId, 0.0, 20.0 );
  3414. cmDspSetDefaultDouble( ctx, &p->inst, kRlsMsCmId, 0.0, 20.0 );
  3415. cmDspSetDefaultDouble( ctx, &p->inst, kInGainCmId, 0.0, 1.0 );
  3416. cmDspSetDefaultDouble( ctx, &p->inst, kOutGainCmId, 0.0, 1.0 );
  3417. cmDspSetDefaultDouble( ctx, &p->inst, kWndMsCmId, 0.0, 200.0);
  3418. cmDspSetDefaultDouble( ctx, &p->inst, kMaxWndMsCmId, 0.0, 1000.0);
  3419. cmDspSetDefaultDouble( ctx, &p->inst, kEnvCmId, 0.0, 0.0 );
  3420. return &p->inst;
  3421. }
  3422. cmDspRC_t _cmDspCompressorFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3423. {
  3424. cmDspCompressor_t* p = (cmDspCompressor_t*)inst;
  3425. cmCompressorFree(&p->p);
  3426. return kOkDspRC;
  3427. }
  3428. cmDspRC_t _cmDspCompressorReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3429. {
  3430. cmDspRC_t rc = kOkDspRC;
  3431. cmDspCompressor_t* p = (cmDspCompressor_t*)inst;
  3432. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  3433. {
  3434. cmDspZeroAudioBuf(ctx,inst,kOutCmId);
  3435. cmReal_t threshDb = cmDspDouble(inst, kThreshDbCmId );
  3436. cmReal_t ratio = cmDspDouble(inst, kRatioCmId );
  3437. cmReal_t atkMs = cmDspDouble(inst, kAtkMsCmId );
  3438. cmReal_t rlsMs = cmDspDouble(inst, kRlsMsCmId );
  3439. cmReal_t inGain = cmDspDouble(inst, kInGainCmId );
  3440. cmReal_t outGain = cmDspDouble(inst, kOutGainCmId );
  3441. cmReal_t wndMs = cmDspDouble(inst, kWndMsCmId );
  3442. cmReal_t maxWndMs = cmDspDouble(inst, kMaxWndMsCmId);
  3443. bool bypassFl = cmDspBool( inst, kBypassCmId );
  3444. cmCompressorInit(p->p,cmDspSampleRate(ctx),cmDspSamplesPerCycle(ctx), inGain, maxWndMs, wndMs, threshDb, ratio, atkMs, rlsMs, outGain, bypassFl );
  3445. }
  3446. return rc;
  3447. }
  3448. cmDspRC_t _cmDspCompressorExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3449. {
  3450. cmDspRC_t rc = kOkDspRC;
  3451. cmDspCompressor_t* p = (cmDspCompressor_t*)inst;
  3452. cmSample_t* y = cmDspAudioBuf(ctx,inst,kOutCmId, 0);
  3453. const cmSample_t* x = cmDspAudioBuf(ctx,inst,kInCmId,0);
  3454. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutCmId,0);
  3455. if( x != NULL )
  3456. {
  3457. cmCompressorExec(p->p,x,y,n);
  3458. rc = cmDspSetDouble( ctx, inst, kEnvCmId, p->p->gain );
  3459. }
  3460. return rc;
  3461. }
  3462. cmDspRC_t _cmDspCompressorRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3463. {
  3464. cmDspRC_t rc;
  3465. cmDspCompressor_t* p = (cmDspCompressor_t*)inst;
  3466. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  3467. return rc;
  3468. cmReal_t v = cmDspDouble(inst,evt->dstVarId);
  3469. switch( evt->dstVarId )
  3470. {
  3471. case kThreshDbCmId:
  3472. cmCompressorSetThreshDb(p->p,v);
  3473. break;
  3474. case kRatioCmId:
  3475. p->p->ratio_num = v;
  3476. break;
  3477. case kAtkMsCmId:
  3478. cmCompressorSetAttackMs(p->p,v);
  3479. break;
  3480. case kRlsMsCmId:
  3481. cmCompressorSetReleaseMs(p->p,v);
  3482. break;
  3483. case kInGainCmId:
  3484. p->p->inGain = v;
  3485. break;
  3486. case kOutGainCmId:
  3487. p->p->outGain = v;
  3488. break;
  3489. case kWndMsCmId:
  3490. cmCompressorSetRmsWndMs(p->p,v);
  3491. break;
  3492. case kBypassCmId:
  3493. p->p->bypassFl = cmDspBool(inst,kBypassCmId);
  3494. break;
  3495. }
  3496. return rc;
  3497. }
  3498. cmDspClass_t* cmCompressorClassCons( cmDspCtx_t* ctx )
  3499. {
  3500. cmDspClassSetup(&_cmCompressorDC,ctx,"Compressor",
  3501. NULL,
  3502. _cmDspCompressorAlloc,
  3503. _cmDspCompressorFree,
  3504. _cmDspCompressorReset,
  3505. _cmDspCompressorExec,
  3506. _cmDspCompressorRecv,
  3507. NULL,NULL,
  3508. "Compressor");
  3509. return &_cmCompressorDC;
  3510. }
  3511. //------------------------------------------------------------------------------------------------------------
  3512. //)
  3513. //( { label:cmDspBiquad file_desc:"Programmable Biquad EQ filter." kw:[sunit] }
  3514. enum
  3515. {
  3516. kBypassBqId,
  3517. kModeBqId,
  3518. kF0HzBqId,
  3519. kQBqId,
  3520. kGainDbBqId,
  3521. kInBqId,
  3522. kOutBqId
  3523. };
  3524. cmDspClass_t _cmBiQuadEqDC;
  3525. typedef struct
  3526. {
  3527. const cmChar_t* label;
  3528. unsigned mode;
  3529. unsigned symbol;
  3530. } cmDspBiQuadMap_t;
  3531. cmDspBiQuadMap_t _cmDspBiQuadMap[] =
  3532. {
  3533. {"LP", kLpfBqId, cmInvalidId },
  3534. {"HP", kHpFBqId, cmInvalidId },
  3535. {"BP", kBpfBqId, cmInvalidId },
  3536. {"Notch", kNotchBqId, cmInvalidId },
  3537. {"AP", kAllpassBqId, cmInvalidId },
  3538. {"Peak", kPeakBqId, cmInvalidId },
  3539. {"LSh", kLowShelfBqId, cmInvalidId },
  3540. {"HSh", kHighShelfBqId, cmInvalidId },
  3541. { NULL, cmInvalidId, cmInvalidId }
  3542. };
  3543. typedef struct
  3544. {
  3545. cmDspInst_t inst;
  3546. cmBiQuadEq* p;
  3547. } cmDspBiQuadEq_t;
  3548. cmDspInst_t* _cmDspBiQuadEqAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3549. {
  3550. cmDspBiQuadEq_t* p = cmDspInstAllocV(cmDspBiQuadEq_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3551. 1, "bypass",kBypassBqId, 0, 0, kInDsvFl | kBoolDsvFl | kReqArgDsvFl, "Bypass enable.",
  3552. 1, "mode", kModeBqId, 0, 0, kInDsvFl | kSymDsvFl | kReqArgDsvFl, "Mode Symbol: LP|HP|BP|AP|Notch|Pk|LSh|HSh.",
  3553. 1, "f0", kF0HzBqId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Center or edge frequecy in Hz.",
  3554. 1, "Q", kQBqId, 0, 0, kInDsvFl | kDoubleDsvFl | kReqArgDsvFl, "Q",
  3555. 1, "gain", kGainDbBqId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Gain Db (Pk,LSh,Hsh only)",
  3556. 1, "in", kInBqId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input",
  3557. 1, "out", kOutBqId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
  3558. 0 );
  3559. cmDspSetDefaultDouble( ctx, &p->inst, kGainDbBqId, 0.0, 1.0 );
  3560. p->p = cmBiQuadEqAlloc(ctx->cmProcCtx,NULL,0,0,0,0,0,false);
  3561. // register the filter mode symbols
  3562. unsigned i;
  3563. for(i=0; _cmDspBiQuadMap[i].label != NULL; ++i)
  3564. if( _cmDspBiQuadMap[i].symbol == cmInvalidId )
  3565. _cmDspBiQuadMap[i].symbol = cmSymTblRegisterStaticSymbol(ctx->stH,_cmDspBiQuadMap[i].label);
  3566. return &p->inst;
  3567. }
  3568. cmDspRC_t _cmDspBiQuadEqFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3569. {
  3570. cmDspBiQuadEq_t* p = (cmDspBiQuadEq_t*)inst;
  3571. cmBiQuadEqFree(&p->p);
  3572. return kOkDspRC;
  3573. }
  3574. unsigned _cmDspBiQuadEqModeId( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned modeSymId )
  3575. {
  3576. unsigned i;
  3577. for(i=0; _cmDspBiQuadMap[i].label!=NULL; ++i)
  3578. if( _cmDspBiQuadMap[i].symbol == modeSymId )
  3579. return _cmDspBiQuadMap[i].mode;
  3580. cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The mode string '%s' is not valid.",cmStringNullGuard(cmSymTblLabel(ctx->stH,modeSymId)));
  3581. return cmInvalidId;
  3582. }
  3583. cmDspRC_t _cmDspBiQuadEqReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3584. {
  3585. cmDspRC_t rc = kOkDspRC;
  3586. cmDspBiQuadEq_t* p = (cmDspBiQuadEq_t*)inst;
  3587. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  3588. {
  3589. cmDspZeroAudioBuf(ctx,inst,kOutBqId);
  3590. unsigned modeSymId = cmDspSymbol(inst, kModeBqId );
  3591. cmReal_t f0Hz = cmDspDouble(inst, kF0HzBqId );
  3592. cmReal_t Q = cmDspDouble(inst, kQBqId );
  3593. cmReal_t gainDb = cmDspDouble(inst, kGainDbBqId );
  3594. unsigned mode = _cmDspBiQuadEqModeId(ctx,inst,modeSymId );
  3595. bool bypassFl = cmDspBool(inst, kBypassBqId );
  3596. if( mode != cmInvalidId )
  3597. cmBiQuadEqInit(p->p, cmDspSampleRate(ctx), mode, f0Hz, Q, gainDb, bypassFl );
  3598. }
  3599. return rc;
  3600. }
  3601. cmDspRC_t _cmDspBiQuadEqExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3602. {
  3603. cmDspRC_t rc = kOkDspRC;
  3604. cmDspBiQuadEq_t* p = (cmDspBiQuadEq_t*)inst;
  3605. cmSample_t* y = cmDspAudioBuf(ctx,inst,kOutBqId, 0);
  3606. const cmSample_t* x = cmDspAudioBuf(ctx,inst,kInBqId,0);
  3607. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutBqId,0);
  3608. cmBiQuadEqExec(p->p,x,y,n);
  3609. return rc;
  3610. }
  3611. cmDspRC_t _cmDspBiQuadEqRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3612. {
  3613. cmDspRC_t rc;
  3614. cmDspBiQuadEq_t* p = (cmDspBiQuadEq_t*)inst;
  3615. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  3616. return rc;
  3617. cmReal_t f0Hz = p->p->f0Hz;
  3618. cmReal_t Q = p->p->Q;
  3619. cmReal_t gainDb = p->p->gainDb;
  3620. unsigned mode = p->p->mode;
  3621. if( evt->dstVarId == kModeBqId )
  3622. {
  3623. if((mode = _cmDspBiQuadEqModeId(ctx,inst,cmDspSymbol(inst,kModeBqId) )) == cmInvalidId )
  3624. rc = kVarNotValidDspRC;
  3625. }
  3626. else
  3627. {
  3628. cmReal_t v = cmDspDouble(inst,evt->dstVarId);
  3629. switch( evt->dstVarId )
  3630. {
  3631. case kF0HzBqId:
  3632. f0Hz = v;
  3633. break;
  3634. case kQBqId:
  3635. Q = v;
  3636. break;
  3637. case kGainDbBqId:
  3638. gainDb = v;
  3639. break;
  3640. case kBypassBqId:
  3641. p->p->bypassFl = cmDspBool(inst,kBypassBqId);
  3642. break;
  3643. }
  3644. }
  3645. cmBiQuadEqSet(p->p,mode,f0Hz,Q,gainDb);
  3646. return rc;
  3647. }
  3648. cmDspClass_t* cmBiQuadEqClassCons( cmDspCtx_t* ctx )
  3649. {
  3650. cmDspClassSetup(&_cmBiQuadEqDC,ctx,"BiQuadEq",
  3651. NULL,
  3652. _cmDspBiQuadEqAlloc,
  3653. _cmDspBiQuadEqFree,
  3654. _cmDspBiQuadEqReset,
  3655. _cmDspBiQuadEqExec,
  3656. _cmDspBiQuadEqRecv,
  3657. NULL,NULL,
  3658. "Bi-Quad EQ Filters");
  3659. return &_cmBiQuadEqDC;
  3660. }
  3661. //------------------------------------------------------------------------------------------------------------
  3662. //)
  3663. //( { label:cmDspDistDs file_desc:"Guitar style distortion effect." kw:[sunit] }
  3664. enum
  3665. {
  3666. kBypassDsId,
  3667. kInGainDsId,
  3668. kSrateDsId,
  3669. kBitsDsId,
  3670. kRectDsId,
  3671. kFullDsId,
  3672. kClipDbDsId,
  3673. kOutGainDsId,
  3674. kInDsId,
  3675. kOutDsId
  3676. };
  3677. cmDspClass_t _cmDistDsDC;
  3678. typedef struct
  3679. {
  3680. cmDspInst_t inst;
  3681. cmDistDs* p;
  3682. } cmDspDistDs_t;
  3683. cmDspInst_t* _cmDspDistDsAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3684. {
  3685. cmDspDistDs_t* p = cmDspInstAllocV(cmDspDistDs_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3686. 1, "bypass", kBypassDsId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Bypass enable.",
  3687. 1, "igain", kInGainDsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Input gain.",
  3688. 1, "srate", kSrateDsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Down-sample rate.",
  3689. 1, "bits", kBitsDsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Bits per sample",
  3690. 1, "rect", kRectDsId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "Rectify flag",
  3691. 1, "full", kFullDsId, 0, 0, kInDsvFl | kBoolDsvFl | kOptArgDsvFl, "1=Full 0=Half rectify",
  3692. 1, "clip", kClipDbDsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Clip dB",
  3693. 1, "ogain", kOutGainDsId, 0, 0, kInDsvFl | kDoubleDsvFl | kOptArgDsvFl, "Output gain",
  3694. 1, "in", kInDsId, 0, 0, kInDsvFl | kAudioBufDsvFl, "Audio input",
  3695. 1, "out", kOutDsId, 0, 1, kOutDsvFl | kAudioBufDsvFl, "Audio output",
  3696. 0 );
  3697. cmDspSetDefaultBool( ctx, &p->inst, kBypassDsId, false, false );
  3698. cmDspSetDefaultDouble( ctx, &p->inst, kInGainDsId, 0.0, 1.0 );
  3699. cmDspSetDefaultDouble( ctx, &p->inst, kSrateDsId, 0.0, cmDspSampleRate(ctx));
  3700. cmDspSetDefaultDouble( ctx, &p->inst, kBitsDsId, 0.0, 24.0 );
  3701. cmDspSetDefaultBool( ctx, &p->inst, kRectDsId, false, false );
  3702. cmDspSetDefaultBool( ctx, &p->inst, kFullDsId, false, false );
  3703. cmDspSetDefaultDouble( ctx, &p->inst, kClipDbDsId, 0.0, 0.0 );
  3704. cmDspSetDefaultDouble( ctx, &p->inst, kOutGainDsId, 0.0, 1.0 );
  3705. p->p = cmDistDsAlloc(ctx->cmProcCtx, NULL, 0, 0, 0, 0, false, false, 0, 0, false );
  3706. return &p->inst;
  3707. }
  3708. cmDspRC_t _cmDspDistDsFree(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3709. {
  3710. cmDspDistDs_t* p = (cmDspDistDs_t*)inst;
  3711. cmDistDsFree(&p->p);
  3712. return kOkDspRC;
  3713. }
  3714. cmDspRC_t _cmDspDistDsReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3715. {
  3716. cmDspRC_t rc = kOkDspRC;
  3717. cmDspDistDs_t* p = (cmDspDistDs_t*)inst;
  3718. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  3719. {
  3720. cmDspZeroAudioBuf(ctx,inst,kOutDsId);
  3721. bool bypassFl = cmDspBool( inst, kBypassDsId );
  3722. cmReal_t inGain = cmDspDouble( inst, kInGainDsId );
  3723. cmReal_t downSrate = cmDspDouble( inst, kSrateDsId );
  3724. cmReal_t bits = cmDspDouble( inst, kBitsDsId );
  3725. bool rectFl = cmDspBool( inst, kRectDsId );
  3726. bool fullFl = cmDspBool( inst, kFullDsId );
  3727. cmReal_t clipDb = cmDspDouble( inst, kClipDbDsId );
  3728. cmReal_t outGain = cmDspDouble( inst, kOutGainDsId );
  3729. cmDistDsInit(p->p, cmDspSampleRate(ctx), inGain, downSrate, bits, rectFl, fullFl, clipDb, outGain, bypassFl );
  3730. }
  3731. return rc;
  3732. }
  3733. cmDspRC_t _cmDspDistDsExec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3734. {
  3735. cmDspRC_t rc = kOkDspRC;
  3736. cmDspDistDs_t* p = (cmDspDistDs_t*)inst;
  3737. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutDsId,0);
  3738. cmSample_t* y = cmDspAudioBuf(ctx,inst,kOutDsId,0);
  3739. const cmSample_t* x = cmDspAudioBuf(ctx,inst,kInDsId,0);
  3740. cmDistDsExec(p->p,x,y,n);
  3741. return rc;
  3742. }
  3743. cmDspRC_t _cmDspDistDsRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3744. {
  3745. cmDspRC_t rc = kOkDspRC;
  3746. cmDspDistDs_t* p = (cmDspDistDs_t*)inst;
  3747. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  3748. {
  3749. switch( evt->dstVarId )
  3750. {
  3751. case kInGainDsId:
  3752. p->p->inGain = cmDspDouble(inst,kInGainDsId);
  3753. break;
  3754. case kSrateDsId:
  3755. p->p->downSrate = cmDspDouble(inst,kSrateDsId);
  3756. break;
  3757. case kBitsDsId:
  3758. p->p->bits = cmDspDouble(inst,kBitsDsId);
  3759. break;
  3760. case kRectDsId:
  3761. p->p->rectFl = cmDspBool(inst,kRectDsId);
  3762. break;
  3763. case kFullDsId:
  3764. p->p->fullFl = cmDspBool(inst,kFullDsId);
  3765. break;
  3766. case kClipDbDsId:
  3767. p->p->clipDb = cmDspDouble(inst,kClipDbDsId);
  3768. break;
  3769. case kOutGainDsId:
  3770. p->p->outGain = cmDspDouble(inst,kOutGainDsId);
  3771. break;
  3772. case kBypassDsId:
  3773. p->p->bypassFl = cmDspBool(inst,kBypassDsId);
  3774. break;
  3775. }
  3776. }
  3777. return rc;
  3778. }
  3779. cmDspClass_t* cmDistDsClassCons( cmDspCtx_t* ctx )
  3780. {
  3781. cmDspClassSetup(&_cmDistDsDC,ctx,"DistDs",
  3782. NULL,
  3783. _cmDspDistDsAlloc,
  3784. _cmDspDistDsFree,
  3785. _cmDspDistDsReset,
  3786. _cmDspDistDsExec,
  3787. _cmDspDistDsRecv,
  3788. NULL,NULL,
  3789. "Distortion and Downsampler");
  3790. return &_cmDistDsDC;
  3791. }
  3792. //------------------------------------------------------------------------------------------------------------
  3793. //)
  3794. //( { label:cmDspDbToLin file_desc:"Convert decibel units to linear units." kw:[sunit] }
  3795. enum
  3796. {
  3797. kInDlId,
  3798. kOutDlId
  3799. };
  3800. cmDspClass_t _cmDbToLinDC;
  3801. typedef struct
  3802. {
  3803. cmDspInst_t inst;
  3804. } cmDspDbToLin_t;
  3805. cmDspInst_t* _cmDspDbToLinAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3806. {
  3807. cmDspDbToLin_t* p = cmDspInstAllocV(cmDspDbToLin_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  3808. 1, "in", kInDlId, 0, 0, kInDsvFl | kDoubleDsvFl, "Input",
  3809. 1, "out", kOutDlId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output",
  3810. 0 );
  3811. cmDspSetDefaultDouble( ctx, &p->inst, kInDlId, 0.0, -1000.0);
  3812. cmDspSetDefaultDouble( ctx, &p->inst, kOutDlId, 0.0, 0.0 );
  3813. return &p->inst;
  3814. }
  3815. cmDspRC_t _cmDspDbToLinReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3816. {
  3817. return cmDspApplyAllDefaults(ctx,inst);
  3818. }
  3819. cmDspRC_t _cmDspDbToLinRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3820. {
  3821. cmDspRC_t rc = kOkDspRC;
  3822. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  3823. {
  3824. if( evt->dstVarId == kInDlId )
  3825. {
  3826. double db = cmMax(0.0,cmMin(100.0,cmDspDouble(inst,kInDlId)));
  3827. double lin = db==0 ? 0.0 : pow(10.0, (db-100.0)/20.0);
  3828. cmDspSetDouble(ctx,inst,kOutDlId,lin);
  3829. }
  3830. }
  3831. return rc;
  3832. }
  3833. cmDspClass_t* cmDbToLinClassCons( cmDspCtx_t* ctx )
  3834. {
  3835. cmDspClassSetup(&_cmDbToLinDC,ctx,"DbToLin",
  3836. NULL,
  3837. _cmDspDbToLinAlloc,
  3838. NULL,
  3839. _cmDspDbToLinReset,
  3840. NULL,
  3841. _cmDspDbToLinRecv,
  3842. NULL,NULL,
  3843. "dB to Linear converter");
  3844. return &_cmDbToLinDC;
  3845. }
  3846. //------------------------------------------------------------------------------------------------------------
  3847. //)
  3848. //( { label:cmDspNofM2 file_desc:"Pass an N of M possible inputs to the output." kw:[sunit] }
  3849. // Pass any N of M inputs
  3850. enum
  3851. {
  3852. kInChCntNoId,
  3853. kOutChCntNoId,
  3854. kXfadeMsNoId,
  3855. kCmdNoId,
  3856. kSelIdxNoId,
  3857. kBaseGateNoId
  3858. };
  3859. cmDspClass_t _cmNofM_DC;
  3860. typedef struct
  3861. {
  3862. cmDspInst_t inst;
  3863. unsigned iChCnt;
  3864. unsigned oChCnt;
  3865. unsigned* map; // map[ oChCnt ]
  3866. cmXfader** xf; // xf[ oChCnt ];
  3867. unsigned cfgSymId;
  3868. unsigned onSymId;
  3869. unsigned offSymId;
  3870. bool verboseFl;
  3871. unsigned baseBaseInNoId; // first data input port id
  3872. unsigned baseBaseOutNoId; // first data output port id
  3873. unsigned baseInFloatNoId;
  3874. unsigned baseInBoolNoId;
  3875. unsigned baseInSymNoId;
  3876. unsigned baseInAudioNoId;
  3877. unsigned baseOutFloatNoId;
  3878. unsigned baseOutBoolNoId;
  3879. unsigned baseOutSymNoId;
  3880. unsigned baseOutAudioNoId;
  3881. bool printFl;
  3882. } cmDspNofM_t;
  3883. cmDspInst_t* _cmDspNofM_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  3884. {
  3885. if( va_cnt < 2 )
  3886. {
  3887. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'NofM' constructor must given input and output channel counts.");
  3888. return NULL;
  3889. }
  3890. va_list vl1;
  3891. va_copy(vl1,vl);
  3892. int iChCnt = va_arg(vl,int);
  3893. int oChCnt = va_arg(vl,int);
  3894. if( oChCnt > iChCnt )
  3895. {
  3896. va_end(vl1);
  3897. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'NofM' output count must be less than or equal to the input count.");
  3898. return NULL;
  3899. }
  3900. unsigned baseInFloatNoId = kBaseGateNoId + iChCnt;
  3901. unsigned baseInBoolNoId = baseInFloatNoId + iChCnt;
  3902. unsigned baseInSymNoId = baseInBoolNoId + iChCnt;
  3903. unsigned baseInAudioNoId = baseInSymNoId + iChCnt;
  3904. unsigned baseOutFloatNoId = baseInAudioNoId + iChCnt;
  3905. unsigned baseOutBoolNoId = baseOutFloatNoId + oChCnt;
  3906. unsigned baseOutSymNoId = baseOutBoolNoId + oChCnt;
  3907. unsigned baseOutAudioNoId = baseOutSymNoId + oChCnt;
  3908. unsigned i;
  3909. cmDspNofM_t* p = cmDspInstAllocV(cmDspNofM_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  3910. 1, "ichs", kInChCntNoId, 0, 0, kUIntDsvFl | kReqArgDsvFl,"Input channel count.",
  3911. 1, "ochs", kOutChCntNoId, 0, 0, kUIntDsvFl | kReqArgDsvFl,"Output channel count.",
  3912. 1, "ms", kXfadeMsNoId, 0, 0, kDoubleDsvFl | kInDsvFl | kOptArgDsvFl,"Audio Cross-fade time in milliseconds.",
  3913. 1, "cmd", kCmdNoId, 0, 0, kSymDsvFl | kInDsvFl, "Command input.",
  3914. 1, "seli", kSelIdxNoId, 0, 0, kUIntDsvFl | kInDsvFl, "Enable gate at index.",
  3915. iChCnt, "sel", kBaseGateNoId, 0, 0, kBoolDsvFl | kInDsvFl, "Selector Gate inputs.",
  3916. iChCnt, "f-in", baseInFloatNoId, 0, 0, kDoubleDsvFl | kInDsvFl, "Float input",
  3917. iChCnt, "b-in", baseInBoolNoId, 0, 0, kBoolDsvFl | kInDsvFl, "Bool input",
  3918. iChCnt, "s-in", baseInSymNoId, 0, 0, kSymDsvFl | kInDsvFl, "Symbol input",
  3919. iChCnt, "a-in", baseInAudioNoId, 0, 0, kAudioBufDsvFl | kInDsvFl, "Audio input",
  3920. oChCnt, "f-out", baseOutFloatNoId, 0, 0, kDoubleDsvFl | kOutDsvFl, "Float output",
  3921. oChCnt, "b-out", baseOutBoolNoId, 0, 0, kBoolDsvFl | kOutDsvFl, "Bool output",
  3922. oChCnt, "s-out", baseOutSymNoId, 0, 0, kSymDsvFl | kOutDsvFl, "Symbol output",
  3923. oChCnt, "a-out", baseOutAudioNoId, 0, 1, kAudioBufDsvFl | kOutDsvFl, "Audio output",
  3924. 0 );
  3925. p->iChCnt = iChCnt;
  3926. p->oChCnt = oChCnt;
  3927. p->map = cmMemAllocZ(unsigned,oChCnt);
  3928. p->xf = cmMemAllocZ(cmXfader*,oChCnt);
  3929. p->cfgSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"cfg");
  3930. p->onSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"on");
  3931. p->offSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"off");
  3932. p->verboseFl = false;
  3933. p->baseBaseInNoId = baseInFloatNoId;
  3934. p->baseBaseOutNoId = baseOutFloatNoId;
  3935. p->baseInFloatNoId = baseInFloatNoId;
  3936. p->baseInBoolNoId = baseInBoolNoId;
  3937. p->baseInSymNoId = baseInSymNoId;
  3938. p->baseInAudioNoId = baseInAudioNoId;
  3939. p->baseOutFloatNoId = baseOutFloatNoId;
  3940. p->baseOutBoolNoId = baseOutBoolNoId;
  3941. p->baseOutSymNoId = baseOutSymNoId;
  3942. p->baseOutAudioNoId = baseOutAudioNoId;
  3943. for(i=0; i<oChCnt; ++i)
  3944. {
  3945. cmDspSetDefaultDouble( ctx, &p->inst, baseOutFloatNoId + i, 0.0, 0.0 );
  3946. cmDspSetDefaultBool( ctx, &p->inst, baseOutBoolNoId + i, false, false );
  3947. cmDspSetDefaultSymbol( ctx, &p->inst, baseOutSymNoId + i, cmInvalidId );
  3948. p->xf[i] = cmXfaderAlloc( ctx->cmProcCtx, NULL, 0, 0, 0 );
  3949. }
  3950. cmDspSetDefaultDouble( ctx, &p->inst, kXfadeMsNoId, 0.0, 15.0 );
  3951. va_end(vl1);
  3952. return &p->inst;
  3953. }
  3954. cmDspRC_t _cmDspNofM_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3955. {
  3956. cmDspNofM_t* p = (cmDspNofM_t*)inst;
  3957. unsigned i;
  3958. for(i=0; i<p->oChCnt; ++i)
  3959. cmXfaderFree(&p->xf[i]);
  3960. cmMemFree(p->map);
  3961. cmMemFree(p->xf);
  3962. return kOkDspRC;
  3963. }
  3964. cmDspRC_t _cmDspNofM_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3965. {
  3966. cmDspRC_t rc = kOkDspRC;
  3967. cmDspNofM_t* p = (cmDspNofM_t*)inst;
  3968. unsigned i;
  3969. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  3970. {
  3971. for(i=0; i<p->oChCnt; ++i)
  3972. {
  3973. cmDspZeroAudioBuf(ctx,inst,p->baseOutAudioNoId+i);
  3974. p->map[i] = cmInvalidIdx;
  3975. double xfadeMs = cmDspDouble(inst,kXfadeMsNoId);
  3976. cmXfaderInit(p->xf[i], cmDspSampleRate(ctx), p->iChCnt, xfadeMs );
  3977. }
  3978. }
  3979. return rc;
  3980. }
  3981. cmDspRC_t _cmDspNofM_Exec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  3982. {
  3983. cmDspRC_t rc = kOkDspRC;
  3984. cmDspNofM_t* p = (cmDspNofM_t*)inst;
  3985. unsigned i;
  3986. const cmSample_t* x[ p->iChCnt ];
  3987. for(i=0; i<p->iChCnt; ++i)
  3988. x[i] = cmDspAudioBuf(ctx,inst,p->baseInAudioNoId + i ,0);
  3989. // for each valid p->map[] element
  3990. for(i=0; i<p->oChCnt; ++i)
  3991. {
  3992. cmSample_t* y = cmDspAudioBuf(ctx,inst,p->baseOutAudioNoId+ i,0);
  3993. unsigned n = cmDspAudioBufSmpCount(ctx,inst,p->baseOutAudioNoId+i,0);
  3994. if( y != NULL )
  3995. {
  3996. y = cmVOS_Zero(y,n);
  3997. cmXfaderExecAudio(p->xf[i],n,NULL,p->iChCnt,x,y);
  3998. }
  3999. }
  4000. return rc;
  4001. }
  4002. cmDspRC_t _cmDspNofM_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4003. {
  4004. cmDspRC_t rc = kOkDspRC;
  4005. cmDspNofM_t* p = (cmDspNofM_t*)inst;
  4006. unsigned i,j;
  4007. assert( evt->dstVarId < p->baseBaseOutNoId );
  4008. // store the incoming value
  4009. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  4010. return rc;
  4011. // if this is a fade time
  4012. if( evt->dstVarId == kXfadeMsNoId )
  4013. {
  4014. for(i=0; i<p->oChCnt; ++i)
  4015. cmXfaderSetXfadeTime( p->xf[i], cmDspDouble(inst,kXfadeMsNoId) );
  4016. return rc;
  4017. }
  4018. // if this is an index selector
  4019. if( kSelIdxNoId == evt->dstVarId )
  4020. {
  4021. unsigned idx;
  4022. if((idx = cmDspUInt(inst,kSelIdxNoId)) >= p->iChCnt )
  4023. rc = cmDspInstErr(ctx,inst,kInvalidArgDspRC,"The selection index ('%i') is out of the channel range, (%i).",idx,p->iChCnt);
  4024. else
  4025. {
  4026. cmDspSetBool( ctx, inst, kBaseGateNoId+idx , true );
  4027. if( p->verboseFl )
  4028. cmRptPrintf(ctx->rpt,"nom seli:%i\n",idx);
  4029. }
  4030. return rc;
  4031. }
  4032. // NOTE: the internal state DOES NOT CHANGE until a message arrives
  4033. // on the 'cmd' port
  4034. // if anything arrives on the command port - then read the gate states and rebuild the map
  4035. if( evt->dstVarId == kCmdNoId )
  4036. {
  4037. unsigned cmdSymId = cmDspSymbol(inst,kCmdNoId);
  4038. // if cmdSymId == 'on' then turn on all selection gates
  4039. if(cmdSymId == p->onSymId )
  4040. {
  4041. for(i=0; i<p->oChCnt; ++i)
  4042. cmDspSetBool(ctx,inst,kBaseGateNoId+i,true);
  4043. }
  4044. else
  4045. // if cmdSymId == 'off' then turn off all selection gates
  4046. if( cmdSymId == p->offSymId )
  4047. {
  4048. if( p->verboseFl )
  4049. cmRptPrintf(ctx->rpt,"nom: off\n");
  4050. for(i=0; i<p->oChCnt; ++i)
  4051. cmDspSetBool(ctx,inst,kBaseGateNoId+i,false);
  4052. }
  4053. else
  4054. // cmdSymId == 'print' then print the in/out map[]
  4055. if( cmdSymId == cmSymTblId(ctx->stH,"print") )
  4056. {
  4057. for(i=0; i<p->oChCnt; ++i)
  4058. cmRptPrintf(ctx->rpt,"%i:%i ",i,p->map[i]);
  4059. cmRptPrintf(ctx->rpt,"\n");
  4060. cmRptPrintf(ctx->rpt,"%i usecs\n",ctx->execDurUsecs);
  4061. p->printFl = !p->printFl;
  4062. }
  4063. if( p->verboseFl )
  4064. cmRptPrintf(ctx->rpt,"Nom: %s ", inst->symId != cmInvalidId ? cmSymTblLabel(ctx->stH,inst->symId) : "");
  4065. // 5/26
  4066. if( p->iChCnt == p->oChCnt )
  4067. cmVOU_Fill(p->map,p->oChCnt,cmInvalidIdx);
  4068. // for each input
  4069. for(i=0,j=0; i<p->iChCnt; ++i)
  4070. {
  4071. // if this input is switched on
  4072. if( cmDspBool(inst,kBaseGateNoId+i) )
  4073. {
  4074. if( j >= p->oChCnt )
  4075. {
  4076. cmDspInstErr(ctx,inst,kVarNotValidDspRC,"To many inputs have been turned on for %i outputs.",p->oChCnt);
  4077. break;
  4078. }
  4079. // assign input i to output j
  4080. p->map[j] = i;
  4081. // fade in ch i and fade out all others
  4082. cmXfaderSelectOne(p->xf[j],i);
  4083. ++j;
  4084. if( p->verboseFl )
  4085. cmRptPrintf(ctx->rpt,"%i ",i);
  4086. }
  4087. else // 5/26
  4088. {
  4089. if( p->iChCnt == p->oChCnt )
  4090. ++j;
  4091. }
  4092. }
  4093. // deselect all other output channels
  4094. //for(; j<p->oChCnt; ++j)
  4095. //{
  4096. // p->map[j] = cmInvalidIdx;
  4097. // cmXfaderAllOff(p->xf[j]);
  4098. //}
  4099. // 5/26
  4100. if( p->iChCnt == p->oChCnt )
  4101. {
  4102. for(j=0; j<p->oChCnt; ++j)
  4103. if( p->map[j] == cmInvalidIdx )
  4104. cmXfaderAllOff(p->xf[j]);
  4105. }
  4106. else
  4107. {
  4108. for(; j<p->oChCnt; ++j)
  4109. {
  4110. p->map[j] = cmInvalidIdx;
  4111. cmXfaderAllOff(p->xf[j]);
  4112. }
  4113. }
  4114. if( p->verboseFl )
  4115. cmRptPrintf(ctx->rpt,"\n");
  4116. // zero the audio buffers of unused output channels
  4117. for(i=0; i<p->oChCnt; ++i)
  4118. if( p->map[i] == cmInvalidIdx )
  4119. cmDspZeroAudioBuf(ctx,inst,p->baseOutAudioNoId+i);
  4120. }
  4121. // if this is an input data event
  4122. if( p->baseBaseInNoId <= evt->dstVarId && evt->dstVarId < p->baseBaseOutNoId )
  4123. {
  4124. // get the input channel this event occurred on
  4125. unsigned iChIdx = (evt->dstVarId - p->baseBaseInNoId) % p->iChCnt;
  4126. // is iChIdx mapped to an output ...
  4127. for(i=0; i<p->oChCnt; ++i)
  4128. if( p->map[i] == iChIdx )
  4129. break;
  4130. // ... no - nothing else to do
  4131. if( i==p->oChCnt )
  4132. return kOkDspRC;
  4133. // ... yes set the output ...
  4134. // double
  4135. if( p->baseInFloatNoId <= evt->dstVarId && evt->dstVarId < p->baseInFloatNoId + p->iChCnt )
  4136. {
  4137. cmDspSetDouble(ctx,inst,p->baseOutFloatNoId + i, cmDspDouble(inst,evt->dstVarId));
  4138. }
  4139. else
  4140. // bool
  4141. if( p->baseInBoolNoId <= evt->dstVarId && evt->dstVarId < p->baseInBoolNoId + p->iChCnt )
  4142. {
  4143. cmDspSetBool(ctx,inst,p->baseOutBoolNoId + i, cmDspBool(inst,evt->dstVarId));
  4144. if(p->printFl)
  4145. cmRptPrintf(ctx->rpt,"%i %i\n",p->baseOutBoolNoId + i, cmDspBool(inst,evt->dstVarId));
  4146. }
  4147. else
  4148. // symbol
  4149. if( p->baseInSymNoId <= evt->dstVarId && evt->dstVarId < p->baseInSymNoId + p->iChCnt )
  4150. cmDspSetSymbol(ctx,inst,p->baseOutSymNoId + i, cmDspSymbol(inst,evt->dstVarId));
  4151. }
  4152. return rc;
  4153. }
  4154. cmDspClass_t* cmNofMClassCons( cmDspCtx_t* ctx )
  4155. {
  4156. cmDspClassSetup(&_cmNofM_DC,ctx,"NofM",
  4157. NULL,
  4158. _cmDspNofM_Alloc,
  4159. _cmDspNofM_Free,
  4160. _cmDspNofM_Reset,
  4161. _cmDspNofM_Exec,
  4162. _cmDspNofM_Recv,
  4163. NULL,NULL,
  4164. "N of M Switch");
  4165. return &_cmNofM_DC;
  4166. }
  4167. //------------------------------------------------------------------------------------------------------------
  4168. //)
  4169. //( { label:cmDsp1ofN file_desc:"Pass 1 or N possible inputs to the output." kw:[sunit] }
  4170. enum
  4171. {
  4172. kInChCnt1oId,
  4173. kInChIdx1oId,
  4174. kOutFloat1oId,
  4175. kOutBool1oId,
  4176. kOutSym1oId,
  4177. kOutAudio1oId,
  4178. kBaseInFloat1oId
  4179. };
  4180. cmDspClass_t _cm1ofN_DC;
  4181. typedef struct
  4182. {
  4183. cmDspInst_t inst;
  4184. unsigned iChCnt;
  4185. unsigned oChCnt;
  4186. unsigned iChIdx;
  4187. unsigned baseBaseIn1oId; // first data input port id
  4188. unsigned baseInFloat1oId;
  4189. unsigned baseInBool1oId;
  4190. unsigned baseInSym1oId;
  4191. unsigned baseInAudio1oId;
  4192. unsigned baseOutFloat1oId;
  4193. unsigned baseOutBool1oId;
  4194. unsigned baseOutSym1oId;
  4195. unsigned baseOutAudio1oId;
  4196. } cmDsp1ofN_t;
  4197. cmDspInst_t* _cmDsp1ofN_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4198. {
  4199. if( va_cnt < 1 )
  4200. {
  4201. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The '1ofN' constructor must given input channel count.");
  4202. return NULL;
  4203. }
  4204. va_list vl1;
  4205. va_copy(vl1,vl);
  4206. int iChCnt = va_arg(vl,int);
  4207. unsigned baseInFloat1oId = kBaseInFloat1oId;
  4208. unsigned baseInBool1oId = baseInFloat1oId + iChCnt;
  4209. unsigned baseInSym1oId = baseInBool1oId + iChCnt;
  4210. unsigned baseInAudio1oId = baseInSym1oId + iChCnt;
  4211. cmDsp1ofN_t* p = cmDspInstAllocV(cmDsp1ofN_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  4212. 1, "ichs", kInChCnt1oId, 0, 0, kUIntDsvFl | kReqArgDsvFl,"Input channel count.",
  4213. 1, "chidx", kInChIdx1oId, 0, 0, kUIntDsvFl | kReqArgDsvFl | kInDsvFl, "Input channel selector index.",
  4214. 1, "f-out", kOutFloat1oId, 0, 0, kDoubleDsvFl | kOutDsvFl, "Float output",
  4215. 1, "b-out", kOutBool1oId, 0, 0, kBoolDsvFl | kOutDsvFl, "Bool output",
  4216. 1, "s-out", kOutSym1oId, 0, 0, kSymDsvFl | kOutDsvFl, "Symbol output",
  4217. 1, "a-out", kOutAudio1oId, 0, 1, kAudioBufDsvFl | kOutDsvFl, "Audio output",
  4218. iChCnt, "f-in", baseInFloat1oId, 0, 0, kDoubleDsvFl | kInDsvFl, "Float input",
  4219. iChCnt, "b-in", baseInBool1oId, 0, 0, kBoolDsvFl | kInDsvFl, "Bool input",
  4220. iChCnt, "s-in", baseInSym1oId, 0, 0, kSymDsvFl | kInDsvFl, "Symbol input",
  4221. iChCnt, "a-in", baseInAudio1oId, 0, 0, kAudioBufDsvFl | kInDsvFl, "Audio input",
  4222. 0 );
  4223. p->iChCnt = iChCnt;
  4224. p->baseBaseIn1oId = kBaseInFloat1oId;
  4225. p->baseInFloat1oId = baseInFloat1oId;
  4226. p->baseInBool1oId = baseInBool1oId;
  4227. p->baseInSym1oId = baseInSym1oId;
  4228. p->baseInAudio1oId = baseInAudio1oId;
  4229. cmDspSetDefaultDouble( ctx, &p->inst, kOutFloat1oId, 0.0, 0.0 );
  4230. cmDspSetDefaultBool( ctx, &p->inst, kOutBool1oId, false, false );
  4231. cmDspSetDefaultSymbol( ctx, &p->inst, kOutSym1oId, cmInvalidId );
  4232. va_end(vl1);
  4233. return &p->inst;
  4234. }
  4235. cmDspRC_t _cmDsp1ofN_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4236. {
  4237. return kOkDspRC;
  4238. }
  4239. cmDspRC_t _cmDsp1ofN_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4240. {
  4241. cmDspRC_t rc = kOkDspRC;
  4242. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  4243. {
  4244. cmDspZeroAudioBuf(ctx,inst,kOutAudio1oId);
  4245. }
  4246. return rc;
  4247. }
  4248. cmDspRC_t _cmDsp1ofN_Exec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4249. {
  4250. cmDspRC_t rc = kOkDspRC;
  4251. cmDsp1ofN_t* p = (cmDsp1ofN_t*)inst;
  4252. unsigned iChIdx = cmDspUInt(inst,kInChIdx1oId);
  4253. cmSample_t* dp = cmDspAudioBuf(ctx,inst,kOutAudio1oId,0);
  4254. const cmSample_t* sp = cmDspAudioBuf(ctx,inst,p->baseInAudio1oId + iChIdx ,0);
  4255. unsigned n = cmDspAudioBufSmpCount(ctx,inst,kOutAudio1oId,0);
  4256. if( dp != NULL )
  4257. {
  4258. if( sp == NULL )
  4259. cmVOS_Zero(dp,n);
  4260. else
  4261. cmVOS_Copy(dp,n,sp);
  4262. }
  4263. return rc;
  4264. }
  4265. cmDspRC_t _cmDsp1ofN_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4266. {
  4267. cmDspRC_t rc = kOkDspRC;
  4268. cmDsp1ofN_t* p = (cmDsp1ofN_t*)inst;
  4269. // ignore out of range input channel
  4270. if( evt->dstVarId == kInChIdx1oId && cmDsvGetUInt(evt->valuePtr) >= p->iChCnt )
  4271. {
  4272. cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The selector channel index %i is out of range.",cmDsvGetUInt(evt->valuePtr));
  4273. return kOkDspRC;
  4274. }
  4275. // store the incoming value
  4276. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  4277. return rc;
  4278. // if this is an input data event
  4279. if( p->baseBaseIn1oId <= evt->dstVarId )
  4280. {
  4281. // get the input channel this event occurred on
  4282. unsigned iChIdx = (evt->dstVarId - p->baseBaseIn1oId) % p->iChCnt;
  4283. // if the event did not arrive on the selected input channel - there is nothing else to do
  4284. if( iChIdx != cmDspUInt(inst,kInChIdx1oId) )
  4285. return kOkDspRC;
  4286. // The event arrived on the input channel - send it out the output
  4287. // double
  4288. if( p->baseInFloat1oId <= evt->dstVarId && evt->dstVarId < p->baseInFloat1oId + p->iChCnt )
  4289. cmDspSetDouble(ctx,inst,kOutFloat1oId, cmDspDouble(inst,evt->dstVarId));
  4290. else
  4291. // bool
  4292. if( p->baseInBool1oId <= evt->dstVarId && evt->dstVarId < p->baseInBool1oId + p->iChCnt )
  4293. cmDspSetBool(ctx,inst,kOutBool1oId, cmDspBool(inst,evt->dstVarId));
  4294. else
  4295. // symbol
  4296. if( p->baseInSym1oId <= evt->dstVarId && evt->dstVarId < p->baseInSym1oId + p->iChCnt )
  4297. cmDspSetSymbol(ctx,inst,kOutSym1oId, cmDspSymbol(inst,evt->dstVarId));
  4298. }
  4299. return rc;
  4300. }
  4301. cmDspClass_t* cm1ofNClassCons( cmDspCtx_t* ctx )
  4302. {
  4303. cmDspClassSetup(&_cm1ofN_DC,ctx,"1ofN",
  4304. NULL,
  4305. _cmDsp1ofN_Alloc,
  4306. _cmDsp1ofN_Free,
  4307. _cmDsp1ofN_Reset,
  4308. _cmDsp1ofN_Exec,
  4309. _cmDsp1ofN_Recv,
  4310. NULL,NULL,
  4311. " 1 of N Switch");
  4312. return &_cm1ofN_DC;
  4313. }
  4314. //------------------------------------------------------------------------------------------------------------
  4315. //)
  4316. //( { label:cmDsp1Up file_desc:"Send 'true' on the selected channel and 'false' on the deselected channel." kw:[sunit] }
  4317. // Send a 'true' out on the selected channel.
  4318. // Send a 'false' out on the deselected channel.
  4319. enum
  4320. {
  4321. kChCnt1uId,
  4322. kSel1uId,
  4323. kBaseOut1uId
  4324. };
  4325. cmDspClass_t _cm1Up_DC;
  4326. typedef struct
  4327. {
  4328. cmDspInst_t inst;
  4329. } cmDsp1Up_t;
  4330. cmDspInst_t* _cmDsp1Up_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4331. {
  4332. if( va_cnt < 1 )
  4333. {
  4334. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The '1Up' constructor must given output channel count.");
  4335. return NULL;
  4336. }
  4337. va_list vl1;
  4338. va_copy(vl1,vl);
  4339. int chCnt = va_arg(vl,int);
  4340. cmDsp1Up_t* p = cmDspInstAllocV(cmDsp1Up_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  4341. 1, "chcnt", kChCnt1uId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Output channel count.",
  4342. 1, "sel", kSel1uId, 0, 0, kUIntDsvFl | kOptArgDsvFl | kInDsvFl, "Channel index selector.",
  4343. chCnt, "out", kBaseOut1uId, 0, 0, kBoolDsvFl | kOutDsvFl, "Gate outputs",
  4344. 0 );
  4345. unsigned i;
  4346. cmDspSetDefaultUInt( ctx, &p->inst, kSel1uId, 0.0, 0.0 );
  4347. for(i=0; i<chCnt; ++i)
  4348. cmDspSetDefaultBool( ctx, &p->inst, kBaseOut1uId + i, false, false );
  4349. va_end(vl1);
  4350. return &p->inst;
  4351. }
  4352. cmDspRC_t _cmDsp1Up_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4353. {
  4354. cmDspRC_t rc = kOkDspRC;
  4355. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  4356. {
  4357. unsigned chIdx = cmDspUInt(inst,kSel1uId);
  4358. unsigned chCnt = cmDspUInt(inst,kChCnt1uId);
  4359. unsigned i;
  4360. for(i=0; i<chCnt; ++i)
  4361. cmDspSetBool(ctx,inst,kBaseOut1uId+i, i == chIdx );
  4362. }
  4363. return rc;
  4364. }
  4365. cmDspRC_t _cmDsp1Up_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4366. {
  4367. cmDspRC_t rc = kOkDspRC;
  4368. if( evt->dstVarId == kSel1uId)
  4369. {
  4370. unsigned chIdx = cmDspUInt(inst,kSel1uId);
  4371. unsigned chCnt = cmDspUInt(inst,kChCnt1uId);
  4372. // turn off the previously selected channel
  4373. if( chIdx != cmInvalidIdx && chIdx < chCnt )
  4374. cmDspSetBool(ctx,inst,kBaseOut1uId+chIdx,false);
  4375. // set the new channel index
  4376. cmDspSetEvent(ctx,inst,evt);
  4377. // get the new channel index
  4378. chIdx = cmDspUInt(inst,kSel1uId);
  4379. // send the new channel index
  4380. if( chIdx != cmInvalidIdx && chIdx < chCnt )
  4381. cmDspSetBool(ctx,inst,kBaseOut1uId+chIdx,true);
  4382. }
  4383. return rc;
  4384. }
  4385. cmDspClass_t* cm1UpClassCons( cmDspCtx_t* ctx )
  4386. {
  4387. cmDspClassSetup(&_cm1Up_DC,ctx,"1Up",
  4388. NULL,
  4389. _cmDsp1Up_Alloc,
  4390. NULL,
  4391. _cmDsp1Up_Reset,
  4392. NULL,
  4393. _cmDsp1Up_Recv,
  4394. NULL,NULL,
  4395. "Set one input high and all others low.");
  4396. return &_cm1Up_DC;
  4397. }
  4398. //------------------------------------------------------------------------------------------------------------
  4399. //)
  4400. //( { label:cmDspGateToSym file_desc:"Convert a 'true'/'false' gate to an 'on'/'off' symbol." kw:[sunit] }
  4401. //
  4402. enum
  4403. {
  4404. kOnSymGsId,
  4405. kOffSymGsId,
  4406. kOnGsId,
  4407. kOffGsId,
  4408. kBothGsId,
  4409. kOutGsId
  4410. };
  4411. cmDspClass_t _cmGateToSym_DC;
  4412. typedef struct
  4413. {
  4414. cmDspInst_t inst;
  4415. } cmDspGateToSym_t;
  4416. cmDspInst_t* _cmDspGateToSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4417. {
  4418. cmDspGateToSym_t* p = cmDspInstAllocV(cmDspGateToSym_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  4419. 1, "on_sym", kOnSymGsId, 0, 0, kSymDsvFl | kInDsvFl | kOptArgDsvFl,"'on' symbol id (default:'on')",
  4420. 1, "off_sym",kOffSymGsId, 0, 0, kSymDsvFl | kInDsvFl | kOptArgDsvFl,"'off' symbol id (default:'off')",
  4421. 1, "on", kOnGsId, 0, 0, kBoolDsvFl | kInDsvFl, "On - send out 'on' symbol when a 'true' is received.",
  4422. 1, "off", kOffGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Off - send out 'off' symbol when a 'false' is received.",
  4423. 1, "both", kBothGsId, 0, 0, kBoolDsvFl | kInDsvFl, "Send 'on' on 'true' and 'off' on 'false'.",
  4424. 1, "out", kOutGsId, 0, 0, kSymDsvFl | kOutDsvFl, "Output",
  4425. 0 );
  4426. unsigned onSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"on");
  4427. unsigned offSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"off");
  4428. cmDspSetDefaultSymbol( ctx, &p->inst, kOnSymGsId, onSymId );
  4429. cmDspSetDefaultSymbol( ctx, &p->inst, kOffSymGsId, offSymId );
  4430. cmDspSetDefaultSymbol( ctx, &p->inst, kOutGsId, cmInvalidId );
  4431. return &p->inst;
  4432. }
  4433. cmDspRC_t _cmDspGateToSym_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4434. {
  4435. cmDspRC_t rc = kOkDspRC;
  4436. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  4437. {
  4438. }
  4439. return rc;
  4440. }
  4441. cmDspRC_t _cmDspGateToSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4442. {
  4443. cmDspRC_t rc = kOkDspRC;
  4444. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  4445. {
  4446. unsigned onSymId = cmDspSymbol(inst,kOnSymGsId);
  4447. unsigned offSymId = cmDspSymbol(inst,kOffSymGsId);
  4448. switch( evt->dstVarId )
  4449. {
  4450. case kOnGsId:
  4451. if( cmDspBool(inst,kOnGsId) )
  4452. cmDspSetSymbol(ctx,inst,kOutGsId,onSymId);
  4453. break;
  4454. case kOffGsId:
  4455. if( !cmDspBool(inst,kOffGsId) )
  4456. cmDspSetSymbol(ctx,inst,kOutGsId,offSymId);
  4457. break;
  4458. case kBothGsId:
  4459. cmDspSetSymbol(ctx,inst, kOutGsId, cmDspBool(inst,kBothGsId) ? onSymId : offSymId);
  4460. break;
  4461. }
  4462. }
  4463. return rc;
  4464. }
  4465. cmDspClass_t* cmGateToSymClassCons( cmDspCtx_t* ctx )
  4466. {
  4467. cmDspClassSetup(&_cmGateToSym_DC,ctx,"GateToSym",
  4468. NULL,
  4469. _cmDspGateToSym_Alloc,
  4470. NULL,
  4471. _cmDspGateToSym_Reset,
  4472. NULL,
  4473. _cmDspGateToSym_Recv,
  4474. NULL,NULL,
  4475. "Convert a 'true'/'false' gate to an 'on'/'off' symbol.");
  4476. return &_cmGateToSym_DC;
  4477. }
  4478. //------------------------------------------------------------------------------------------------------------
  4479. //)
  4480. //( { label:cmDspPortToSym file_desc:"Send a pre-defined symbol every time a message arrives a given input port." kw:[sunit] }
  4481. enum
  4482. {
  4483. kOutPtsId,
  4484. kBaseInPtsId
  4485. };
  4486. cmDspClass_t _cmPortToSym_DC;
  4487. typedef struct
  4488. {
  4489. cmDspInst_t inst;
  4490. unsigned* symIdArray;
  4491. unsigned symIdCnt;
  4492. unsigned baseOutPtsId;
  4493. } cmDspPortToSym_t;
  4494. cmDspInst_t* _cmDspPortToSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4495. {
  4496. va_list vl1;
  4497. va_copy(vl1,vl);
  4498. if( va_cnt < 1 )
  4499. {
  4500. va_end(vl1);
  4501. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'PortToSym' constructor argument list must contain at least one symbol label.");
  4502. return NULL;
  4503. }
  4504. unsigned symCnt = va_cnt;
  4505. unsigned argCnt = 1 + 2*symCnt;
  4506. cmDspVarArg_t args[argCnt+1];
  4507. unsigned* symIdArray = cmMemAllocZ(unsigned,symCnt);
  4508. unsigned baseOutPtsId = kBaseInPtsId + symCnt;
  4509. // setup the output port arg recd
  4510. cmDspArgSetup(ctx,args,"out",cmInvalidId,kOutPtsId,0,0,kOutDsvFl | kSymDsvFl, "Output" );
  4511. unsigned i;
  4512. for(i=0; i<symCnt; ++i)
  4513. {
  4514. // get the symbol label
  4515. const cmChar_t* symLabel = va_arg(vl,const char*);
  4516. assert( symLabel != NULL );
  4517. // register the symbol
  4518. symIdArray[i] = cmSymTblRegisterSymbol(ctx->stH,symLabel);
  4519. // input port - any msg in this port will generate an output from 'out' as well as the associated output port
  4520. cmDspArgSetup(ctx, args+kBaseInPtsId+i, symLabel, cmInvalidId, kBaseInPtsId+i, 0, 0, kInDsvFl | kTypeDsvMask, cmTsPrintfH(ctx->lhH,"%s Input.",symLabel) );
  4521. cmDspArgSetup(ctx, args+baseOutPtsId+i, symLabel, cmInvalidId, baseOutPtsId+i, 0, 0, kOutDsvFl | kSymDsvFl, cmTsPrintfH(ctx->lhH,"%s Output.",symLabel) );
  4522. }
  4523. cmDspArgSetupNull(args + argCnt);
  4524. cmDspPortToSym_t* p = cmDspInstAlloc(cmDspPortToSym_t,ctx,classPtr,args,instSymId,id,storeSymId,0,vl1);
  4525. p->symIdCnt = symCnt;
  4526. p->symIdArray = symIdArray;
  4527. p->baseOutPtsId = baseOutPtsId;
  4528. cmDspSetDefaultSymbol(ctx,&p->inst,kOutPtsId,cmInvalidId);
  4529. va_end(vl1);
  4530. return &p->inst;
  4531. }
  4532. cmDspRC_t _cmDspPortToSym_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4533. {
  4534. cmDspPortToSym_t* p = (cmDspPortToSym_t*)inst;
  4535. cmMemFree(p->symIdArray);
  4536. return kOkDspRC;
  4537. }
  4538. cmDspRC_t _cmDspPortToSym_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4539. {
  4540. return cmDspApplyAllDefaults(ctx,inst);
  4541. }
  4542. cmDspRC_t _cmDspPortToSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4543. {
  4544. cmDspRC_t rc = kOkDspRC;
  4545. cmDspPortToSym_t* p = (cmDspPortToSym_t*)inst;
  4546. // if a msg of any type is recieved on an input port - send out the associated symbol
  4547. if( kBaseInPtsId <= evt->dstVarId && evt->dstVarId < kBaseInPtsId + p->symIdCnt )
  4548. {
  4549. unsigned idx = evt->dstVarId - kBaseInPtsId;
  4550. assert( idx < p->symIdCnt );
  4551. cmDspSetSymbol(ctx,inst,p->baseOutPtsId + idx, p->symIdArray[idx]);
  4552. return cmDspSetSymbol(ctx,inst,kOutPtsId, p->symIdArray[idx]);
  4553. }
  4554. return rc;
  4555. }
  4556. cmDspClass_t* cmPortToSymClassCons( cmDspCtx_t* ctx )
  4557. {
  4558. cmDspClassSetup(&_cmPortToSym_DC,ctx,"PortToSym",
  4559. NULL,
  4560. _cmDspPortToSym_Alloc,
  4561. _cmDspPortToSym_Free,
  4562. _cmDspPortToSym_Reset,
  4563. NULL,
  4564. _cmDspPortToSym_Recv,
  4565. NULL,NULL,
  4566. "If a message of any kind is received on a port then send the symbol associated with the port.");
  4567. return &_cmPortToSym_DC;
  4568. }
  4569. //------------------------------------------------------------------------------------------------------------
  4570. //)
  4571. //( { label:cmDspIntToSym file_desc:"Send a pre-defined symbol every time a message arrives a given input port." kw:[sunit] }
  4572. enum
  4573. {
  4574. kInItsId,
  4575. kOutItsId,
  4576. kBaseInItsId
  4577. };
  4578. cmDspClass_t _cmIntToSym_DC;
  4579. typedef struct
  4580. {
  4581. cmDspInst_t inst;
  4582. int* intArray;
  4583. unsigned* symIdArray;
  4584. unsigned symIdCnt;
  4585. unsigned baseIntItsId;
  4586. unsigned baseOutItsId;
  4587. } cmDspIntToSym_t;
  4588. cmDspInst_t* _cmDspIntToSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4589. {
  4590. va_list vl1;
  4591. va_copy(vl1,vl);
  4592. if( va_cnt < 2 || va_cnt % 2 !=0 )
  4593. {
  4594. va_end(vl1);
  4595. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'IntToSym' constructor argument list must contain at least one int/symbol pair and all pairs must be complete.");
  4596. return NULL;
  4597. }
  4598. unsigned symCnt = va_cnt/2;
  4599. unsigned argCnt = 2 + 3*symCnt;
  4600. cmDspVarArg_t args[argCnt+1];
  4601. unsigned* symIdArray = cmMemAllocZ(unsigned,symCnt);
  4602. int* intArray = cmMemAllocZ(int,symCnt);
  4603. unsigned baseIntItsId = kBaseInItsId + symCnt;
  4604. unsigned baseOutItsId = baseIntItsId + symCnt;
  4605. // setup the integer input and symbol output port arg recd
  4606. cmDspArgSetup(ctx,args, "in", cmInvalidId, kInItsId, 0, 0, kInDsvFl | kIntDsvFl, "Integer input" );
  4607. cmDspArgSetup(ctx,args+1,"out", cmInvalidId, kOutItsId, 0, 0, kOutDsvFl | kSymDsvFl, "Output" );
  4608. unsigned i;
  4609. for(i=0; i<symCnt; ++i)
  4610. {
  4611. // get the integer value
  4612. intArray[i] = va_arg(vl,int);
  4613. // get the symbol label
  4614. const cmChar_t* symLabel = va_arg(vl,const char*);
  4615. assert( symLabel != NULL );
  4616. unsigned intLabelN = (symLabel==NULL ? 0 : strlen(symLabel)) + 5;
  4617. cmChar_t intLabel[ intLabelN ];
  4618. snprintf(intLabel,intLabelN,"%s%s", symLabel==NULL ? "" : symLabel, "-int" );
  4619. // register the symbol
  4620. symIdArray[i] = cmSymTblRegisterSymbol(ctx->stH,symLabel);
  4621. // trigger port associated with this symbol (any msg on this port will trigger an output)
  4622. cmDspArgSetup(ctx, args+kBaseInItsId+i, symLabel, cmInvalidId, kBaseInItsId+i, 0, 0, kInDsvFl | kTypeDsvMask, cmTsPrintfH(ctx->lhH,"%s Input.",symLabel) );
  4623. // this port is used to set the integer value associated with this symbol
  4624. cmDspArgSetup(ctx, args+baseIntItsId+i, intLabel, cmInvalidId, baseIntItsId+i, 0, 0, kInDsvFl | kIntDsvFl, cmTsPrintfH(ctx->lhH,"Set the integer value associated with %s.",symLabel) );
  4625. // symbol output port - when ever this symbol is sent out it will go out this port as well as the 'out' port
  4626. cmDspArgSetup(ctx, args+baseOutItsId+i, symLabel, cmInvalidId, baseOutItsId+i, 0, 0, kOutDsvFl | kSymDsvFl, cmTsPrintfH(ctx->lhH,"%s Output.",symLabel) );
  4627. }
  4628. cmDspArgSetupNull(args + argCnt);
  4629. cmDspIntToSym_t* p = cmDspInstAlloc(cmDspIntToSym_t,ctx,classPtr,args,instSymId,id,storeSymId,0,vl1);
  4630. p->symIdCnt = symCnt;
  4631. p->intArray = intArray;
  4632. p->symIdArray = symIdArray;
  4633. p->baseOutItsId = baseOutItsId;
  4634. p->baseIntItsId = baseIntItsId;
  4635. cmDspSetDefaultSymbol(ctx,&p->inst,kOutItsId,cmInvalidId);
  4636. va_end(vl1);
  4637. return &p->inst;
  4638. }
  4639. cmDspRC_t _cmDspIntToSym_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4640. {
  4641. cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst;
  4642. cmMemFree(p->symIdArray);
  4643. return kOkDspRC;
  4644. }
  4645. cmDspRC_t _cmDspIntToSym_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4646. {
  4647. return cmDspApplyAllDefaults(ctx,inst);
  4648. }
  4649. cmDspRC_t _cmDspIntToSymSendOut( cmDspCtx_t* ctx, cmDspInst_t* inst, unsigned idx )
  4650. {
  4651. cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst;
  4652. assert( idx < p->symIdCnt );
  4653. cmDspSetSymbol(ctx,inst,p->baseOutItsId + idx, p->symIdArray[idx]);
  4654. return cmDspSetSymbol(ctx, inst, kOutItsId, p->symIdArray[ idx ]);
  4655. }
  4656. cmDspRC_t _cmDspIntToSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4657. {
  4658. cmDspRC_t rc = kOkDspRC;
  4659. cmDspIntToSym_t* p = (cmDspIntToSym_t*)inst;
  4660. // if an integer arrived at 'in'
  4661. if( evt->dstVarId == kInItsId )
  4662. {
  4663. cmDspSetEvent(ctx,inst,evt);
  4664. unsigned i;
  4665. int intVal = cmDspInt(inst,kInItsId);
  4666. for(i=0; i<p->symIdCnt; ++i)
  4667. if( intVal == p->intArray[i] )
  4668. {
  4669. rc = _cmDspIntToSymSendOut( ctx, inst, i );
  4670. break;
  4671. }
  4672. }
  4673. else
  4674. {
  4675. // if a msg of any type is recieved on an input port - send out the associated symbol
  4676. if( kBaseInItsId <= evt->dstVarId && evt->dstVarId < kBaseInItsId + p->symIdCnt )
  4677. {
  4678. _cmDspIntToSymSendOut( ctx, inst, evt->dstVarId - kBaseInItsId );
  4679. }
  4680. else
  4681. // if this is a new interger value for this symbol
  4682. if( p->baseIntItsId <= evt->dstVarId && evt->dstVarId < p->baseIntItsId + p->symIdCnt )
  4683. {
  4684. cmDspSetEvent(ctx,inst,evt);
  4685. p->intArray[ evt->dstVarId - p->baseIntItsId ] = cmDspInt( inst, evt->dstVarId );
  4686. }
  4687. }
  4688. return rc;
  4689. }
  4690. cmDspClass_t* cmIntToSymClassCons( cmDspCtx_t* ctx )
  4691. {
  4692. cmDspClassSetup(&_cmIntToSym_DC,ctx,"IntToSym",
  4693. NULL,
  4694. _cmDspIntToSym_Alloc,
  4695. _cmDspIntToSym_Free,
  4696. _cmDspIntToSym_Reset,
  4697. NULL,
  4698. _cmDspIntToSym_Recv,
  4699. NULL,NULL,
  4700. "If a message of any kind is received on a port then send the symbol associated with the port.");
  4701. return &_cmIntToSym_DC;
  4702. }
  4703. //------------------------------------------------------------------------------------------------------------
  4704. //)
  4705. //( { label:cmDspRouter file_desc:"Route the input value to one of multiple output ports." kw:[sunit] }
  4706. enum
  4707. {
  4708. kOutChCntRtId,
  4709. kOutChIdxRtId,
  4710. kInFloatRtId,
  4711. kInBoolRtId,
  4712. kInSymRtId,
  4713. kInAudioRtId,
  4714. kBaseOutFloatRtId
  4715. };
  4716. cmDspClass_t _cmRouter_DC;
  4717. typedef struct
  4718. {
  4719. cmDspInst_t inst;
  4720. unsigned oChCnt;
  4721. unsigned oChIdx;
  4722. unsigned baseBaseOutRtId; // first data input port id
  4723. unsigned baseInFloatRtId;
  4724. unsigned baseInBoolRtId;
  4725. unsigned baseInSymRtId;
  4726. unsigned baseInAudioRtId;
  4727. unsigned baseOutFloatRtId;
  4728. unsigned baseOutBoolRtId;
  4729. unsigned baseOutSymRtId;
  4730. unsigned baseOutAudioRtId;
  4731. } cmDspRouter_t;
  4732. cmDspInst_t* _cmDspRouter_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4733. {
  4734. if( va_cnt < 1 )
  4735. {
  4736. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'Router' constructor must be given an output channel count.");
  4737. return NULL;
  4738. }
  4739. va_list vl1;
  4740. va_copy(vl1,vl);
  4741. int oChCnt = va_arg(vl,int);
  4742. unsigned baseOutFloatRtId = kBaseOutFloatRtId;
  4743. unsigned baseOutBoolRtId = baseOutFloatRtId + oChCnt;
  4744. unsigned baseOutSymRtId = baseOutBoolRtId + oChCnt;
  4745. unsigned baseOutAudioRtId = baseOutSymRtId + oChCnt;
  4746. cmDspRouter_t* p = cmDspInstAllocV(cmDspRouter_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  4747. 1, "ochs", kOutChCntRtId, 0, 0, kUIntDsvFl | kReqArgDsvFl,"Output channel count.",
  4748. 1, "sel", kOutChIdxRtId, 0, 0, kUIntDsvFl | kReqArgDsvFl | kInDsvFl, "Output channel index selector.",
  4749. 1, "f-in", kInFloatRtId, 0, 0, kDoubleDsvFl | kInDsvFl, "Float input",
  4750. 1, "b-in", kInBoolRtId, 0, 0, kBoolDsvFl | kInDsvFl, "Bool input",
  4751. 1, "s-in", kInSymRtId, 0, 0, kSymDsvFl | kInDsvFl, "Symbol input",
  4752. 1, "a-in", kInAudioRtId, 0, 0, kAudioBufDsvFl | kInDsvFl, "Audio input",
  4753. oChCnt, "f-out", baseOutFloatRtId, 0, 0, kDoubleDsvFl | kOutDsvFl, "Float output",
  4754. oChCnt, "b-out", baseOutBoolRtId, 0, 0, kBoolDsvFl | kOutDsvFl, "Bool output",
  4755. oChCnt, "s-out", baseOutSymRtId, 0, 0, kSymDsvFl | kOutDsvFl, "Symbol output",
  4756. oChCnt, "a-out", baseOutAudioRtId, 0, 1, kAudioBufDsvFl | kOutDsvFl, "Audio output",
  4757. 0 );
  4758. p->oChCnt = oChCnt;
  4759. p->baseBaseOutRtId = kBaseOutFloatRtId;
  4760. p->baseOutFloatRtId = baseOutFloatRtId;
  4761. p->baseOutBoolRtId = baseOutBoolRtId;
  4762. p->baseOutSymRtId = baseOutSymRtId;
  4763. p->baseOutAudioRtId = baseOutAudioRtId;
  4764. unsigned i;
  4765. for(i=0; i<oChCnt; ++i)
  4766. {
  4767. cmDspSetDefaultDouble( ctx, &p->inst, baseOutFloatRtId+i, 0.0, 0.0 );
  4768. cmDspSetDefaultBool( ctx, &p->inst, baseOutBoolRtId+i, false, false );
  4769. cmDspSetDefaultSymbol( ctx, &p->inst, baseOutSymRtId+i, cmInvalidId );
  4770. }
  4771. va_end(vl1);
  4772. return &p->inst;
  4773. }
  4774. cmDspRC_t _cmDspRouter_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4775. {
  4776. return kOkDspRC;
  4777. }
  4778. cmDspRC_t _cmDspRouter_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4779. {
  4780. cmDspRC_t rc = kOkDspRC;
  4781. cmDspRouter_t* p = (cmDspRouter_t*)inst;
  4782. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  4783. {
  4784. unsigned i;
  4785. for(i=0; i<p->oChCnt; ++i)
  4786. cmDspZeroAudioBuf(ctx,inst,p->baseOutAudioRtId+i);
  4787. }
  4788. return rc;
  4789. }
  4790. cmDspRC_t _cmDspRouter_Exec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4791. {
  4792. cmDspRC_t rc = kOkDspRC;
  4793. cmDspRouter_t* p = (cmDspRouter_t*)inst;
  4794. unsigned oChIdx = cmDspUInt(inst,kOutChIdxRtId);
  4795. cmSample_t* dp = cmDspAudioBuf(ctx,inst,p->baseOutAudioRtId + oChIdx,0);
  4796. const cmSample_t* sp = cmDspAudioBuf(ctx,inst,kInAudioRtId ,0);
  4797. unsigned n = cmDspAudioBufSmpCount(ctx,inst,p->baseOutAudioRtId,0);
  4798. if( dp != NULL )
  4799. {
  4800. if( sp == NULL )
  4801. cmVOS_Zero(dp,n);
  4802. else
  4803. cmVOS_Copy(dp,n,sp);
  4804. }
  4805. return rc;
  4806. }
  4807. cmDspRC_t _cmDspRouter_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4808. {
  4809. cmDspRC_t rc = kOkDspRC;
  4810. cmDspRouter_t* p = (cmDspRouter_t*)inst;
  4811. // ignore out of range output channel selection
  4812. if( evt->dstVarId == kOutChIdxRtId && cmDsvGetUInt(evt->valuePtr) >= p->oChCnt )
  4813. {
  4814. cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The selector channel index %i is out of of range.",cmDsvGetUInt(evt->valuePtr));
  4815. return kOkDspRC;
  4816. }
  4817. // if( evt->dstVarId == kOutChIdxRtId && cmDsvGetUInt(evt->valuePtr) < p->oChCnt )
  4818. // {
  4819. // const cmChar_t* symLbl = cmSymTblLabel(ctx->stH,inst->symId);
  4820. // cmDspInstErr(ctx,inst,kOkDspRC,"Router: ch:%i %s\n",cmDsvGetUInt(evt->valuePtr),symLbl==NULL?"":symLbl);
  4821. // }
  4822. // store the incoming value
  4823. if( evt->dstVarId < p->baseBaseOutRtId )
  4824. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  4825. return rc;
  4826. unsigned chIdx = cmDspUInt(inst,kOutChIdxRtId);
  4827. switch( evt->dstVarId )
  4828. {
  4829. case kInFloatRtId:
  4830. cmDspSetDouble(ctx,inst,p->baseOutFloatRtId + chIdx, cmDspDouble(inst,kInFloatRtId) );
  4831. break;
  4832. case kInBoolRtId:
  4833. cmDspSetBool(ctx,inst,p->baseOutBoolRtId + chIdx, cmDspBool(inst,kInBoolRtId) );
  4834. break;
  4835. case kInSymRtId:
  4836. cmDspSetSymbol(ctx,inst,p->baseOutSymRtId + chIdx, cmDspSymbol(inst,kInSymRtId));
  4837. break;
  4838. }
  4839. return rc;
  4840. }
  4841. cmDspClass_t* cmRouterClassCons( cmDspCtx_t* ctx )
  4842. {
  4843. cmDspClassSetup(&_cmRouter_DC,ctx,"Router",
  4844. NULL,
  4845. _cmDspRouter_Alloc,
  4846. _cmDspRouter_Free,
  4847. _cmDspRouter_Reset,
  4848. _cmDspRouter_Exec,
  4849. _cmDspRouter_Recv,
  4850. NULL,NULL,
  4851. "1 to N Router");
  4852. return &_cmRouter_DC;
  4853. }
  4854. //------------------------------------------------------------------------------------------------------------
  4855. //)
  4856. //( { label:cmDspAvailCh file_desc:"Track active an inactive processing channels." kw:[sunit] }
  4857. //
  4858. // Purpose: AvailCh can be used to implement a channel switching circuit.
  4859. //
  4860. // Inputs:
  4861. // chs - The count of channels. Constructor only argument.
  4862. // trig - Any input causes the next available channel, i, to be enabled.
  4863. // gate[i] transmits 'true'. In 'exclusive (0) mode all active
  4864. // channels are then requested to shutdown by transmitting 'false' on
  4865. // gate[] - only the new channel will be active. In 'multi' (1) mode
  4866. // no signal is sent out the gate[].
  4867. // dis[chCnt] - Recieves a gate signal from an external object which indicates
  4868. // when a channel is no longer active. When a 'false' is received on dis[i]
  4869. // the channel i is marked as available. In 'multi' mode 'false' is
  4870. // then transmitted on gate[i].
  4871. // Outputs:
  4872. // gate[chCnt] - 'true' is transmitted when a channel is made active (see trig)
  4873. // 'false' is transmitted to notify the channel that it should shutdown.
  4874. // The channel is not considered actually shutdown until dis[i]
  4875. // recieves a 'false'.
  4876. // ch The next prospective available channel is sent whenever it
  4877. // becomes available. A next channel becomes available when
  4878. // a channel is marked as inactive via dis[i] or when
  4879. // a new channel is made active, via trigger, and another
  4880. // channel active channel exists. Note that this channel is
  4881. // sent "prospectively" - possibly long before the associated
  4882. // gate[ch] is raised - in order to switch parameter routers away
  4883. // from the newly active channel and a currently in-active channel.
  4884. // Notes:
  4885. // The gate[] output is designed to work with the gate[] input of Xfader. When
  4886. // availCh.gate[] goes high Xfader fades in, when availCh.gate[] goes low
  4887. // Xfader fades out. The dis[] channel is designed to connect from Xfader.state[].
  4888. // Xfader.state[] goes low when a fade-out is complete, the connected AvailCh
  4889. // is then marked as available.
  4890. enum
  4891. {
  4892. kChCntAvId,
  4893. kModeAvId,
  4894. kTrigAvId,
  4895. kResetAvId,
  4896. kChIdxAvId,
  4897. kBaseDisInAvId,
  4898. kExclusiveModeAvId=0,
  4899. kMultiModeAvId=1
  4900. };
  4901. cmDspClass_t _cmAvailCh_DC;
  4902. typedef struct
  4903. {
  4904. cmDspInst_t inst;
  4905. unsigned chCnt;
  4906. unsigned baseDisInAvId;
  4907. unsigned baseGateOutAvId;
  4908. bool* stateArray;
  4909. unsigned nextAvailChIdx;
  4910. unsigned audioCycleCnt;
  4911. } cmDspAvailCh_t;
  4912. cmDspInst_t* _cmDspAvailCh_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  4913. {
  4914. if( va_cnt < 1 )
  4915. {
  4916. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'AvailCh' constructor must be given an channel count.");
  4917. return NULL;
  4918. }
  4919. va_list vl1;
  4920. va_copy(vl1,vl);
  4921. int chCnt = va_arg(vl,int);
  4922. if( chCnt <= 0 )
  4923. {
  4924. va_end(vl1);
  4925. cmDspClassErr(ctx,classPtr,kInvalidArgDspRC,"The 'AvailCh' constructor must be given a positive channel count.");
  4926. return NULL;
  4927. }
  4928. unsigned baseDisInAvId = kBaseDisInAvId;
  4929. unsigned baseGateOutAvId = baseDisInAvId + chCnt;
  4930. cmDspAvailCh_t* p = cmDspInstAllocV(cmDspAvailCh_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl1,
  4931. 1, "chs", kChCntAvId, 0, 0, kUIntDsvFl | kReqArgDsvFl, "Channel count.",
  4932. 1, "mode", kModeAvId, 0, 0, kUIntDsvFl | kInDsvFl, "Mode: 0=exclusive (dflt) 1=multi",
  4933. 1, "trig", kTrigAvId, 0, 0, kTypeDsvMask | kInDsvFl, "Trigger the unit to select the next available channel.",
  4934. 1, "reset", kResetAvId, 0, 0, kBoolDsvFl | kInDsvFl | kOutDsvFl, "Reset to default state",
  4935. 1, "ch", kChIdxAvId, 0, 0, kUIntDsvFl | kOutDsvFl, "Currently selected channel.",
  4936. chCnt, "dis", baseDisInAvId, 0, 0, kBoolDsvFl | kInDsvFl, "Disable channel gate",
  4937. chCnt, "gate", baseGateOutAvId, 0, 0, kBoolDsvFl | kOutDsvFl, "Active channel gate",
  4938. 0 );
  4939. p->chCnt = chCnt;
  4940. p->baseDisInAvId = baseDisInAvId;
  4941. p->baseGateOutAvId = baseGateOutAvId;
  4942. p->nextAvailChIdx = cmInvalidIdx;
  4943. p->audioCycleCnt = 0;
  4944. unsigned i;
  4945. for(i=0; i<chCnt; ++i)
  4946. {
  4947. cmDspSetDefaultBool( ctx, &p->inst, baseDisInAvId+i, false, false );
  4948. cmDspSetDefaultBool( ctx, &p->inst, baseGateOutAvId+i, false, false );
  4949. }
  4950. cmDspSetDefaultUInt( ctx, &p->inst, kModeAvId, 0, kExclusiveModeAvId );
  4951. cmDspSetDefaultUInt( ctx, &p->inst, kChIdxAvId, 0, 0 );
  4952. va_end(vl1);
  4953. return &p->inst;
  4954. }
  4955. cmDspRC_t _cmDspAvailCh_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4956. {
  4957. return kOkDspRC;
  4958. }
  4959. cmDspRC_t _cmDspAvailCh_DoReset( cmDspCtx_t* ctx, cmDspInst_t* inst )
  4960. {
  4961. unsigned i;
  4962. cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst;
  4963. // ch 0 is the channel receiving parameters
  4964. cmDspSetUInt(ctx,inst,kChIdxAvId,0);
  4965. for(i=0; i<p->chCnt; ++i)
  4966. {
  4967. cmDspSetBool(ctx, inst, p->baseDisInAvId + i, i==0); // disable all channels except ch zero
  4968. cmDspSetBool(ctx, inst, p->baseGateOutAvId + i, i==0); // enable channel 0
  4969. }
  4970. p->audioCycleCnt = 0;
  4971. p->nextAvailChIdx = cmInvalidIdx;
  4972. // transmit reset
  4973. cmDspSetBool(ctx,inst, kResetAvId, false );
  4974. return kOkDspRC;
  4975. }
  4976. cmDspRC_t _cmDspAvailCh_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  4977. {
  4978. cmDspRC_t rc;
  4979. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  4980. {
  4981. rc = _cmDspAvailCh_DoReset(ctx,inst);
  4982. }
  4983. return rc;
  4984. }
  4985. void _cmDspAvailCh_SetNextAvailCh( cmDspCtx_t* ctx, cmDspInst_t* inst, bool warnFl, const char* label )
  4986. {
  4987. cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst;
  4988. unsigned i;
  4989. // if a valid next avail ch already exists then do nothing
  4990. if( p->nextAvailChIdx != cmInvalidIdx )
  4991. return;
  4992. // for each channel
  4993. for(i=0; i<p->chCnt; ++i)
  4994. {
  4995. // the channel's active state is held in the 'dis' variable.
  4996. bool activeFl = cmDspBool(inst,p->baseDisInAvId+i);
  4997. // if ch[i] is the first avail inactive channel
  4998. if( !activeFl )
  4999. {
  5000. p->nextAvailChIdx = i; // then make it the next available channel
  5001. break;
  5002. }
  5003. }
  5004. // if no available channels were found
  5005. if( p->nextAvailChIdx == cmInvalidIdx )
  5006. {
  5007. if( warnFl )
  5008. cmDspInstErr(ctx,inst,kInvalidStateDspRC,"No available channels exist.");
  5009. }
  5010. else
  5011. {
  5012. // Notify the external world which channel is to be used next.
  5013. // This allows routers which are switching parameters between
  5014. // xfade channels to switch new parameter values to go to the
  5015. // next available channel rather than the current channel.
  5016. // The next available channel will then be faded up with the
  5017. // new parameters on the next trigger command.
  5018. cmDspSetUInt(ctx,inst,kChIdxAvId,p->nextAvailChIdx);
  5019. }
  5020. }
  5021. cmDspRC_t _cmDspAvailCh_Exec( cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5022. {
  5023. cmDspRC_t rc = kOkDspRC;
  5024. cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst;
  5025. p->audioCycleCnt += 1;
  5026. // Setting the next available channel here solves the problem of sending the
  5027. // first 'ch' output after the program starts executing.
  5028. // The problem is that 'ch' should be set to 0 for the first
  5029. // execution cycle so that parameters may be set to the initial active channel
  5030. // during the first cycle. After the first cycle however parameters should be
  5031. // sent to the next channel which will be faded up. Setting
  5032. // 'ch' here accomplishes this without relying on an external signal.
  5033. // Note that we wait until the second cycle because we don't know where
  5034. // this 'availCh' will be in the execution cycle relative to other processors.
  5035. // If it is at the beginning then other processors that might be setting
  5036. // initial parameters will not have had a chance to run before the
  5037. // 'ch' change. Waiting unitl the second cycle guarantees that all the
  5038. // other processors had at least one chance to run.
  5039. if( p->audioCycleCnt == 2 )
  5040. {
  5041. _cmDspAvailCh_SetNextAvailCh(ctx,inst,true,"exec");
  5042. }
  5043. return rc;
  5044. }
  5045. cmDspRC_t _cmDspAvailCh_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5046. {
  5047. cmDspRC_t rc = kOkDspRC;
  5048. cmDspAvailCh_t* p = (cmDspAvailCh_t*)inst;
  5049. bool exclModeFl = cmDspUInt(inst, kModeAvId ) == kExclusiveModeAvId;
  5050. // if this is a reset
  5051. if( evt->dstVarId == kResetAvId )
  5052. {
  5053. return _cmDspAvailCh_DoReset(ctx,inst);
  5054. }
  5055. // if this is a trigger
  5056. if( evt->dstVarId == kTrigAvId )
  5057. {
  5058. // if no available channels were previously found
  5059. if( p->nextAvailChIdx == cmInvalidIdx )
  5060. cmDspInstErr(ctx,inst,kInvalidStateDspRC,"There are no available channels to trigger.");
  5061. else
  5062. {
  5063. // indicate that ch[nexAvailChIdx] is no longer available
  5064. cmDspSetBool(ctx, inst, p->baseDisInAvId + p->nextAvailChIdx, true);
  5065. // raise the gate to start the xfade.
  5066. cmDspSetBool(ctx, inst, p->baseGateOutAvId + p->nextAvailChIdx, true);
  5067. if( exclModeFl )
  5068. {
  5069. unsigned i;
  5070. for(i=0; i<p->chCnt; ++i)
  5071. if( i!=p->nextAvailChIdx && cmDspBool(inst,p->baseDisInAvId+i) )
  5072. cmDspSetBool(ctx,inst, p->baseGateOutAvId+i, false );
  5073. }
  5074. // invalidate nextAvailChIdx
  5075. p->nextAvailChIdx = cmInvalidIdx;
  5076. // It may be possible to know the next avail ch so try to set it here.
  5077. _cmDspAvailCh_SetNextAvailCh(ctx, inst, false, "trig" );
  5078. }
  5079. return rc;
  5080. }
  5081. // if this is an incoming disable message.
  5082. if( p->baseDisInAvId <= evt->dstVarId && evt->dstVarId < p->baseDisInAvId+p->chCnt && cmDsvGetBool(evt->valuePtr) == false)
  5083. {
  5084. cmDspSetEvent(ctx,inst,evt);
  5085. // a channel was disabled so a new channel should be available for selection
  5086. if( p->audioCycleCnt > 0 )
  5087. _cmDspAvailCh_SetNextAvailCh(ctx, inst, true, "dis" );
  5088. if( !exclModeFl )
  5089. cmDspSetBool(ctx, inst, p->baseGateOutAvId + (evt->dstVarId - p->baseDisInAvId), false);
  5090. }
  5091. return rc;
  5092. }
  5093. cmDspClass_t* cmAvailChClassCons( cmDspCtx_t* ctx )
  5094. {
  5095. cmDspClassSetup(&_cmAvailCh_DC,ctx,"AvailCh",
  5096. NULL,
  5097. _cmDspAvailCh_Alloc,
  5098. _cmDspAvailCh_Free,
  5099. _cmDspAvailCh_Reset,
  5100. _cmDspAvailCh_Exec,
  5101. _cmDspAvailCh_Recv,
  5102. NULL,NULL,
  5103. "Enable the next availabled channel");
  5104. return &_cmAvailCh_DC;
  5105. }
  5106. //------------------------------------------------------------------------------------------------------------
  5107. //)
  5108. //( { label:cmDspPreset file_desc:"Store and recall preset. Show a preset list user interface unit." kw:[sunit] }
  5109. enum
  5110. {
  5111. kGroupSymPrId,
  5112. kLabelPrId,
  5113. kCmdPrId,
  5114. kDonePrId,
  5115. kListPrId,
  5116. kSelPrId
  5117. };
  5118. cmDspClass_t _cmPreset_DC;
  5119. typedef struct
  5120. {
  5121. cmDspInst_t inst;
  5122. unsigned storeCmdSymId;
  5123. unsigned recallCmdSymId;
  5124. unsigned doneSymId;
  5125. cmJsonH_t jsH;
  5126. cmJsonNode_t* np;
  5127. } cmDspPreset_t;
  5128. cmDspRC_t _cmDspPresetUpdateList( cmDspCtx_t* ctx, cmDspPreset_t* p, unsigned groupSymId )
  5129. {
  5130. cmDspRC_t rc = kOkDspRC;
  5131. // initialize the JSON tree
  5132. if( cmJsonInitialize(&p->jsH,ctx->cmCtx) != kOkJsRC )
  5133. {
  5134. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"JSON preset list handle initialization failed.");
  5135. goto errLabel;
  5136. }
  5137. // create the JSON tree root container
  5138. if( cmJsonCreateObject(p->jsH,NULL) == NULL )
  5139. {
  5140. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"JSON preset list root object create failed.");
  5141. goto errLabel;
  5142. }
  5143. // if a valid preset group symbol was given
  5144. if( groupSymId != cmInvalidId )
  5145. {
  5146. // get the JSON list containing the preset labels and symId's for this preset group
  5147. if( cmDspSysPresetPresetJsonList(ctx->dspH, groupSymId, &p->jsH ) != kOkDspRC )
  5148. {
  5149. rc = cmDspInstErr(ctx,&p->inst,kSubSysFailDspRC,"Request for a preset list failed.");
  5150. goto errLabel;
  5151. }
  5152. // get a pointer to the JSON 'presetArray' array node
  5153. if(( p->np = cmJsonFindValue(p->jsH,"presetArray",NULL,kArrayTId)) == NULL )
  5154. {
  5155. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"Preset list is empty or synatax is not recognized.");
  5156. goto errLabel;
  5157. }
  5158. // set the JSON list
  5159. if((rc = cmDspSetJson(ctx,&p->inst,kListPrId,p->np)) != kOkDspRC )
  5160. {
  5161. rc = cmDspInstErr(ctx,&p->inst,rc,"Preset list set failed.");
  5162. goto errLabel;
  5163. }
  5164. }
  5165. errLabel:
  5166. return rc;
  5167. }
  5168. cmDspRC_t _cmDspPresetDoRecall( cmDspCtx_t* ctx, cmDspPreset_t* p, const cmChar_t* groupLabel, const cmChar_t* presetLabel )
  5169. {
  5170. cmDspRC_t rc;
  5171. // recall the preset
  5172. if(( rc = cmDspSysPresetRecall(ctx->dspH, groupLabel, presetLabel )) != kOkDspRC )
  5173. return cmDspInstErr(ctx,&p->inst,kSubSysFailDspRC,"Preset recall failed for group:'%s' preset:'%s'.",cmStringNullGuard(groupLabel),cmStringNullGuard(presetLabel));
  5174. // send out a notification that a new preset has been loaded
  5175. return cmDspSetSymbol(ctx,&p->inst,kDonePrId,p->doneSymId);
  5176. }
  5177. // selIdx is base 1, not base 0, because it references the JSON tree rows where the
  5178. // first row contains the titles.
  5179. cmDspRC_t _cmDspPresetListSelectRecall( cmDspCtx_t* ctx, cmDspPreset_t* p, unsigned selIdx )
  5180. {
  5181. cmDspRC_t rc = kOkDspRC;
  5182. const cmChar_t* presetLabel;
  5183. const cmChar_t* groupLabel;
  5184. unsigned groupSymId;
  5185. unsigned presetSymId;
  5186. const cmJsonNode_t* rnp;
  5187. // validate the JSON tree
  5188. if( cmJsonIsValid(p->jsH) == false || p->np == NULL )
  5189. {
  5190. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"Preset recall failed. The preset JSON tree does not exist.");
  5191. goto errLabel;
  5192. }
  5193. // validate the group id
  5194. if( (groupSymId = cmDspSymbol(&p->inst,kGroupSymPrId)) == cmInvalidId )
  5195. {
  5196. rc = cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"Preset recall failed. The preset group symbol has not been set.");
  5197. goto errLabel;
  5198. }
  5199. // validate the selection index
  5200. if( selIdx >= cmJsonChildCount(p->np) )
  5201. {
  5202. rc = cmDspInstErr(ctx,&p->inst,kVarNotValidDspRC,"Preset recall failed. The preset index: %i is out of range 0-%i", selIdx, cmJsonChildCount(p->np));
  5203. goto errLabel;
  5204. }
  5205. // get the preset element
  5206. if(( rnp = cmJsonArrayElementC(p->np, selIdx )) == NULL )
  5207. {
  5208. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"Preset recall failed. Unable to retrieve preset JSON element.");
  5209. goto errLabel;
  5210. }
  5211. // verify the JSON syntax
  5212. assert( rnp->typeId==kArrayTId && cmJsonChildCount(rnp)==2 && cmJsonArrayElementC(rnp,1)->typeId == kIntTId );
  5213. // get the preset symbol id
  5214. if( cmJsonUIntValue( cmJsonArrayElementC(rnp,1), &presetSymId ) != kOkJsRC )
  5215. {
  5216. rc = cmDspInstErr(ctx,&p->inst,kJsonFailDspRC,"Preset recall failed. Unable to retrieve preset symbol id.");
  5217. goto errLabel;
  5218. }
  5219. // convert symbols to strings
  5220. groupLabel = cmSymTblLabel(ctx->stH,groupSymId);
  5221. presetLabel = cmSymTblLabel(ctx->stH,presetSymId);
  5222. rc = _cmDspPresetDoRecall(ctx,p,groupLabel,presetLabel);
  5223. errLabel:
  5224. return rc;
  5225. }
  5226. cmDspInst_t* _cmDspPreset_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  5227. {
  5228. cmDspPreset_t* p = cmDspInstAllocV(cmDspPreset_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  5229. 1, "sym", kGroupSymPrId, 0, 0, kInDsvFl | kSymDsvFl | kReqArgDsvFl, "Preset group symbol.",
  5230. 1, "label", kLabelPrId, 0, 0, kInDsvFl | kStrzDsvFl | kOptArgDsvFl, "Preset label",
  5231. 1, "cmd", kCmdPrId, 0, 0, kInDsvFl | kSymDsvFl, "Command input",
  5232. 1, "done", kDonePrId, 0, 0, kOutDsvFl | kSymDsvFl, "Send 'done' symbol after preset recall.",
  5233. 1, "list", kListPrId, 0, 0, kInDsvFl | kJsonDsvFl, "Preset list as a JSON array.",
  5234. 1, "sel", kSelPrId, 0, 0, kInDsvFl | kUIntDsvFl, "Preset index selection index",
  5235. 0 );
  5236. p->jsH = cmJsonNullHandle;
  5237. p->np = NULL;
  5238. p->storeCmdSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"store");
  5239. p->recallCmdSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"recall");
  5240. p->doneSymId = cmSymTblRegisterStaticSymbol(ctx->stH,"done");
  5241. cmDspSetDefaultBool( ctx, &p->inst, kDonePrId,false,false);
  5242. cmDspSetDefaultSymbol( ctx, &p->inst, kGroupSymPrId, cmInvalidId);
  5243. cmDspSetDefaultStrcz( ctx, &p->inst, kLabelPrId, NULL,"");
  5244. unsigned height = 5;
  5245. cmDspUiMsgListCreate(ctx, &p->inst, height, kListPrId, kSelPrId );
  5246. return &p->inst;
  5247. }
  5248. cmDspRC_t _cmDspPreset_Free(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5249. {
  5250. cmDspPreset_t* p = (cmDspPreset_t*)inst;
  5251. cmJsonFinalize(&p->jsH);
  5252. return kOkDspRC;
  5253. }
  5254. cmDspRC_t _cmDspPreset_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5255. {
  5256. cmDspRC_t rc;
  5257. cmDspPreset_t* p = (cmDspPreset_t*)inst;
  5258. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  5259. {
  5260. _cmDspPresetUpdateList(ctx, p, cmDspSymbol(inst,kGroupSymPrId) );
  5261. }
  5262. return rc;
  5263. }
  5264. cmDspRC_t _cmDspPreset_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5265. {
  5266. cmDspRC_t rc = kOkDspRC;
  5267. cmDspPreset_t* p = (cmDspPreset_t*)inst;
  5268. switch( evt->dstVarId )
  5269. {
  5270. case kListPrId:
  5271. return rc; // we don't yet handle lists arriving by the input port
  5272. case kSelPrId:
  5273. {
  5274. // sel idx is base 1 because the first row in the msg list contains the titles
  5275. unsigned selIdx = cmDsvGetUInt(evt->valuePtr);
  5276. if((rc = _cmDspPresetListSelectRecall(ctx,p,selIdx)) != kOkDspRC)
  5277. return rc;
  5278. }
  5279. break;
  5280. }
  5281. if((rc = cmDspSetEvent(ctx,inst,evt)) != kOkDspRC )
  5282. return rc;
  5283. // if this is a store or recall command
  5284. if( evt->dstVarId == kCmdPrId )
  5285. {
  5286. unsigned cmdSymId = cmDspSymbol(inst,kCmdPrId);
  5287. if( cmdSymId == p->storeCmdSymId || cmdSymId==p->recallCmdSymId )
  5288. {
  5289. unsigned groupSymId;
  5290. const cmChar_t* groupLabel;
  5291. const cmChar_t* presetLabel;
  5292. // get the group symbol
  5293. if((groupSymId = cmDspSymbol(inst,kGroupSymPrId)) == cmInvalidId )
  5294. return cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The preset group symbol id is not set.");
  5295. // get the group label
  5296. if((groupLabel = cmSymTblLabel(ctx->stH,groupSymId)) == NULL )
  5297. return cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The preset group label was not found.");
  5298. // get the preset label
  5299. if(( presetLabel = cmDspStrcz(inst,kLabelPrId)) == NULL || strlen(presetLabel)==0 )
  5300. return cmDspInstErr(ctx,inst,kVarNotValidDspRC,"The preset label was not set.");
  5301. // if this is a store command
  5302. if( cmdSymId == p->storeCmdSymId )
  5303. {
  5304. // create a new preset
  5305. if((rc = cmDspSysPresetCreate(ctx->dspH,groupLabel, presetLabel)) != kOkDspRC )
  5306. return cmDspInstErr(ctx,inst,kSubSysFailDspRC,"Preset create failed for group:'%s' preset:'%s'.",cmStringNullGuard(groupLabel),cmStringNullGuard(presetLabel));
  5307. // update the list with the new preset
  5308. rc = _cmDspPresetUpdateList(ctx, p, groupSymId );
  5309. }
  5310. else // otherwise this must be a recall command
  5311. {
  5312. rc = _cmDspPresetDoRecall(ctx,p,groupLabel, presetLabel);
  5313. }
  5314. }
  5315. }
  5316. return rc;
  5317. }
  5318. cmDspClass_t* cmPresetClassCons( cmDspCtx_t* ctx )
  5319. {
  5320. cmDspClassSetup(&_cmPreset_DC,ctx,"Preset",
  5321. NULL,
  5322. _cmDspPreset_Alloc,
  5323. _cmDspPreset_Free,
  5324. _cmDspPreset_Reset,
  5325. NULL,
  5326. _cmDspPreset_Recv,
  5327. NULL,NULL,
  5328. "Preset Manager");
  5329. return &_cmPreset_DC;
  5330. }
  5331. //------------------------------------------------------------------------------------------------------------
  5332. //)
  5333. //( { label:cmDspBcastSym file_desc:"Broadcast a symbol/value to all units registered to listen for the symbol." kw:[sunit] }
  5334. enum
  5335. {
  5336. kAttrBcId,
  5337. kMsgBcId
  5338. };
  5339. cmDspClass_t _cmBcastSym_DC;
  5340. typedef struct
  5341. {
  5342. cmDspInst_t inst;
  5343. unsigned onSymId;
  5344. unsigned offSymId;
  5345. } cmDspBcastSym_t;
  5346. cmDspInst_t* _cmDspBcastSym_Alloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  5347. {
  5348. cmDspBcastSym_t* p = cmDspInstAllocV(cmDspBcastSym_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  5349. 1, "attr", kAttrBcId, 0, 0, kSymDsvFl | kInDsvFl | kOptArgDsvFl, "Instance which have this attribute symbol will receive the message.",
  5350. 1, "msg", kMsgBcId, 0, 0, kTypeDsvMask | kInDsvFl, "Msg to broadcast.",
  5351. 0 );
  5352. cmDspSetDefaultSymbol( ctx, &p->inst, kAttrBcId, cmInvalidId );
  5353. return &p->inst;
  5354. }
  5355. cmDspRC_t _cmDspBcastSym_Reset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5356. {
  5357. cmDspRC_t rc = kOkDspRC;
  5358. if((rc = cmDspApplyAllDefaults(ctx,inst)) == kOkDspRC )
  5359. {
  5360. }
  5361. return rc;
  5362. }
  5363. cmDspRC_t _cmDspBcastSym_Recv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5364. {
  5365. cmDspRC_t rc = kOkDspRC;
  5366. if( evt->dstVarId == kAttrBcId )
  5367. return cmDspSetEvent(ctx,inst,evt);
  5368. if( evt->dstVarId == kMsgBcId )
  5369. {
  5370. unsigned attrSymId = cmDspSymbol(inst,kAttrBcId);
  5371. if( cmDsvIsSymbol(evt->valuePtr) )
  5372. {
  5373. printf("bcast: %i %s\n",attrSymId,cmSymTblLabel(ctx->stH,cmDsvSymbol(evt->valuePtr)));
  5374. }
  5375. return cmDspSysBroadcastValue(ctx->dspH, attrSymId, evt->valuePtr );
  5376. }
  5377. return rc;
  5378. }
  5379. cmDspClass_t* cmBcastSymClassCons( cmDspCtx_t* ctx )
  5380. {
  5381. cmDspClassSetup(&_cmBcastSym_DC,ctx,"BcastSym",
  5382. NULL,
  5383. _cmDspBcastSym_Alloc,
  5384. NULL,
  5385. _cmDspBcastSym_Reset,
  5386. NULL,
  5387. _cmDspBcastSym_Recv,
  5388. NULL,NULL,
  5389. "Set one input high and all others low.");
  5390. return &_cmBcastSym_DC;
  5391. }
  5392. //------------------------------------------------------------------------------------------------------------
  5393. //)
  5394. //( { label:cmDspSegLine file_desc:"Line segment generator." kw:[sunit] }
  5395. enum
  5396. {
  5397. kRsrcSlId,
  5398. kCmdSlId,
  5399. kTrigSlId,
  5400. kOutSlId,
  5401. };
  5402. cmDspClass_t _cmSegLineDC;
  5403. typedef struct
  5404. {
  5405. cmDspInst_t inst;
  5406. double* x; // x[n]
  5407. unsigned n;
  5408. unsigned i; // current segment
  5409. unsigned m; // cur cnt
  5410. } cmDspSegLine_t;
  5411. cmDspInst_t* _cmDspSegLineAlloc(cmDspCtx_t* ctx, cmDspClass_t* classPtr, unsigned storeSymId, unsigned instSymId, unsigned id, unsigned va_cnt, va_list vl )
  5412. {
  5413. cmDspSegLine_t* p = cmDspInstAllocV(cmDspSegLine_t,ctx,classPtr,instSymId,id,storeSymId,va_cnt,vl,
  5414. 1, "rsrc", kRsrcSlId, 0, 0, kInDsvFl | kStrzDsvFl | kReqArgDsvFl, "Name of resource array.",
  5415. 1, "cmd", kCmdSlId, 0, 0, kInDsvFl | kSymDsvFl, "Command",
  5416. 1, "trig", kTrigSlId, 0, 0, kInDsvFl | kTypeDsvMask, "Trigger",
  5417. 1, "out", kOutSlId, 0, 0, kOutDsvFl | kDoubleDsvFl, "Output",
  5418. 0 );
  5419. if( p == NULL )
  5420. return NULL;
  5421. // The array is expected to contain interleaved values:
  5422. // cnt_0, val_0, cnt_1, val_1 .... cnt_n val_n
  5423. // The 'cnt_x' values give the count of trigger values upon which the output will be 'val_x'.
  5424. if( cmDspRsrcDblArray(ctx->dspH,&p->n,&p->x,cmDspDefaultStrcz(&p->inst,kRsrcSlId),NULL) != kOkDspRC )
  5425. {
  5426. cmDspClassErr(ctx,classPtr,kVarArgParseFailDspRC,"The 'SegLine' constructor resource array could not be read.");
  5427. return NULL;
  5428. }
  5429. cmDspSetDefaultDouble( ctx, &p->inst, kOutSlId, 0.0, p->n >= 2 ? p->x[1] : 0.0 );
  5430. p->i = 0;
  5431. p->m = 0;
  5432. return &p->inst;
  5433. }
  5434. cmDspRC_t _cmDspSegLineReset(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5435. {
  5436. cmDspSegLine_t* p = (cmDspSegLine_t*)inst;
  5437. p->i = 0;
  5438. p->m = 0;
  5439. return cmDspApplyAllDefaults(ctx,inst);
  5440. }
  5441. cmDspRC_t _cmDspSegLineRecv(cmDspCtx_t* ctx, cmDspInst_t* inst, const cmDspEvt_t* evt )
  5442. {
  5443. cmDspRC_t rc = kOkDspRC;
  5444. cmDspSegLine_t* p = (cmDspSegLine_t*)inst;
  5445. if((rc = cmDspSetEvent(ctx,inst,evt)) == kOkDspRC )
  5446. {
  5447. switch( evt->dstVarId )
  5448. {
  5449. case kTrigSlId:
  5450. {
  5451. double val = cmDspDouble(inst,kOutSlId);
  5452. if( p->i < p->n )
  5453. {
  5454. if( p->m >= p->x[p->i] )
  5455. p->i += 2;
  5456. if( p->i < p->n )
  5457. {
  5458. double x0 = p->x[p->i-2];
  5459. double y0 = p->x[p->i-1];
  5460. double x1 = p->x[p->i+0];
  5461. double y1 = p->x[p->i+1];
  5462. double dx = x1 - x0;
  5463. double dy = y1 - y0;
  5464. val = y0 + (p->m - x0) * dy / dx;
  5465. printf("i:%i m=%i x0:%f y0:%f x1:%f y1:%f : %f\n",p->i,p->m,x0,y0,x1,y1,val);
  5466. }
  5467. else
  5468. {
  5469. val = p->x[p->n-1];
  5470. }
  5471. ++p->m;
  5472. }
  5473. cmDspSetDouble(ctx,inst,kOutSlId,val);
  5474. }
  5475. break;
  5476. case kCmdSlId:
  5477. p->i = 0;
  5478. p->m = 0;
  5479. break;
  5480. }
  5481. }
  5482. return rc;
  5483. }
  5484. cmDspClass_t* cmSegLineClassCons( cmDspCtx_t* ctx )
  5485. {
  5486. cmDspClassSetup(&_cmSegLineDC,ctx,"SegLine",
  5487. NULL,
  5488. _cmDspSegLineAlloc,
  5489. NULL,
  5490. _cmDspSegLineReset,
  5491. NULL,
  5492. _cmDspSegLineRecv,
  5493. NULL,NULL,
  5494. "SegLine");
  5495. return &_cmSegLineDC;
  5496. }
  5497. //)