1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673 |
- #include "cmPrefix.h"
- #include "cmGlobal.h"
- #include "cmRpt.h"
- #include "cmErr.h"
- #include "cmCtx.h"
- #include "cmMem.h"
- #include "cmMallocDebug.h"
- #include "cmLinkedHeap.h"
- #include "cmSymTbl.h"
- #include "cmFloatTypes.h"
- #include "cmComplexTypes.h"
- #include "cmFileSys.h"
- #include "cmJson.h"
- #include "cmProcObj.h"
- #include "cmProcTemplate.h"
- #include "cmAudioFile.h"
- #include "cmMath.h"
- #include "cmProc.h"
- #include "cmVectOps.h"
- #include "cmProc3.h"
- #include "cmTime.h"
- #include "cmMidi.h" // cmMidiToSciPitch();
-
- cmPitchShift* cmPitchShiftAlloc( cmCtx* c, cmPitchShift* p, unsigned procSmpCnt, cmReal_t srate )
- {
- cmPitchShift* op = cmObjAlloc(cmPitchShift, c, p );
- if( procSmpCnt != 0 )
- if( cmPitchShiftInit(op, procSmpCnt,srate) != cmOkRC )
- cmPitchShiftFree(&op);
- return op;
- }
-
- cmRC_t cmPitchShiftFinal(cmPitchShift* p )
- { return cmOkRC; }
-
- #define _cube_interp(x,y0,y1,y2,y3) ((y3) - (y2) - (y0) + (y1))*(x)*(x)*(x) + ((y0) - (y1) - ((y3) - (y2) - (y0) + (y1)))*(x)*(x) + ((y2) - (y0))*(x) + (y1)
- #define _lin_interp(x,y0,y1) (y0) + (x) * ((y1)-(y0))
-
-
- /*
- cmRC_t cmPitchShiftFree( cmPitchShift** pp )
- {
- cmRC_t rc = cmOkRC;
- if( pp != NULL && *pp != NULL )
- {
- cmPitchShift* p = *pp;
- if(( rc = cmPitchShiftFinal(p)) == cmOkRC )
- {
- cmMemPtrFree(&p->x);
- cmMemPtrFree(&p->y);
- cmMemPtrFree(&p->cf);
- cmObjFree(pp);
- }
- }
- return rc;
- }
-
-
- cmRC_t cmPitchShiftInit( cmPitchShift* p, unsigned procSmpCnt, double srate )
- {
- cmRC_t rc;
- if((rc = cmPitchShiftFinal(p)) != cmOkRC )
- return rc;
-
- p->procSmpCnt = procSmpCnt;
- p->srate = srate;
- p->wn = 4096;
- p->cfn = 1024;
- p->outN = p->procSmpCnt;
- p->x = cmMemResizeZ(cmSample_t, p->x,procSmpCnt + 3 );
- p->y = cmMemResizeZ(cmSample_t, p->y, p->wn );
- p->cf = cmMemResizeZ(cmSample_t, p->cf, p->cfn );
- p->pii = procSmpCnt + p->cfn;
- p->poi = 0;
- p->outV = p->y;
- p->prv_x0 = 0;
- p->prv_x1 = 0;
- p->genFl = true;
- p->xfi = 3;
- p->cfi = 0;
- p->cubeFl = true;
- p->linCfFl = true;
-
- assert( p->cfn+p->procSmpCnt < p->wn );
-
- unsigned i;
- for(i=0; i<p->cfn; ++i)
- {
- p->cf[i] = (sin(((double)i/p->cfn * M_PI) - (M_PI/2.0)) + 1.0) / 2.0;
- p->cf[i] = (double)i/p->cfn;
- }
- return rc;
- }
-
-
- // Algorithm:
- // 1. Generate srate converted values into p->y[] until it is full.
- // 2. Playback from y[] ignoring any incoming samples until less than
- // p->cfn + p->procSmpCnt samples remain in y[] (i.e. pii < procSmpCnt + cfn).
- // 3. At this point begin generating samples from the input and crossfading them
- // with the last cfn samples in y[].
- // 4. After cfn new samples have been crossfaded proceed to fill the remaining
- // space in y[]
- // 5. Goto 2.
- //
- // Note that since we are pitch shifting down (ratio<1.0) the number of samples generated
- // will always be greater than the number of input samples.
- //
- // Notes:
- // For small downward shifts there will be large time aliasing because the length of time
- // to fill the buffer (step 4) will because only a few extra samples
- // are generated on each input cycle. Try decreasing the window length as the pitch ratio increases.
- //
- // Implement smoothly varying ratio changes.
- //
- // Change model so that at ratio 1.0 the input is effectively being constantly cross faded to produce
- // identity output.
-
-
- void _cmPitchShiftDown( cmPitchShift* p, double ratio, const cmSample_t* x, unsigned xn )
- {
- // shift off the expired samples
- memmove(p->y,p->y + p->procSmpCnt, (p->pii - p->procSmpCnt) * sizeof(cmSample_t));
- p->pii -= p->procSmpCnt;
-
- // if not currently generating and there are less than cfn + procSmpCnt samples remaining ...
- if( p->genFl == false && p->pii <= p->procSmpCnt + p->cfn )
- {
- // ... then setup to begin generating
- p->cfi = 0;
- p->genFl = true;
- p->xfi = 3;
- }
-
- if( p->genFl )
- {
- // setup the incoming samples
- p->x[0] = p->prv_x0;
- p->x[1] = p->prv_x1;
- p->x[2] = p->prv_x2;
- memcpy(p->x+2,x,p->procSmpCnt*sizeof(cmSample_t));
-
- int n0 = p->cubeFl ? xn+1 : xn+2;
-
- // as long as there are incoming samples available and space left in the output buffer
- for(; p->xfi < n0 && p->pii < p->wn; p->xfi += ratio )
- {
- unsigned xii = floor(p->xfi);
- double frac = p->xfi - xii;
-
- // generate the value of the output sample
- cmSample_t value;
- if( p->cubeFl )
- value = _cube_interp(frac,p->x[xii-1],p->x[xii],p->x[xii+1],p->x[xii+2]);
- else
- value = p->x[ xii ] + frac * (p->x[ xii+1 ] - p->x[xii]);
-
- // if xfading
- if( p->cfi < p->cfn )
- {
- // calc index into y[] of the sample to crossfade with
- int idx = p->pii - p->cfn + p->cfi;
-
- p->y[idx] = (1.0 - p->cf[p->cfi]) * p->y[idx] + p->cf[p->cfi] * value;
- ++p->cfi;
- }
- else
- {
- // else fill the remaing space in y[]
- p->y[p->pii] = value;
- ++p->pii;
- }
-
- }
-
- // if the output buffer is full then stop generating
- if( p->pii == p->wn )
- p->genFl = false;
- }
-
- // reset the input index to the beginning of the buffer
- p->xfi -= xn;
-
- p->prv_x0 = x[xn-3];
- p->prv_x1 = x[xn-2];
- p->prv_x2 = x[xn-1];
-
- }
-
-
- cmRC_t cmPitchShiftExec( cmPitchShift* p, const cmSample_t* x, cmSample_t* y, unsigned n, double shiftRatio )
- {
- assert(n == p->procSmpCnt);
-
- if( shiftRatio >= 1 )
- memcpy(y,x,n*sizeof(cmSample_t));
- else
- {
- _cmPitchShiftDown(p,shiftRatio,x,n);
- if( y != NULL )
- memcpy(y,p->y,n*sizeof(cmSample_t));
- }
- return cmOkRC;
- }
- */
-
- cmRC_t cmPitchShiftFree( cmPitchShift** pp )
- {
- cmRC_t rc = cmOkRC;
- if( pp != NULL && *pp != NULL )
- {
- cmPitchShift* p = *pp;
- if(( rc = cmPitchShiftFinal(p)) == cmOkRC )
- {
- cmMemPtrFree(&p->b);
- cmMemPtrFree(&p->outV);
- cmMemPtrFree(&p->wnd);
- cmMemPtrFree(&p->osc[0].y);
- cmMemPtrFree(&p->osc[1].y);
- cmObjFree(pp);
- }
- }
- return rc;
- }
-
- /*
-
- cmRC_t cmPitchShiftInit( cmPitchShift* p, unsigned procSmpCnt, double srate)
- {
- cmRC_t rc;
-
- if((rc = cmPitchShiftFinal(p)) != cmOkRC )
- return rc;
-
- p->procSmpCnt = procSmpCnt;
- p->srate = srate;
- p->wn = 4096;
- p->in = 2*p->wn + p->procSmpCnt;
- p->outN = p->procSmpCnt;
- p->m = cmMemResizeZ(cmSample_t, p->m,p->in + 2 );
- p->x = p->m + 1;
- p->outV = cmMemResizeZ(cmSample_t, p->outV,procSmpCnt );
- p->wnd = cmMemResizeZ(cmSample_t, p->wnd, p->wn+1 );
- p->ii = 1;
- p->cubeFl = true;
- p->ei0 = -1;
- p->ei1 = -1;
-
- p->osc[0].ratio = 1.0;
- p->osc[0].wi = 0;
- p->osc[0].xi = 0;
- p->osc[0].yN = 2*p->wn;
- p->osc[0].y = cmMemResizeZ(cmSample_t, p->osc[0].y, p->osc[0].yN );
- p->osc[0].yii = 0;
- p->osc[0].yoi = 0;
- p->osc[0].ynn = 0;
-
- p->osc[1].ratio = 1.0;
- p->osc[1].wi = floor(p->wn/2);
- p->osc[1].xi = 0;
- p->osc[1].yN = 2*p->wn;
- p->osc[1].y = cmMemResizeZ(cmSample_t, p->osc[1].y, p->osc[1].yN );
- p->osc[1].yii = 0;
- p->osc[1].yoi = 0;
- p->osc[1].ynn = 0;
-
- assert( p->in >= p->procSmpCnt + 1 );
-
- cmVOS_Hann( p->wnd, p->wn+1 );
-
- return rc;
- }
-
- #define _isInNoGoZone(p,i) ( ((0 <= (i)) && ((i) <= (p)->ei0)) || (((p)->ii <= (i)) && ((i) <= (p)->ei1)) )
-
- #define _isNotInNoGoZone(p,i) (!_isInNoGoZone(p,i))
-
- void _startNewWindow( cmPitchShift* p, cmPitchShiftOsc_t* op, int li, double ratio)
- {
- op->wi = 0;
-
- if( op->ratio < 1.0 )
- op->xi = p->ii - p->procSmpCnt;
- else
- op->xi = p->ii + (li)*(p->procSmpCnt/ratio);
-
- while( op->xi < 0 )
- op->xi += p->in-1;
-
- while( op->xi > (p->in-1) )
- op->xi -= (p->in-1);
-
- op->xi = floor(op->xi);
-
- }
-
- void _cmPitchShiftOsc( cmPitchShift* p, cmPitchShiftOsc_t* op, double ratio )
- {
- int li = 0;
- bool contFl = 1;
-
- // if we are waiting to start a new window until the output buffer drains
- if( op->wi==-1 )
- {
- // if the output buffer has enough samples to complete this cycle - return
- if(op->ynn >= p->procSmpCnt)
- return;
-
- // otherwise start a new window
- _startNewWindow(p,op,li,ratio);
-
- }
-
- // iterate until all output samples have been generated
- for(li=0; contFl; ++li)
- {
- // iterate over one window or until output is complete
- while( op->wi < p->wn )
- {
- int wii = floor(op->wi);
- double frac = op->wi - wii;
- int xii = (op->xi + wii) % (p->in-1);
- cmSample_t wnd = p->wnd[ wii ] + frac * (p->wnd[wii+1] - p->wnd[wii]);
- cmSample_t val;
-
- // if enough samples have been generated and the next input will not be in the no-go zone
- if( (op->ynn >= p->procSmpCnt) && _isNotInNoGoZone(p,xii-1) && _isNotInNoGoZone(p,xii+2) )
- {
- contFl = false;
- break;
- }
-
- if( op->ynn >= op->yN )
- {
- printf("OVER\n");
- contFl = false;
- break;
- }
-
- // generate the value of the output sample
- if( p->cubeFl )
- val = _cube_interp(frac,p->x[xii-1],p->x[xii],p->x[xii+1],p->x[xii+2]);
- else
- val = p->x[ xii ] + frac * (p->x[ xii+1 ] - p->x[xii]);
-
- // apply the window function and assign to output
- op->y[op->yii] = wnd * val;
-
- // incr the count of samples in y[]
- ++op->ynn;
-
- // advance the output buffers input location
- op->yii = (op->yii + 1) % op->yN;
-
- op->wi += ratio; // increment the window location
-
- }
-
- // if a window completed
- if( op->wi >= p->wn )
- {
- if( (ratio < 1.0) && (op->ynn >= p->procSmpCnt) )
- {
- op->wi = -1;
- break;
- }
- _startNewWindow(p,op,li+1,ratio);
- }
-
- }
-
-
- }
-
- // in=5
- // m x
- // 0 1 2 3 4 5
- // 1 x x a b c d e
- // 2 c d e f g h i
- // 3 g h i j k l m
- //
- // ratio < 1 - the output oscillators must be able to generate 1 complete window prior to new samples
- // overwriting the oscillators location in the input buffer.
-
- cmRC_t cmPitchShiftExec( cmPitchShift* p, const cmSample_t* x, cmSample_t* y, unsigned xn, double ratio )
- {
- cmRC_t rc = cmOkRC;
-
- //memcpy(y,x,xn*sizeof(cmSample_t));
- //return rc;
-
- int i;
-
- // copy in the incoming samples
- for(i=0; i<xn; ++i)
- {
- p->x[p->ii] = x[i];
-
- ++p->ii;
-
- if( p->ii == p->in+1 )
- {
- p->x[-1] = p->x[p->in-2];
- p->x[ 0] = p->x[p->in-1];
- p->x[ 1] = p->x[p->in];
- p->ii = 2;
- }
- }
-
- // locate the section of the input buffer which
- // will be written over on the next cycle.
- // The oscillators have to avoid ending in this area
- if( (p->in+1) - p->ii >= p->procSmpCnt )
- {
- p->ei1 = p->ii + p->procSmpCnt - 1;
- p->ei0 = -1;
- }
- else
- {
- int n = (p->in+1) - p->ii;
- p->ei1 = (p->ii + n) - 1;
- p->ei0 = (p->procSmpCnt - n) - 1;
- }
-
- //memset(p->outV,0,p->procSmpCnt*sizeof(cmSample_t));
- _cmPitchShiftOsc(p, p->osc + 0, ratio );
- _cmPitchShiftOsc(p, p->osc + 1, ratio );
-
- // mix the indidual output of the two oscillators to form the final output
- if( p->osc[0].ynn < p->procSmpCnt || p->osc[1].ynn < p->procSmpCnt )
- printf("UNDER\n");
-
- for(i=0; i<p->procSmpCnt; ++i)
- {
- p->outV[i] = p->osc[0].y[p->osc[0].yoi] + p->osc[1].y[p->osc[1].yoi];
- p->osc[0].yoi = (p->osc[0].yoi + 1) % p->osc[0].yN;
- p->osc[1].yoi = (p->osc[1].yoi + 1) % p->osc[1].yN;
- }
-
- p->osc[0].ynn -= p->procSmpCnt;
- p->osc[1].ynn -= p->procSmpCnt;
-
- if( y != NULL )
- memcpy(y,p->outV,p->outN*sizeof(cmSample_t));
-
- return rc;
-
- }
- */
-
- cmRC_t cmPitchShiftInit( cmPitchShift* p, unsigned procSmpCnt, double srate)
- {
- cmRC_t rc;
-
- if((rc = cmPitchShiftFinal(p)) != cmOkRC )
- return rc;
-
- p->procSmpCnt = procSmpCnt;
- p->outN = procSmpCnt;
- p->outV = cmMemAllocZ(cmSample_t,procSmpCnt);
- p->wn = 2048;
- p->xn = 2*p->wn + procSmpCnt;
- p->bn = p->xn + 3;
- p->b = cmMemAllocZ(cmSample_t,p->bn);
- p->x = p->b + 1;
- p->wnd = cmMemAllocZ(cmSample_t,p->wn+1);
- p->xni = p->xn - procSmpCnt + 2;
- p->cubeFl = true;
-
- int i;
- for(i=0; i<2; ++i)
- {
- cmPitchShiftOsc_t* op = p->osc + i;
- op->xi = p->procSmpCnt;
- op->yn = p->wn * 2;
- op->y = cmMemAllocZ(cmSample_t,op->yn);
- op->yii= 0;
- op->yoi= 0;
- op->ynn= 0;
- op->wi = i==0 ? 0 : p->wn/2;
- }
-
- cmVOS_Hann(p->wnd,p->wn+1);
-
- return rc;
- }
-
- void _cmPitchShiftOscExec( cmPitchShift* p, cmPitchShiftOsc_t* op, double ratio )
- {
-
- int k = 0;
-
- // account for right buffer shift on input
- op->xi -= p->procSmpCnt;
-
- // pass through code for testing
- if(0)
- {
- int i;
- for(i=0; i<p->procSmpCnt; ++i)
- {
- op->y[op->yii] = p->x[ (int)floor(op->xi) ];
- op->yii = (op->yii + 1) % op->yn;
- op->ynn += 1;
- op->xi += 1.0;
- }
- return;
- }
-
-
- while(1)
- {
- int wii = floor(op->wi);
- double wfrac = op->wi - wii;
-
- int xii = floor(op->xi);
- double vfrac = op->xi - xii;
- cmSample_t val;
-
- // if enough output samples have been generated and we are outside the no-land zone
- if( (op->ynn >= p->procSmpCnt && op->xi >= p->procSmpCnt) )
- break;
-
- if( op->xi >= p->xn )
- {
- //printf("Wrap %f %f\n",op->xi,op->wi);
- }
-
- cmSample_t wnd = p->wnd[ wii ] + wfrac * (p->wnd[wii+1] - p->wnd[wii]);
-
- // generate the value of the output sample
- if( p->cubeFl )
- val = _cube_interp(vfrac,p->x[xii-1],p->x[xii],p->x[xii+1],p->x[xii+2]);
- else
- val = p->x[ xii ] + vfrac * (p->x[ xii+1 ] - p->x[xii]);
-
- // apply the window function and assign to output
- op->y[op->yii] = wnd * val;
-
- // incr the count of samples in y[]
- ++op->ynn;
-
- // advance the output buffers input location
- op->yii = (op->yii + 1) % op->yn;
-
- op->wi += ratio<1 ? 1 : ratio; // increment the window location
- op->xi += ratio;
-
- if( op->wi >= p->wn )
- {
- ++k;
-
- op->wi = 0;
-
- if( ratio < 1 )
- op->xi = p->xni; // begin of most recent block of procSmpCnt input samples
- else
- op->xi = k*p->procSmpCnt/ratio;
-
- }
- }
-
- //if( op->ynn != p->procSmpCnt )
- // printf("wi:%f xi:%f ynn:%i\n",op->wi,op->xi,op->ynn);
-
- }
- // b: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17
- // x: -1 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
- //
- // On each cycle:
- // 1) shift x[] left by procSmpCnt samples.
- // 2) add new samples on right side of x[]
- // 3) oscillator scans from right to left.
- cmRC_t cmPitchShiftExec( cmPitchShift* p, const cmSample_t* x, cmSample_t* y, unsigned xn, double ratio, bool bypassFl )
- {
- if(0)
- {
- memcpy(p->outV,x,xn*sizeof(cmSample_t));
-
- if( y != NULL )
- memcpy(y,x,xn*sizeof(cmSample_t));
-
- return cmOkRC;
- }
-
- if( y == NULL )
- return cmOkRC;
-
- if( x == NULL )
- {
- cmVOS_Zero(y,xn);
- return cmOkRC;
- }
-
- if( bypassFl )
- {
- memcpy(p->outV,x,xn*sizeof(cmSample_t));
-
- if( y != NULL )
- memcpy(y,x,xn*sizeof(cmSample_t));
-
- return cmOkRC;
- }
-
- int i;
- memmove(p->x - 1, p->x+p->procSmpCnt-1,(p->xn - p->procSmpCnt + 3)*sizeof(cmSample_t));
- memcpy( p->x + p->xni, x, xn * sizeof(cmSample_t) );
-
- //memmove(p->x + p->procSmpCnt -1, p->x - 1, (p->xn - p->procSmpCnt + 3) * sizeof(cmSample_t));
- //memcpy( p->x-1, x, xn * sizeof(cmSample_t));
-
- _cmPitchShiftOscExec(p, p->osc + 0, ratio );
- _cmPitchShiftOscExec(p, p->osc + 1, ratio );
-
- // mix the indidual output of the two oscillators to form the final output
- if( p->osc[0].ynn < p->procSmpCnt || p->osc[1].ynn < p->procSmpCnt )
- printf("UNDER\n");
-
- for(i=0; i<p->procSmpCnt; ++i)
- {
- p->outV[i] = p->osc[0].y[p->osc[0].yoi] + p->osc[1].y[p->osc[1].yoi];
- p->osc[0].yoi = (p->osc[0].yoi + 1) % p->osc[0].yn;
- p->osc[1].yoi = (p->osc[1].yoi + 1) % p->osc[1].yn;
- }
-
- p->osc[0].ynn -= p->procSmpCnt;
- p->osc[1].ynn -= p->procSmpCnt;
-
- if( y != NULL )
- memcpy(y,p->outV,xn*sizeof(cmSample_t));
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
- cmLoopRecord* cmLoopRecordAlloc(
- cmCtx* c, cmLoopRecord* p, unsigned procSmpCnt, unsigned maxRecdSmpCnt, unsigned xfadeSmpCnt )
- {
- cmLoopRecord* op = cmObjAlloc(cmLoopRecord, c, p );
- if( procSmpCnt != 0 )
- if( cmLoopRecordInit(op, procSmpCnt, maxRecdSmpCnt, xfadeSmpCnt) != cmOkRC )
- cmLoopRecordFree(&op);
- return op;
- }
- /*
- cmRC_t cmLoopRecordFree( cmLoopRecord** pp )
- {
- cmRC_t rc = cmOkRC;
- if( pp != NULL && *pp != NULL )
- {
- cmLoopRecord* p = *pp;
- if(( rc = cmLoopRecordFinal(p)) == cmOkRC )
- {
- cmMemPtrFree(&p->bufMem);
- cmMemPtrFree(&p->bufArray);
- cmMemPtrFree(&p->outV);
- cmMemPtrFree(&p->xfadeFunc);
- cmObjFree(pp);
- }
- }
- return rc;
- }
-
- cmRC_t cmLoopRecordInit( cmLoopRecord* p, unsigned procSmpCnt, unsigned maxRecdSmpCnt, unsigned xfadeSmpCnt )
- {
- cmRC_t rc;
- unsigned i;
-
- if((rc = cmLoopRecordFinal(p)) != cmOkRC )
- return rc;
-
- assert( xfadeSmpCnt < maxRecdSmpCnt );
-
- p->maxRecdSmpCnt = maxRecdSmpCnt;
- p->bufArrayCnt = 2;
- p->bufMem = cmMemResizeZ( cmSample_t, p->bufMem, maxRecdSmpCnt * p->bufArrayCnt );
- p->bufArray = cmMemResizeZ( cmLoopRecdBuf, p->bufArray, p->bufArrayCnt );
- p->outV = cmMemResizeZ( cmSample_t, p->outV, procSmpCnt );
- p->xfadeFunc = cmMemResizeZ( cmSample_t, p->xfadeFunc, xfadeSmpCnt+1 );
- p->outN = procSmpCnt;
- p->procSmpCnt = procSmpCnt;
- p->xfadeSmpCnt = xfadeSmpCnt;
- p->recdBufIdx = 0;
- p->playBufIdx = 1;
- p->recdFl = false;
- p->playFl = false;
-
- for(i=0; i<p->bufArrayCnt; ++i)
- {
- p->bufArray[i].bV = p->bufMem + (i * maxRecdSmpCnt);
- p->bufArray[i].bN = maxRecdSmpCnt;
- p->bufArray[i].xfi = xfadeSmpCnt;
- }
-
- for(i=0; i<=p->xfadeSmpCnt; ++i)
- p->xfadeFunc[i] = (cmReal_t)i/p->xfadeSmpCnt;
-
- return rc;
- }
-
- cmRC_t cmLoopRecordFinal( cmLoopRecord* p )
- { return cmOkRC; }
-
- cmRC_t cmLoopRecordExec( cmLoopRecord* p, const cmSample_t* x, cmSample_t* y, unsigned xn, bool recdFl, bool playFl )
- {
- unsigned i;
-
- // if the recdFl was enabled
- if(recdFl==true && p->recdFl==false)
- {
- p->recdFl = true;
- p->bufArray[p->recdBufIdx].bii = 0;
- p->bufArray[p->recdBufIdx].boi = 0;
- printf("Recd:on %i\n",p->recdBufIdx);
- }
- else
- // if the recdFl was disabled
- if( recdFl==false && p->recdFl==true )
- {
- p->recdFl = false;
- playFl = true;
- p->playBufIdx = p->recdBufIdx;
- p->recdBufIdx = (p->recdBufIdx + 1) % p->bufArrayCnt;
- printf("Recd:off\n");
- }
-
- // if the playFl triggered on
- if( playFl==true && p->playFl==false)
- {
- p->bufArray[p->playBufIdx].boi = 0;
- p->playFl = true;
- //printf("Play:on %i %i\n",p->playBufIdx,p->bufArray[p->playBufIdx].bii);
- }
-
- // if recording
- if( p->recdFl )
- {
- cmLoopRecdBuf* rp = p->bufArray + p->recdBufIdx;
-
- for(i=0; i<xn && rp->bii < rp->bN; ++i,++rp->bii)
- {
- rp->bV[ rp->bii ] = x[i];
- }
-
- p->recdFl = rp->bii != rp->bN;
- }
-
- // if playing
- if( p->playFl )
- {
- cmLoopRecdBuf* rp = p->bufArray + p->playBufIdx;
- unsigned xf0n = p->xfadeSmpCnt/2;
- unsigned xf1n = rp->bii - p->xfadeSmpCnt/2;
- unsigned xfi0 = (rp->boi + p->xfadeSmpCnt/2) % rp->bii;
-
- for(i=0; i<xn; ++i)
- {
- bool fl = rp->boi < xf0n || rp->boi > xf1n;
- cmSample_t env = fl ? p->xfadeFunc[ rp->xfi ] : 1;
-
- p->outV[i] = ((1.0-env) * rp->bV[ rp->boi ]) + (env * rp->bV[ xfi0 ]);
- rp->boi = (rp->boi + 1) % rp->bii;
- xfi0 = (xfi0 + 1) % rp->bii;
- }
- }
-
- if( y != NULL )
- memcpy(y,p->outV,xn*sizeof(cmSample_t));
-
- return cmOkRC;
- }
-
- */
-
- cmRC_t cmLoopRecordFree( cmLoopRecord** pp )
- {
- cmRC_t rc = cmOkRC;
- if( pp != NULL && *pp != NULL )
- {
- cmLoopRecord* p = *pp;
- if(( rc = cmLoopRecordFinal(p)) == cmOkRC )
- {
- cmMemPtrFree(&p->bufMem);
- cmMemPtrFree(&p->bufArray);
- cmMemPtrFree(&p->outV);
- cmObjFree(pp);
- }
- }
- return rc;
- }
-
- cmRC_t cmLoopRecordInit( cmLoopRecord* p, unsigned procSmpCnt, unsigned maxRecdSmpCnt, unsigned xfadeSmpCnt )
- {
- cmRC_t rc;
- unsigned i;
-
- if((rc = cmLoopRecordFinal(p)) != cmOkRC )
- return rc;
-
- assert( xfadeSmpCnt < maxRecdSmpCnt );
-
- p->maxRecdSmpCnt = maxRecdSmpCnt;
- p->bufArrayCnt = 2;
- p->bufMem = cmMemResizeZ( cmSample_t, p->bufMem, (maxRecdSmpCnt+3) * p->bufArrayCnt * 2 );
- p->bufArray = cmMemResizeZ( cmLoopRecdBuf, p->bufArray, p->bufArrayCnt );
- p->outV = cmMemResizeZ( cmSample_t, p->outV, procSmpCnt );
- p->outN = procSmpCnt;
- p->procSmpCnt = procSmpCnt;
- p->xfadeSmpCnt = xfadeSmpCnt;
- p->recdBufIdx = 0;
- p->playBufIdx = 1;
- p->recdFl = false;
- p->playFl = false;
-
- for(i=0; i<p->bufArrayCnt; ++i)
- {
- p->bufArray[i].xV = p->bufMem + ((2 * i + 0) * (maxRecdSmpCnt+3)) + 1;
- p->bufArray[i].xN = maxRecdSmpCnt;
- p->bufArray[i].xii = 0;
- p->bufArray[i].wV = p->bufMem + ((2 * i + 1) * (maxRecdSmpCnt+3));
- }
-
- return rc;
- }
-
- cmRC_t cmLoopRecordFinal( cmLoopRecord* p )
- { return cmOkRC; }
-
- void _cmLoopRecordOscExec( cmLoopRecord* p, cmLoopRecdBuf* rp, cmLoopRecdOsc* op, double ratio )
- {
- unsigned i;
- for(i=0; i<p->outN; ++i)
- {
- int xi = floor(op->xi);
- double vfrac = op->xi - xi;
- cmSample_t val = _cube_interp(vfrac,rp->xV[xi-1],rp->xV[xi],rp->xV[xi+1],rp->xV[xi+2]);
-
- int wi = floor(op->wi);
- double wfrac = op->wi - wi;
- cmSample_t wnd = rp->wV[ wi ] + wfrac * (rp->wV[wi+1] - rp->wV[wi]);
-
-
- wnd = (wnd - 0.5) * op->u + 0.5;
-
- p->outV[i] += wnd * val;
-
- op->wi += ratio;
-
- if( op->wi >= rp->xii )
- {
- op->wi -= rp->xii;
- op->u *= -1.0;
- }
-
- op->xi += ratio;
- if( op->xi >= rp->xii )
- op->xi -= rp->xii;
-
- }
- }
-
- //
- // a b c d e f g h i - osc 0 sample value
- // 0.0 .25 0.5 .75 1.0 1.0 .75 0.5 .25 - osc 0 window value
- //
- // e f g h i a b c d - osc 1 sample value
- // 1.0 .75 0.5 .25 0.0 0.0 .25 0.5 .75 - osc 1 window value
- //
- // Notes:
- // 1) The window values transition through zero
- // at the loop point.
- // 2)
-
- cmRC_t cmLoopRecordExec( cmLoopRecord* p, const cmSample_t* x, cmSample_t* y, unsigned xn, bool bypassFl, bool recdFl, bool playFl, double ratio, double pgain, double rgain )
- {
- int i,j;
-
- assert( xn <= p->outN );
-
- if( bypassFl )
- {
- memcpy(p->outV,x,xn*sizeof(cmSample_t));
-
- if( y != NULL )
- {
- //memcpy(y,x,xn*sizeof(cmSample_t));
- cmVOS_MultVVS(y,xn,x,pgain);
- }
- return cmOkRC;
- }
-
- // if the recdFl was enabled
- if(recdFl==true && p->recdFl==false)
- {
- p->recdFl = true;
- p->bufArray[p->recdBufIdx].xii = 0;
- //printf("Recd:on %i\n",p->recdBufIdx);
- }
- else
- // if the recdFl was disabled
- if( recdFl==false && p->recdFl==true )
- {
- cmLoopRecdBuf* rp = p->bufArray + p->recdBufIdx;
-
- // arrange the 'wrap-around' samples
- rp->xV[-1] = rp->xV[rp->xii-1];
- rp->xV[rp->xii ] = rp->xV[0];
- rp->xV[rp->xii+1] = rp->xV[1];
-
- // calc the length of the cross-fade
- if( rp->xii < p->xfadeSmpCnt * 2)
- rp->xfN = rp->xii/2;
- else
- rp->xfN = p->xfadeSmpCnt;
-
- assert( rp->xfN > 0 );
-
- // fill the crossfade window with zeros
- cmVOS_Zero(rp->wV,rp->xii);
-
-
- // fill the last xfN samples in the xfade window vector with a fade-in slope
- int xfi = rp->xii - rp->xfN;
-
- for(j=0; j<rp->xfN; ++j)
- rp->wV[xfi+j] = (cmSample_t)j/rp->xfN;
-
- // initialize the oscillators
- for(j=0; j<2; ++j)
- {
- //
- rp->osc[j].xi = j==0 ? 0.0 : rp->xfN; // oscillators are p->xfN samples out of phase
- rp->osc[j].u = j==0 ? 1.0 : -1.0; // set windows to have opposite polarity
- rp->osc[j].wi = xfi; // begin window at cross-fade
- }
-
- p->recdFl = false;
- p->playFl = true;
- p->playBufIdx = p->recdBufIdx;
- p->recdBufIdx = (p->recdBufIdx + 1) % p->bufArrayCnt;
- //printf("Recd:off\n");
- }
-
-
- // if recording
- if( p->recdFl )
- {
- cmLoopRecdBuf* rp = p->bufArray + p->recdBufIdx;
-
- for(i=0; i<xn && rp->xii < rp->xN; ++i,++rp->xii)
- {
- rp->xV[ rp->xii ] = x[i];
- }
-
- }
-
- if( playFl && p->bufArray[p->playBufIdx].xii > 0 )
- {
- p->playFl = !p->playFl;
- if( p->playFl )
- {
- // reset oscillators to start at the begin of loop
- }
-
- }
-
-
- if( p->playFl )
- {
- cmLoopRecdBuf* rp = p->bufArray + p->playBufIdx;
- cmVOS_Zero(p->outV,p->outN);
- _cmLoopRecordOscExec(p,rp, rp->osc + 0, ratio );
- _cmLoopRecordOscExec(p,rp, rp->osc + 1, ratio );
- }
-
- if( y != NULL )
- {
- //memcpy(y,p->outV,xn*sizeof(cmSample_t));
- for(i=0; i<p->outN; ++i)
- y[i] = (pgain * x[i]) + (rgain * p->outV[i]);
- }
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
- cmGateDetect* cmGateDetectAlloc( cmCtx* c, cmGateDetect* p, unsigned procSmpCnt, cmReal_t onThreshPct, cmReal_t onThreshDb, cmReal_t offThreshDb )
- {
- cmGateDetect* op = cmObjAlloc(cmGateDetect, c, p );
-
- if( procSmpCnt != 0 )
- if( cmGateDetectInit(op, procSmpCnt, onThreshPct, onThreshDb, offThreshDb) != cmOkRC )
- cmGateDetectFree(&op);
- return op;
-
- }
-
- cmRC_t cmGateDetectFree( cmGateDetect** pp )
- {
- cmRC_t rc;
-
- if( pp==NULL || *pp == NULL )
- return cmOkRC;
-
- cmGateDetect* p = *pp;
-
- if((rc = cmGateDetectFinal(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->rmsV);
- cmMemPtrFree(&p->wndV);
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmGateDetectInit( cmGateDetect* p, unsigned procSmpCnt, cmReal_t onThreshPct, cmReal_t onThreshDb, cmReal_t offThreshDb )
- {
- cmRC_t rc;
- if((rc = cmGateDetectFinal(p)) != cmOkRC )
- return rc;
-
- p->rmsN = 3;
- p->rmsV = cmMemResizeZ(cmSample_t,p->rmsV,p->rmsN);
- p->wndN = 9;
- p->wndV = cmMemResizeZ(cmSample_t,p->wndV,p->wndN);
- p->rms = 0;
- p->durSmpCnt = 0;
- p->gateFl = false;
- p->deltaFl = false;
- p->onThreshPct = onThreshPct;
- p->onThreshDb = onThreshDb;
- p->offThreshDb = offThreshDb;
-
- return rc;
- }
-
- cmRC_t cmGateDetectFinal(cmGateDetect* p )
- {
- return cmOkRC;
- }
-
- cmRC_t cmGateDetectExec22( cmGateDetect* p, const cmSample_t* x, unsigned xn )
- {
- p->deltaFl = false;
- p->rms = cmVOS_RMS(x,xn,xn);
- cmReal_t db = p->rms==0 ? -100 : 20*log10(p->rms);
- //cmSample_t b0 = 0;
- cmSample_t b1 = 0;
-
- cmVOS_Shift(p->rmsV,p->rmsN,-1,p->rms);
-
- // if gate is on
- if( p->gateFl )
- {
- p->deltaFl = db < p->offThreshDb;
- }
- else
- {
-
- //cmVOS_Lsq1(NULL,p->rmsV,p->rmsN,&b0,&b1);
- // p->deltaFl = b1 > p->onThreshPct && db > p->onThreshDb;
-
- unsigned i;
-
- for(i=0; i<p->rmsN-1; ++i)
- b1 += p->rmsV[i+1] - p->rmsV[i];
-
- b1 /= p->rmsN;
-
- p->deltaFl = b1 > p->onThreshPct && db > p->onThreshDb;
-
-
- }
-
- if( p->deltaFl )
- {
- p->gateFl = !p->gateFl;
- p->durSmpCnt = xn;
- }
- else
- {
- p->durSmpCnt += xn;
- }
-
-
- //p->rms = b1;
- //printf("%f %f %i %f;\n",db,p->rms,p->deltaFl,b1);
-
- return cmOkRC;
- }
-
- cmRC_t cmGateDetectExec( cmGateDetect* p, const cmSample_t* x, unsigned xn )
- {
- p->deltaFl = false;
- p->rms = cmVOS_RMS(x,xn,xn);
- cmReal_t db = p->rms==0 ? -100 : 20*log10(p->rms);
- unsigned i;
- cmSample_t d = 0;
-
- // update the rms window
- cmVOS_Shift(p->rmsV,p->rmsN,-1,p->rms);
-
- // calc. derr of RMS
- for(i=0; i<p->rmsN-1; ++i)
- d += p->rmsV[i+1] - p->rmsV[i];
-
- d /= p->rmsN;
-
- // zero negative derr's
- d = d<0 ? 0 : d;
-
- // update the peak window
- cmVOS_Shift(p->wndV,p->wndN,-1,d);
-
- p->mean = cmVOS_Mean(p->wndV,p->wndN);
-
- // if this is an offset
- if( p->gateFl && db < p->offThreshDb )
- {
- p->gateFl = false;
- p->deltaFl = true;
- }
- else
- // if this may be an onset.
- if( db > p->onThreshDb )
- {
-
- i = p->wndN - 2;
-
- // if previous derr was a peak
- if( p->wndV[i]>0 && p->wndV[i-1] < p->wndV[i] && p->wndV[i] > p->wndV[i+1] )
- {
- // and the peak is the largest value in the exteneded window
- if( p->wndV[i] > p->mean )
- {
- p->deltaFl = true;
- p->gateFl = true;
- p->durSmpCnt = 0;
- }
-
- }
-
- }
-
- if( p->gateFl )
- p->durSmpCnt += xn;
-
- p->rms = p->d0;
- p->d0 = d;
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
- cmGateDetect2* cmGateDetectAlloc2( cmCtx* c, cmGateDetect2* p, unsigned procSmpCnt, const cmGateDetectParams* args )
- {
- cmGateDetect2* op = cmObjAlloc(cmGateDetect2, c, p );
-
- if( procSmpCnt != 0 )
- if( cmGateDetectInit2(op, procSmpCnt, args) != cmOkRC )
- cmGateDetectFree2(&op);
- return op;
-
- }
-
- cmRC_t cmGateDetectFree2( cmGateDetect2** pp )
- {
- cmRC_t rc;
-
- if( pp==NULL || *pp == NULL )
- return cmOkRC;
-
- cmGateDetect2* p = *pp;
-
- if((rc = cmGateDetectFinal2(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->medV);
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmGateDetectInit2( cmGateDetect2* p, unsigned procSmpCnt, const cmGateDetectParams* args )
- {
- cmRC_t rc;
- if((rc = cmGateDetectFinal2(p)) != cmOkRC )
- return rc;
-
- unsigned pkCnt = 3;
-
- unsigned eleCnt = 3*args->medCnt + args->avgCnt + args->suprCnt + args->offCnt + pkCnt;
- unsigned i;
-
- p->args = *args;
- p->medV = cmMemResizeZ(cmSample_t,p->medV,eleCnt);
- p->fcofV = p->medV + args->medCnt;
- p->fdlyV = p->fcofV + args->medCnt;
- p->avgV = p->fdlyV + args->medCnt;
- p->suprV = p->avgV + args->avgCnt;
- p->offV = p->suprV + args->suprCnt;
- p->pkV = p->offV + args->offCnt;
-
- assert( p->medV + eleCnt == p->pkV + pkCnt );
-
- p->medIdx = 0;
- p->avgIdx = 0;
- p->suprIdx = args->suprCnt;
- p->offIdx = 0;
-
- p->pkFl = false;
- p->gateFl = false;
- p->onFl = false;
- p->offFl = false;
-
- cmGateDetectSetOnThreshDb2(p,args->onThreshDb);
- cmGateDetectSetOnThreshDb2(p,args->offThreshDb);
-
- p->fcofV[0] = 1.0;
- for(i=1; i<args->medCnt; ++i)
- {
- p->fcofV[i] = (1.0 - 1.0/args->medCnt) / ( pow(2.0,i-1) );
- //printf("%i %f ",i,p->fcofV[i]);
- }
-
- for(i=0; i<args->suprCnt; ++i)
- {
- p->suprV[i] = 1.0/pow(args->suprCoeff,i + 1.0);
- //printf("%i %f ",i,p->suprV[i]);
- }
-
- return rc;
- }
-
- cmRC_t cmGateDetectFinal2(cmGateDetect2* p )
- { return cmOkRC; }
-
- void _cmGateDetectPickPeak( cmGateDetect2* p, cmSample_t input )
- {
- p->pkV[0] = p->pkV[1];
- p->pkV[1] = p->pkV[2];
- p->pkV[2] = input;
-
- // if supression is active - apply it to the center pkV[]
- if( p->suprIdx < p->args.suprCnt )
- {
- p->pkV[1] -= p->pkV[1] * p->suprV[p->suprIdx];
- p->suprIdx = (p->suprIdx + 1) % p->args.suprCnt;
- }
-
- p->sup = p->pkV[1];
-
- // if the center value in pkV[] is a local peak and above the onset threshold
- if( p->pkV[1] > p->onThresh && p->pkV[0] < p->pkV[1] && p->pkV[1] > p->pkV[2] )
- {
- p->suprIdx = 0;
- p->gateFl = true;
- p->onFl = true;
- }
-
- // update the offset buffer
- p->offV[p->offIdx] = fabs(p->pkV[2]);
- p->offIdx = (p->offIdx + 1) % p->args.offCnt;
-
- // if this is an offset
- if( p->gateFl==true && cmVOS_Mean(p->offV,p->args.offCnt) < p->offThresh )
- {
- p->gateFl = false;
- p->offFl = true;
- }
-
- }
-
- void _cmGateDetectPickPeak2( cmGateDetect2* p, cmSample_t input )
- {
- // if supression is active - apply it to the input
- if( p->suprIdx < p->args.suprCnt )
- {
- input -= input * p->suprV[p->suprIdx];
- ++p->suprIdx;// = (p->suprIdx + 1) % p->args.suprCnt;
- }
-
- // update the peak buffer
- p->pkV[0] = p->pkV[1];
- p->pkV[1] = p->pkV[2];
- p->pkV[2] = input;
-
- p->sup = input;
-
- // if the signal increased above the threshold and is not already waiting for a peak
- if( p->pkV[1] < input && input > p->onThresh && p->pkFl == false )
- {
- p->pkFl = true;
- p->gateFl = true;
- p->onFl = true;
- }
-
- // if the center value in pkV[] is a local peak and above the onset threshold ...
- if( p->gateFl && p->pkFl && p->pkV[0] < p->pkV[1] && p->pkV[1] > p->pkV[2] )
- {
- p->suprIdx = 0; // ... turn on supression
- p->pkFl = false; // ... not longer waiting for the peak
- }
-
- // update the offset buffer
- p->offV[p->offIdx] = fabs(input);
- p->offIdx = (p->offIdx + 1) % p->args.offCnt;
-
- // if this is an offset
- if( p->gateFl==true && cmVOS_Mean(p->offV,p->args.offCnt) < p->offThresh )
- {
- p->gateFl = false;
- p->offFl = true;
- p->pkFl = false;
- }
-
- }
-
- cmRC_t cmGateDetectExec2( cmGateDetect2* p, const cmSample_t* x, unsigned xn )
- {
- p->rms = cmVOS_RMS(x,xn,xn); // take RMS of incoming window
- p->medV[ p->medIdx ] = p->rms; // input RMS to median filter
- p->medIdx = (p->medIdx + 1) % p->args.medCnt;
-
- p->med = cmVOS_Median(p->medV,p->args.medCnt); // calc the median
- p->dif = cmMax(0,p->rms - p->med); // dif = half_rect( rms - med )
- p->avgV[ p->avgIdx ] = p->dif; // input dif to avg filter
- p->avgIdx = (p->avgIdx + 1) % p->args.avgCnt;
-
- p->avg = cmVOS_Mean(p->avgV,p->args.avgCnt); // calc the avg
- p->ons = p->dif - p->avg; // ons = dif - avg
-
- cmVOS_Shift(p->fdlyV,p->args.medCnt,1,p->ons);
- p->flt = cmVOS_MultSumVV(p->fdlyV,p->fcofV,p->args.medCnt);
-
- p->offFl = false;
- p->onFl = false;
-
- _cmGateDetectPickPeak2(p,p->flt);
-
- return cmOkRC;
- }
-
- void _cmGateDetectSetDb2( cmGateDetect2* p, cmReal_t db, cmReal_t* dbPtr )
- {
- *dbPtr = pow(10.0, db/20.0 );
- }
-
- void cmGateDetectSetOnThreshDb2( cmGateDetect2* p, cmReal_t db )
- { _cmGateDetectSetDb2(p,db,&p->onThresh); }
-
- void cmGateDetectSetOffThreshDb2( cmGateDetect2* p, cmReal_t db )
- { _cmGateDetectSetDb2(p,db,&p->offThresh); }
-
-
-
- //=======================================================================================================================
-
- cmAutoGain* cmAutoGainAlloc( cmCtx* c, cmAutoGain* p, unsigned procSmpCnt, cmReal_t srate, cmReal_t hopMs, unsigned chCnt, const cmGateDetectParams* gd_args )
- {
- cmAutoGain* op = cmObjAlloc(cmAutoGain, c, p );
-
- op->sbp = cmShiftBufAlloc(c,NULL,0,0,0);
- op->gdp = cmGateDetectAlloc2(c,NULL,0,NULL);
-
- if( procSmpCnt != 0 )
- if( cmAutoGainInit(op, procSmpCnt, srate, hopMs, chCnt, gd_args) != cmOkRC )
- cmAutoGainFree(&op);
- return op;
-
- }
-
- cmRC_t cmAutoGainFree( cmAutoGain** pp )
- {
- cmRC_t rc;
-
- if( pp==NULL || *pp == NULL )
- return cmOkRC;
-
- cmAutoGain* p = *pp;
-
- if((rc = cmAutoGainFinal(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->chArray);
- p->chCnt = 0;
-
- cmShiftBufFree(&p->sbp);
- cmGateDetectFree2(&p->gdp);
-
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmAutoGainInit( cmAutoGain* p, unsigned procSmpCnt, cmReal_t srate, cmReal_t hopMs, unsigned chCnt, const cmGateDetectParams* gd_args )
- {
- unsigned i;
- cmRC_t rc;
- if((rc = cmAutoGainFinal(p)) != cmOkRC )
- return rc;
-
- unsigned hopSmpCnt = (unsigned)floor(srate * hopMs / 1000.0);
- unsigned wndSmpCnt = hopSmpCnt * gd_args->medCnt;
-
- cmShiftBufInit(p->sbp,procSmpCnt,wndSmpCnt,hopSmpCnt);
- cmGateDetectInit2(p->gdp,procSmpCnt,gd_args);
-
- p->chCnt = chCnt;
- p->chArray = cmMemResizeZ(cmAutoGainCh,p->chArray,p->chCnt);
- p->chp = NULL;
-
- for(i=0; i<p->chCnt; ++i)
- p->chArray[i].id = cmInvalidIdx;
-
- return rc;
- }
-
- cmRC_t cmAutoGainFinal( cmAutoGain* p )
- { return cmOkRC;}
-
- void _cmAutoGainChannelFinish( cmAutoGain* p )
- {
- if( p->chp != NULL )
- {
- if( p->gateMax != 0 )
- {
- p->gateSum += p->gateMax;
- p->gateCnt += 1;
- }
-
- p->chp->gateMaxAvg = p->gateCnt == 0 ? 0.0 : p->gateSum / p->gateCnt;
- }
-
- }
-
- cmRC_t cmAutoGainStartCh( cmAutoGain* p, unsigned id )
- {
- cmReal_t rmsMax = 1.0;
- unsigned i;
-
- if( id == cmInvalidIdx )
- return cmOkRC;
-
- // do intermediate channel calculations on the last selected channel
- if( p->chp != NULL )
- _cmAutoGainChannelFinish( p );
-
-
- // if 'id' has already been used
- // then select the associated channel as the current channel
- // otherwise select the next avail channel as the current channel
- for(i=0; i<p->chCnt; ++i)
- if( p->chArray[i].id == id || p->chArray[i].id == cmInvalidId )
- {
- p->chp = p->chArray + i;
- break;
- }
-
-
- if( p->chp == NULL )
- return cmCtxRtCondition( &p->obj, cmArgAssertRC, "All channels are in use.");
-
-
- p->chp->id = id;
- p->gateCnt = 0;
- p->gateSum = 0;
- p->gateMax = 0;
- p->minRms = rmsMax;
-
- return cmOkRC;
- }
-
- // The goal of this process is to locate the max RMS value during
- // the duration of each note. When all the notes have been processed for
- // a given channel the average maximum value for all of the notes is
- // then calculated.
- cmRC_t cmAutoGainProcCh( cmAutoGain* p, const cmSample_t* x, unsigned xn )
- {
- // shift the new samples into the shift buffer
- while(cmShiftBufExec(p->sbp,x,xn))
- {
- // update the gate detector
- cmGateDetectExec2(p->gdp,p->sbp->outV,p->sbp->outN);
-
- // write the output matrix file
- //if( _cmPuWriteMtxFile(p,segFl) != kOkPuRC )
- // goto errLabel;
-
- // if this frame is an RMS minimum or onset or offset
- // then select it as a possible segment end.
- // Note that for onsets this will effectively force the end to
- // come after the onset because the onset will not be an energy minimum
- // relative to subsequent frames.
- if( p->gdp->rms < p->minRms || p->gdp->onFl || p->gdp->offFl )
- {
- p->minRms = p->gdp->rms;
-
- // count onsets
- if( p->gdp->onFl )
- ++p->chp->onCnt;
-
- // count offsets
- if( p->gdp->offFl )
- {
- ++p->chp->offCnt;
-
- // update the gate sum and count
- p->gateSum += p->gateMax;
- p->gateCnt += 1;
- p->gateMax = 0;
- }
- }
-
- // track the max RMS value during this gate
- if( p->gdp->gateFl && p->gdp->rms > p->gateMax )
- p->gateMax = p->gdp->rms;
-
- }
-
- return cmOkRC;
- }
-
- cmRC_t cmAutoGainCalcGains( cmAutoGain* p )
- {
- unsigned i;
- cmReal_t avg = 0;
-
- if( p->chCnt == 0 )
- return cmOkRC;
-
- // verify that all channels were input
- for(i=0; i<p->chCnt; ++i)
- if( p->chArray[i].id == cmInvalidId )
- break;
-
- if( i != p->chCnt )
- return cmCtxRtCondition( &p->obj, cmArgAssertRC, "All channels must be set prior to calculating gains.");
-
- // process the last channel
- _cmAutoGainChannelFinish(p);
-
- // p->chp isn't used again unless we restart the indidual channel processing
- p->chp = NULL;
-
-
- for(i=0; i<p->chCnt; ++i)
- avg += p->chArray[i].gateMaxAvg;
-
- avg /= p->chCnt;
-
- for(i=0; i<p->chCnt; ++i)
- {
- cmReal_t d = p->chArray[i].gateMaxAvg==0 ? 1.0 : p->chArray[i].gateMaxAvg;
- p->chArray[i].gain = avg / d;
- }
-
- return cmOkRC;
- }
-
- void cmAutoGainPrint( cmAutoGain* p, cmRpt_t* rpt )
- {
- unsigned i=0;
- for(i=0; i<p->chCnt; ++i)
- {
- cmAutoGainCh* chp = p->chArray + i;
- cmRptPrintf(rpt,"midi:%3i %4s on:%i off:%i avg:%5.5f gain:%5.5f\n",
- chp->id,
- cmStringNullGuard(cmMidiToSciPitch(chp->id,NULL,0)),
- chp->onCnt, chp->offCnt, chp->gateMaxAvg, chp->gain );
- }
- }
-
- //==========================================================================================================================================
-
- cmChCfg* cmChCfgAlloc( cmCtx* c, cmChCfg* p, cmCtx_t* ctx, const cmChar_t* fn )
- {
- cmChCfg* op = cmObjAlloc(cmChCfg, c, p );
-
- if( fn != NULL )
- if( cmChCfgInit( op, ctx, fn ) != cmOkRC )
- cmChCfgFree(&op);
- return op;
- }
-
- cmRC_t cmChCfgFree( cmChCfg** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmChCfg* p = *pp;
-
- if((rc = cmChCfgFinal(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->chArray);
- cmFsFreeFn(p->fn);
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- enum { kChColIdx, kSsiColIdx, kPitchColIdx, kMidiColIdx, kGainColIdx, kNsFlColIdx, kCdFlColIdx, kColCnt };
-
- cmRC_t cmChCfgInit( cmChCfg* p, cmCtx_t* ctx, const cmChar_t* fn )
- {
- cmRC_t rc = cmOkRC;
- unsigned i,j;
- const cmChar_t* ch_array_label = "ch_array";
-
- typedef struct
- {
- unsigned id;
- const char* label;
- } map_t;
-
- map_t map[ kColCnt ] =
- {
- { kChColIdx, "ch" },
- { kSsiColIdx, "ssi" },
- { kPitchColIdx, "pitch" },
- { kMidiColIdx, "midi" },
- { kGainColIdx, "gain" },
- { kNsFlColIdx, "ns_fl"},
- { kCdFlColIdx, "cd_fl"}
- };
-
-
- if((rc = cmChCfgFinal(p)) != cmOkRC )
- return rc;
-
- p->fn = cmFsMakeFn(cmFsPrefsDir(),fn,NULL,NULL);
-
- // read the channel cfg JSON file
- if( cmJsonInitializeFromFile(&p->jsH, p->fn, ctx ) != kOkJsRC )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "JSON initialize failed on '%s'.",cmStringNullGuard(p->fn));
- goto errLabel;
- }
-
- // locate the 'ch_array' node
- if((p->cap = cmJsonFindValue( p->jsH, ch_array_label, cmJsonRoot(p->jsH), kArrayTId )) == NULL )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "Unable to locate the JSON element '%s'.",ch_array_label);
- goto errLabel;
- }
-
- unsigned rowCnt = cmJsonChildCount(p->cap);
-
- // there must be at least 1 label row and 1 ch row
- if( rowCnt < 2 )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "The 'ch_array' appears to be empty.");
- goto errLabel;
- }
-
- // allocate the ch array
- p->chCnt = rowCnt - 1;
- p->chArray = cmMemResizeZ( cmChCfgCh, p->chArray, p->chCnt );
- p->nsChCnt = 0;
-
- // read each row
- for(i=0; i<rowCnt; ++i)
- {
- // get the array on row i
- const cmJsonNode_t* np = cmJsonArrayElementC(p->cap,i);
-
- // all row arrays contain 'kColCnt' elements
- if( cmJsonChildCount(np) != kColCnt )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "All 'ch_array' element at index %i does not contain %i values.",i,kColCnt);
- goto errLabel;
- }
-
- // for each columns
- for(j=0; j<kColCnt; ++j)
- {
- const cmJsonNode_t* cp = cmJsonArrayElementC(np,j);
-
- // the first row contains the labels ....
- if( i == 0 )
- {
- // verify that the column format is as expected
- if( cmJsonIsString(cp)==false || strcmp(cp->u.stringVal,map[j].label) != 0 )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "The first row column at index %i of 'ch_array' should be the label '%s'.",map[j].label);
- goto errLabel;
- }
- }
- else // ... other rows contain Ch Cfg's.
- {
-
- cmChCfgCh* chp = p->chArray + (i-1);
-
- switch(j)
- {
- case kChColIdx: rc = cmJsonUIntValue( cp, &chp->ch ); break;
- case kSsiColIdx: rc = cmJsonUIntValue( cp, &chp->ssi ); break;
- case kPitchColIdx: rc = cmJsonStringValue( cp, &chp->pitchStr ); break;
- case kMidiColIdx: rc = cmJsonUIntValue( cp, &chp->midi ); break;
- case kGainColIdx: rc = cmJsonRealValue( cp, &chp->gain ); break;
- case kNsFlColIdx:
- rc = cmJsonBoolValue( cp, &chp->nsFl );
- if( chp->nsFl )
- ++p->nsChCnt;
- break;
-
- case kCdFlColIdx: rc = cmJsonBoolValue( cp, &chp->cdFl ); break;
- default:
- { assert(0); }
- }
-
- if( rc != kOkJsRC )
- {
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "An error occurred while reading the '%s' column on row index:%i .", map[j].label,i);
- goto errLabel;
- }
-
- }
- }
- }
-
- errLabel:
-
- return rc;
- }
-
- cmRC_t cmChCfgFinal( cmChCfg* p )
- {
- cmRC_t rc = cmOkRC;
-
- if( cmJsonIsValid(p->jsH) )
- if( cmJsonFinalize(&p->jsH) != kOkJsRC )
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "JSON finalize failed.");
-
- return rc;
- }
-
- cmRC_t cmChCfgWrite( cmChCfg* p )
- {
- cmRC_t rc = cmOkRC;
- unsigned i;
-
- for(i=0; i<p->chCnt; ++i)
- {
- // get the array on row i+1
- cmJsonNode_t* np = cmJsonArrayElement(p->cap,i+1);
-
- // get the ele in the 'gainColIdx' column
- np = cmJsonArrayElement(np,kGainColIdx);
-
- assert( cmJsonIsReal(np) );
-
- np->u.realVal = p->chArray[i].gain;
-
- }
-
-
- if( cmJsonWrite( p->jsH, cmJsonRoot(p->jsH), p->fn ) != kOkJsRC )
- rc = cmCtxRtCondition( &p->obj, cmSubSysFailRC, "The JSON Channel Cfg file write failed on '%s'.",cmStringNullGuard(p->fn));
-
- return rc;
- }
-
- void cmChCfgPrint( cmChCfg* p, cmRpt_t* rpt )
- {
- unsigned i;
- for(i=0; i<p->chCnt; ++i)
- {
- const cmChCfgCh* chp = p->chArray + i;
- cmRptPrintf(rpt,"%3i %3i %4s %3i %5.5f\n",chp->ch,chp->ssi,chp->pitchStr,chp->midi,chp->gain);
- }
- }
-
- unsigned cmChCfgChannelCount( cmCtx_t* ctx, const cmChar_t* fn, unsigned* nsChCntPtr )
- {
- cmChCfg* ccp;
- unsigned chCnt = 0;
- cmCtx* c = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
-
- if((ccp = cmChCfgAlloc(c, NULL, ctx, fn )) == NULL )
- goto errLabel;
-
- chCnt = ccp->chCnt;
-
- if( nsChCntPtr != NULL )
- *nsChCntPtr = ccp->nsChCnt;
-
- cmChCfgFree(&ccp);
-
- errLabel:
- cmCtxFree(&c);
- return chCnt;
- }
-
- unsigned cmChCfgChannelIndex( cmCtx_t* ctx, const cmChar_t* fn, unsigned chIdx )
- {
- cmChCfg* ccp;
- unsigned retChIdx = -1;
- cmCtx* c = cmCtxAlloc(NULL, &ctx->rpt, cmLHeapNullHandle, cmSymTblNullHandle );
-
- if((ccp = cmChCfgAlloc(c, NULL, ctx, fn )) == NULL )
- goto errLabel;
-
- if( chIdx >= ccp->chCnt )
- cmCtxRtCondition( &ccp->obj, cmArgAssertRC, "The channel index %i is not less than the channel count %i when querying '%s'.",chIdx,ccp->chCnt,cmStringNullGuard(ccp->fn));
- else
- retChIdx = ccp->chArray[chIdx].ch;
-
-
-
- cmChCfgFree(&ccp);
-
- errLabel:
- cmCtxFree(&c);
- return retChIdx;
- }
-
-
- //==========================================================================================================================================
- cmChordDetect* cmChordDetectAlloc( cmCtx*c, cmChordDetect* p, cmReal_t srate, unsigned chCnt, cmReal_t maxTimeSpanMs, unsigned minNotesPerChord )
- {
- cmChordDetect* op = cmObjAlloc(cmChordDetect, c, p );
-
- if( srate != 0 )
- if( cmChordDetectInit( op, srate, chCnt, maxTimeSpanMs, minNotesPerChord ) != cmOkRC )
- cmChordDetectFree(&op);
- return op;
- }
-
- cmRC_t cmChordDetectFree( cmChordDetect** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmChordDetect* p = *pp;
-
- if((rc = cmChordDetectFinal(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->chArray);
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmChordDetectInit( cmChordDetect* p, cmReal_t srate, unsigned chCnt, cmReal_t maxTimeSpanMs, unsigned minNotesPerChord )
- {
- cmRC_t rc;
- if((rc = cmChordDetectFinal(p)) != cmOkRC )
- return rc;
-
- p->chArray = cmMemResizeZ(cmChordDetectCh, p->chArray, chCnt );
- p->chCnt = chCnt;
- p->minNotesPerChord = minNotesPerChord;
- p->detectFl = false;
- p->timeSmp = 0;
- p->srate = srate;
- cmChordDetectSetSpanMs(p,maxTimeSpanMs);
-
- unsigned i;
- for(i=0; i<p->chCnt; ++i)
- p->chArray[i].readyFl = true;
-
- return rc;
- }
-
- cmRC_t cmChordDetectFinal( cmChordDetect* P )
- { return cmOkRC; }
-
- cmRC_t cmChordDetectExec( cmChordDetect* p, unsigned procSmpCnt, const bool* gateV, const cmReal_t* rmsV, unsigned chCnt )
- {
- assert( chCnt == p->chCnt );
-
- chCnt = cmMin(chCnt,p->chCnt);
-
- cmRC_t rc = cmOkRC;
- unsigned candCnt = 0;
- cmChordDetectCh* oldCand = NULL;
- unsigned i;
-
- p->detectFl = false;
- p->timeSmp += procSmpCnt;
-
- // update the readyFl's and candFl's based on onset and offsets
- for(i=0; i<chCnt; ++i)
- {
- cmChordDetectCh* cp = p->chArray + i;
-
- // if onset and the channel is ready
- if( gateV[i] && cp->gateFl==false && cp->readyFl )
- {
- cp->candSmpTime = p->timeSmp;
- cp->candRMS = rmsV[i];
- cp->candFl = true;
- }
-
- // if offset then this channel is again ready to be a candidate
- if( gateV[i]==false && cp->gateFl )
- {
- cp->readyFl = true;
- }
-
- cp->gateFl = gateV[i];
- cp->chordFl = false;
- }
-
- // check if we have enough channels to form a chord and
- // expire channels that have passed the max time out value
- for(i=0; i<chCnt; ++i)
- {
- cmChordDetectCh* cp = p->chArray + i;
- unsigned ageSmpCnt = p->timeSmp - cp->candSmpTime;
-
- // if this is a candiate ...
- if( cp->candFl )
- {
- // ... that has not expired
- if( ageSmpCnt <= p->maxTimeSpanSmpCnt )
- {
- // track the oldest candidate
- if( oldCand==NULL || cp->candSmpTime < oldCand->candSmpTime )
- oldCand = cp;
-
- ++candCnt;
- }
- else // ... that has expired
- {
- cp->candFl = false;
- }
- }
- }
-
-
- // If we have enough notes and the oldest candiate will expire on the next cycle.
- // (By waiting for the oldest note to almost expire we gather the maximum number of
- // possible notes given the time duration. If we remove this condition then
- // we will tend to trigger chord detection with fewer notes.)
- if( oldCand != NULL )
- {
- unsigned nextAge = p->timeSmp + procSmpCnt - oldCand->candSmpTime;
-
- if( candCnt >= p->minNotesPerChord && nextAge >= p->maxTimeSpanSmpCnt )
- {
- for(i=0; i<chCnt; ++i)
- {
- cmChordDetectCh* cp = p->chArray + i;
- if( cp->candFl )
- {
- cp->chordFl = true;
- cp->candFl = false;
- }
- }
-
- p->detectFl = true;
-
- }
- }
- return rc;
- }
-
- cmRC_t cmChordDetectSetSpanMs( cmChordDetect* p, cmReal_t maxTimeSpanMs )
- {
- p->maxTimeSpanSmpCnt = floor( maxTimeSpanMs * p->srate / 1000.0 );
- return cmOkRC;
- }
-
-
- //==========================================================================================================================================
- cmXfader* cmXfaderAlloc( cmCtx*c, cmXfader* p, cmReal_t srate, unsigned chCnt, cmReal_t fadeTimeMs )
- {
- cmXfader* op = cmObjAlloc(cmXfader, c, p );
-
- if( srate != 0 )
- if( cmXfaderInit( op, srate, chCnt, fadeTimeMs ) != cmOkRC )
- cmXfaderFree(&op);
- return op;
- }
-
- cmRC_t cmXfaderFree( cmXfader** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmXfader* p = *pp;
-
- if((rc = cmXfaderFinal(p)) != cmOkRC )
- return rc;
-
- cmMemPtrFree(&p->chArray);
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmXfaderInit( cmXfader* p, cmReal_t srate, unsigned chCnt, cmReal_t fadeTimeMs )
- {
- cmRC_t rc;
- if((rc = cmXfaderFinal(p)) != cmOkRC )
- return rc;
-
- p->chCnt = chCnt;
- p->chArray = cmMemResizeZ(cmXfaderCh,p->chArray,p->chCnt);
- p->srate = srate;
- p->gateFl = false;
- p->onFl = false;
- p->offFl = false;
-
- cmXfaderSetXfadeTime(p,fadeTimeMs);
-
- return rc;
- }
-
- cmRC_t cmXfaderFinal( cmXfader* p )
- { return cmOkRC; }
-
- cmRC_t cmXfaderExec( cmXfader* p, unsigned procSmpCnt, const bool* chGateV, unsigned chCnt )
- {
- assert( chCnt == p->chCnt);
- chCnt = cmMin(chCnt,p->chCnt);
-
- bool gateFl = false;
-
- // gain change associated with procSmpCnt
- //cmReal_t dgain = (cmReal_t)procSmpCnt / p->fadeSmpCnt;
- cmReal_t i_dgain = (cmReal_t)procSmpCnt / p->fadeInSmpCnt;
- cmReal_t o_dgain = (cmReal_t)procSmpCnt / p->fadeOutSmpCnt;
-
- unsigned i;
- // for each channel
- for(i=0; i<chCnt; ++i)
- {
- cmXfaderCh* cp = p->chArray + i;
-
- cp->onFl = false;
- cp->offFl = false;
-
- if( chGateV != NULL )
- {
- cp->onFl = chGateV[i] && !cp->gateFl; // notice fade-in transition begin
- cp->gateFl = chGateV[i];
- }
-
- cmReal_t g = cp->gain;
-
- if( cp->gateFl )
- {
- cp->gain = cmMin(cp->gain + i_dgain,1.0);
- cp->ep_gain = sqrt(0.5 - 0.5 * cos(3.14159*cp->gain));
- }
- else
- {
- cp->gain = cmMax(cp->gain - o_dgain,0.0);
- cp->ep_gain = sqrt(0.5 - 0.5 * cos(3.14159*cp->gain));
- cp->offFl = g>0.0 && cp->gain==0.0; // notice fade-out transition end
- }
-
- if( cp->gain != 0.0 )
- gateFl = true;
-
- }
-
- p->onFl = false;
- p->offFl = false;
-
- if( p->gateFl==false && gateFl==true )
- p->onFl = true;
- else
- if( p->gateFl==true && gateFl==false )
- p->offFl = true;
-
- p->gateFl = gateFl;
-
- return cmOkRC;
- }
-
- cmRC_t cmXfaderExecAudio( cmXfader* p, unsigned procSmpCnt, const bool* gateV, unsigned chCnt, const cmSample_t* x[], cmSample_t* y )
- {
- cmRC_t rc;
-
- assert( chCnt == p->chCnt);
- chCnt = cmMin(chCnt,p->chCnt);
-
- if((rc = cmXfaderExec(p,procSmpCnt,gateV,chCnt)) != cmOkRC )
- return rc;
-
- unsigned i;
- for(i=0; i<chCnt; ++i)
- if( x[i] != NULL )
- cmVOS_MultVaVS(y,procSmpCnt,x[i],p->chArray[i].ep_gain);
-
- return rc;
- }
-
- void cmXfaderSetXfadeTime( cmXfader* p, cmReal_t fadeTimeMs )
- {
- p->fadeSmpCnt = floor(fadeTimeMs * p->srate /1000.0);
- p->fadeInSmpCnt = p->fadeSmpCnt;
- p->fadeOutSmpCnt = p->fadeSmpCnt;
- }
-
- void cmXfaderSetXfadeInTime( cmXfader* p, cmReal_t fadeTimeMs )
- {
- p->fadeInSmpCnt = floor(fadeTimeMs * p->srate /1000.0);
- }
- void cmXfaderSetXfadeOutTime( cmXfader* p, cmReal_t fadeTimeMs )
- {
- p->fadeOutSmpCnt = floor(fadeTimeMs * p->srate /1000.0);
- }
-
- void cmXfaderSelectOne( cmXfader* p, unsigned chIdx )
- {
- unsigned i = 0;
- for(i=0; i<p->chCnt; ++i)
- p->chArray[i].gateFl = i == chIdx;
- }
-
- void cmXfaderAllOff( cmXfader* p )
- {
- unsigned i = 0;
- for(i=0; i<p->chCnt; ++i)
- p->chArray[i].gateFl = false;
- }
-
- void cmXfaderJumpToDestinationGain( cmXfader* p )
- {
- unsigned i = 0;
- for(i=0; i<p->chCnt; ++i)
- {
- if( p->chArray[i].gateFl )
- p->chArray[i].gain = 1.0;
- else
- p->chArray[i].gain = 0.0;
-
- p->chArray[i].onFl = false;
- p->chArray[i].offFl = false;
- p->chArray[i].ep_gain = p->chArray[i].gain;
- }
- }
-
- //==========================================================================================================================================
- cmFader* cmFaderAlloc( cmCtx*c, cmFader* p, cmReal_t srate, cmReal_t fadeTimeMs )
- {
- cmFader* op = cmObjAlloc(cmFader, c, p );
-
- if( srate != 0 )
- if( cmFaderInit( op, srate, fadeTimeMs ) != cmOkRC )
- cmFaderFree(&op);
- return op;
- }
-
- cmRC_t cmFaderFree( cmFader** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmFader* p = *pp;
-
- if((rc = cmFaderFinal(p)) != cmOkRC )
- return rc;
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmFaderInit( cmFader* p, cmReal_t srate, cmReal_t fadeTimeMs )
- {
- cmRC_t rc;
- if((rc = cmFaderFinal(p)) != cmOkRC )
- return rc;
-
- p->srate = srate;
- p->gain = 0.0;
- cmFaderSetFadeTime(p,fadeTimeMs);
-
- return rc;
- }
-
- cmRC_t cmFaderFinal( cmFader* p )
- { return cmOkRC; }
-
- cmRC_t cmFaderExec( cmFader* p, unsigned procSmpCnt, bool gateFl, bool mixFl, const cmSample_t* x, cmSample_t* y )
- {
- cmReal_t d = (gateFl ? 1.0 : -1.0) * procSmpCnt / p->fadeSmpCnt;
-
- // TODO: add fade curves
-
- p->gain = cmMin(1.0,cmMax(0.0,p->gain + d));
-
- if( x!=NULL && y!=NULL )
- {
- if( mixFl )
- cmVOS_MultVaVS(y, procSmpCnt, x, 1.0/* p->gain*/);
- else
- cmVOS_MultVVS(y,procSmpCnt,x,p->gain);
- }
-
- return cmOkRC;
- }
-
- void cmFaderSetFadeTime( cmFader* p, cmReal_t fadeTimeMs )
- {
- p->fadeSmpCnt = (unsigned)floor( fadeTimeMs * p->srate / 1000.0 );
- }
-
- //=======================================================================================================================
- cmCombFilt* cmCombFiltAlloc( cmCtx* c, cmCombFilt* p, cmReal_t srate, bool feedbackFl, cmReal_t minHz, cmReal_t alpha, cmReal_t hz, bool bypassFl )
- {
- cmCombFilt* op = cmObjAlloc(cmCombFilt, c, p );
-
- op->idp = cmIDelayAlloc(c, NULL, 0, 0, NULL, NULL, NULL, 0 );
-
- if( srate != 0 )
- if( cmCombFiltInit( op, srate, feedbackFl, minHz, alpha, hz, bypassFl ) != cmOkRC )
- cmCombFiltFree(&op);
-
- return op;
- }
-
- cmRC_t cmCombFiltFree( cmCombFilt** pp)
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmCombFilt* p = *pp;
-
- if((rc = cmCombFiltFinal(p)) != cmOkRC )
- return rc;
-
- cmMemFree(p->a);
- cmMemFree(p->b);
- cmMemFree(p->d);
-
- cmIDelayFree(&p->idp);
-
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmCombFiltInit( cmCombFilt* p, cmReal_t srate, bool feedbackFl, cmReal_t minHz, cmReal_t alpha, cmReal_t hz, bool bypassFl )
- {
- cmRC_t rc;
- if((rc = cmCombFiltFinal(p)) != cmOkRC )
- return rc;
-
- p->feedbackFl = feedbackFl;
-
- p->dN = cmMax(1,floor(srate / minHz ));
- p->d = cmMemResizeZ( cmReal_t, p->d, p->dN+1 );
- p->a = cmMemResizeZ( cmReal_t, p->a, p->dN );
- p->b = cmMemResizeZ( cmReal_t, p->b, p->dN );
-
- p->dn = 1;
- p->alpha = alpha;
- p->srate = srate;
- p->bypassFl = bypassFl;
-
- cmReal_t tapMs = p->dn * 1000.0 / srate;
- cmReal_t tapFf = 1.0;
- cmReal_t tapFb = 1.0;
- cmIDelayInit(p->idp, srate, p->dN * 1000.0 / srate, &tapMs, &tapFf, &tapFb, 1 );
-
- cmCombFiltSetHz(p,hz);
-
- return rc;
- }
-
- cmRC_t cmCombFiltFinal( cmCombFilt* p )
- { return cmOkRC; }
-
- cmRC_t cmCombFiltExec( cmCombFilt* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- if( y == NULL )
- return cmOkRC;
-
- if( x == NULL )
- {
- cmVOS_Zero(y,n);
- return cmOkRC;
- }
-
- if( p->bypassFl )
- cmVOS_Copy(y,n,x);
- else
- cmIDelayExec(p->idp,x,y,n);
-
- return cmOkRC;
- }
-
- void cmCombFiltSetAlpha( cmCombFilt* p, cmReal_t alpha )
- {
- p->b0 = 1.0 - fabs(alpha); // normalization coeff (could be applied directly to the input or output)
- p->a[p->dn-1] = -alpha;
- p->alpha = alpha;
-
- p->idp->tff[0] = p->b0;
- p->idp->tfb[0] = -alpha;
-
- }
-
- cmRC_t cmCombFiltSetHz( cmCombFilt* p, cmReal_t hz )
- {
- if( hz < p->minHz )
- return cmCtxRtCondition( &p->obj, cmInvalidArgRC, "The comb filter frequency %f Hz is invalid given the minimum frequency setting of %f Hz.",hz,p->minHz );
-
- // clear the current alpha
- p->a[p->dn-1] = 0;
-
- // change location of alpha in p->a[]
- p->dn = cmMin(p->dN-1,cmMax(1,floor(p->srate / hz )));
-
- p->hz = hz;
-
- cmCombFiltSetAlpha(p,p->alpha); // the location of filter coeff changed - reset it here
-
- cmIDelaySetTapMs(p->idp, 0,p->dn * 1000.0 / p->srate );
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
- cmDcFilt* cmDcFiltAlloc( cmCtx* c, cmDcFilt* p, bool bypassFl )
- {
- cmDcFilt* op = cmObjAlloc(cmDcFilt, c, p );
-
- if( cmDcFiltInit( op, bypassFl ) != cmOkRC )
- cmDcFiltFree(&op);
- return op;
- }
-
- cmRC_t cmDcFiltFree( cmDcFilt** pp)
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmDcFilt* p = *pp;
-
- if((rc = cmDcFiltFinal(p)) != cmOkRC )
- return rc;
-
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmDcFiltInit( cmDcFilt* p, bool bypassFl )
- {
- cmRC_t rc;
- if((rc = cmDcFiltFinal(p)) != cmOkRC )
- return rc;
-
- p->b0 = 1;
- p->b[0] = -1;
- p->a[0] = -0.999;
- p->d[0] = 0;
- p->d[1] = 0;
- p->bypassFl = bypassFl;
- return rc;
- }
-
- cmRC_t cmDcFiltFinal( cmDcFilt* p )
- { return cmOkRC; }
-
- cmRC_t cmDcFiltExec( cmDcFilt* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- if( p->bypassFl )
- cmVOS_Copy(y,n,x);
- else
- cmVOS_Filter(y,n,x,n,p->b0, p->b, p->a, p->d, 1 );
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
- cmIDelay* cmIDelayAlloc( cmCtx* c, cmIDelay* p, cmReal_t srate, cmReal_t maxDelayMs, const cmReal_t* tapMs, const cmReal_t* tapFfGain, const cmReal_t* tapFbGain, unsigned tapCnt )
- {
- cmIDelay* op = cmObjAlloc(cmIDelay, c, p );
-
- if( srate != 0 )
- if( cmIDelayInit( op, srate, maxDelayMs, tapMs, tapFfGain, tapFbGain, tapCnt ) != cmOkRC )
- cmIDelayFree(&op);
- return op;
- }
-
- cmRC_t cmIDelayFree( cmIDelay** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmIDelay* p = *pp;
-
- if((rc = cmIDelayFinal(p)) != cmOkRC )
- return rc;
-
- cmMemFree(p->m);
- cmMemFree(p->ti);
- cmMemFree(p->tff);
- cmMemFree(p->tfb);
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmIDelayInit( cmIDelay* p, cmReal_t srate, cmReal_t maxDelayMs, const cmReal_t* tapMs, const cmReal_t* tapFfGain, const cmReal_t* tapFbGain, unsigned tapCnt )
- {
- cmRC_t rc;
- if(( rc = cmIDelayFinal(p)) != cmOkRC )
- return rc;
-
- p->dn = (unsigned)floor( maxDelayMs * srate / 1000.0 );
- p->mn = p->dn + 3;
- p->m = cmMemResizeZ(cmSample_t,p->m,p->mn);
- p->d = p->m + 1;
- p->tn = tapCnt;
- p->ti = cmMemResize(cmReal_t,p->ti,tapCnt);
- p->tff = cmMemResize(cmReal_t,p->tff,tapCnt);
- p->tfb = cmMemResize(cmReal_t,p->tfb,tapCnt);
- p->srate = srate;
-
- unsigned i;
- for(i=0; i<tapCnt; ++i)
- {
- cmIDelaySetTapMs(p,i,tapMs[i]);
- p->tff[i] = tapFfGain[i];
- p->tfb[i] = tapFbGain[i];
- }
-
- return rc;
- }
-
- cmRC_t cmIDelayFinal(cmIDelay* p )
- { return cmOkRC; }
-
- cmRC_t cmIDelayExec( cmIDelay* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- unsigned i,j;
- for(i=0; i<n; ++i)
- {
- cmSample_t fb = 0;
- y[i] = 0;
-
-
- // calculate the output sample
- for(j=0; j<p->tn; ++j)
- {
- // get tap_j
- cmReal_t tfi = p->ii - p->ti[j];
-
- // mod it into 0:dn-1
- while( tfi < 0 )
- tfi += p->dn;
-
- int ti = floor(tfi);
- cmReal_t tf = tfi - ti;
- cmSample_t v = _lin_interp(tf,p->d[ti],p->d[ti+1]); // _cube_interp(tf,p->d[ti-1],p->d[ti],p->d[ti+1],p->d[ti+2]);
-
- y[i] += p->tff[j] * v;
- fb += p->tfb[j] * v;
- }
-
- // insert incoming sample
- p->d[p->ii] = x[i] + fb;
-
- // advance the delay line
- ++p->ii;
-
- // handle beg/end delay sample duplication
- // -1 0 1 2 .... dn-1 dn dn+1
- // a b c a b c
- // The samples at position -1 0 1 must be duplicated
- // at positions dn-1,dn,dn+1 so that output sample calculation
- // does not need to deal with buffer wrap-around issues.
-
- if( p->ii == 1 )
- p->d[p->dn] = x[i];
- else
- if( p->ii == 2 )
- p->d[p->dn+1] = x[i];
- else
- if( p->ii == p->dn )
- {
- p->d[-1] = x[i];
- p->ii = 0;
- }
- }
-
- return cmOkRC;
- }
-
- cmRC_t cmIDelaySetTapMs( cmIDelay* p, unsigned tapIdx, cmReal_t tapMs )
- {
- cmRC_t rc = cmOkRC;
-
- if( tapIdx < p->tn )
- p->ti[tapIdx] = tapMs * p->srate / 1000.0;
- else
- rc = cmCtxRtCondition( &p->obj, cmInvalidArgRC, "Tap index %i is out of range 0 - %i.",tapIdx,p->tn-1 );
-
- return rc;
- }
-
-
- //=======================================================================================================================
-
- cmGroupSel* cmGroupSelAlloc( cmCtx* c, cmGroupSel* p, unsigned chCnt, unsigned groupCnt, unsigned chsPerGroup )
- {
- cmGroupSel* op = cmObjAlloc(cmGroupSel, c, p );
-
- if( chCnt != 0 )
- if( cmGroupSelInit( op, chCnt, groupCnt, chsPerGroup ) != cmOkRC )
- cmGroupSelFree(&op);
- return op;
-
- }
-
- cmRC_t cmGroupSelFree( cmGroupSel** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmGroupSel* p = *pp;
-
- if((rc = cmGroupSelFinal(p)) != cmOkRC )
- return rc;
-
- cmMemFree(p->groupArray);
- cmMemFree(p->chArray);
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmGroupSelInit( cmGroupSel* p, unsigned chCnt, unsigned groupCnt, unsigned chsPerGroup )
- {
- cmRC_t rc;
- if((rc = cmGroupSelFinal(p)) != cmOkRC )
- return rc;
-
- p->chArray = cmMemResizeZ(cmGroupSelCh,p->chArray,chCnt);
- p->groupArray = cmMemResizeZ(cmGroupSelGrp,p->groupArray,chCnt);
- p->chCnt = chCnt;
- p->groupCnt = groupCnt;
- p->chsPerGroup = chsPerGroup;
-
- unsigned i;
- for(i=0; i<p->chCnt; ++i)
- p->chArray[i].groupIdx = cmInvalidIdx;
-
- for(i=0; i<p->groupCnt; ++i)
- {
- p->groupArray[i].chIdxArray = cmMemAllocZ(unsigned, p->chCnt);
- p->groupArray[i].chIdxCnt = 0;
- }
-
- return rc;
- }
-
- cmRC_t cmGroupSelFinal( cmGroupSel* p )
- {
- unsigned i;
-
- for(i=0; i<p->groupCnt; ++i)
- cmMemFree(p->groupArray[i].chIdxArray);
-
- return cmOkRC;
- }
-
- cmRC_t cmGroupSetChannelGate( cmGroupSel* p, unsigned chIdx, bool gateFl )
- {
- assert(chIdx <p->chCnt);
- cmGroupSelCh* cp = p->chArray + chIdx;
-
- if( gateFl==true && cp->gateFl==false )
- {
- cp->readyFl = true;
- }
-
- if( gateFl==false && cp->gateFl==true )
- {
- cp->offsetFl = true;
- cp->readyFl = false;
- }
-
-
- cp->gateFl = gateFl;
-
- //printf("ch:%i gate:%i ready:%i offset:%i grp:%i\n",chIdx,cp->gateFl,cp->readyFl,cp->offsetFl,cp->groupIdx);
-
- return cmOkRC;
- }
-
- cmRC_t cmGroupSetChannelRMS( cmGroupSel* p, unsigned chIdx, cmReal_t rms )
- {
- assert(chIdx <p->chCnt);
- cmGroupSelCh* cp = p->chArray + chIdx;
- cp->rms = rms;
- return cmOkRC;
- }
-
- cmRC_t cmGroupSelExec( cmGroupSel* p )
- {
- unsigned i,j;
- unsigned availGroupCnt = 0;
-
- p->chsPerGroup = cmMin( p->chsPerGroup, p->chCnt );
-
- p->updateFl = false;
-
- // clear the create and release flags on each group
- // and get the count of available groups
- for(i=0; i<p->groupCnt; ++i)
- {
- cmGroupSelGrp* gp = p->groupArray + i;
-
- gp->createFl = false;
-
- if( gp->releaseFl )
- {
- // clear the groupIdx from the channels assigned to this released group
- for(j=0; j<gp->chIdxCnt; ++j)
- p->chArray[ gp->chIdxArray[j] ].groupIdx = cmInvalidIdx;
-
- gp->releaseFl = false;
- gp->chIdxCnt = 0;
- }
-
- if( gp->chIdxCnt == 0 )
- ++availGroupCnt;
- }
-
- // count the number of ready but unassigned ch's and
- // release any groups which contain a channel with a gate offset
- unsigned readyChCnt = 0;
-
- for(i=0; i<p->chCnt; ++i)
- {
- cmGroupSelCh* cp = p->chArray + i;
-
- // count the number of channels that are ready to be assigned
- if( cp->readyFl )
- ++readyChCnt;
-
- // if this channel offset and it had been assigned to a group
- // then mark its group for release
- if( cp->offsetFl && cp->groupIdx != cmInvalidIdx )
- {
- p->groupArray[cp->groupIdx].releaseFl = true;
-
- p->updateFl = true;
- }
- }
-
-
- // assign ready ch's to available groups
- while( readyChCnt > p->chsPerGroup && availGroupCnt > 0 )
- {
- unsigned groupIdx;
-
- // locate an available group
- for(groupIdx=0; groupIdx<p->groupCnt; ++groupIdx)
- if( p->groupArray[groupIdx].chIdxCnt == 0 )
- break;
-
- if( groupIdx == p->groupCnt )
- break;
-
- --availGroupCnt;
-
- cmGroupSelGrp* gp = p->groupArray + groupIdx;
-
- printf("gs - group:%i chs: ",groupIdx);
-
- // assign chsPerGroup ch's to this group
- for(i=0; i<p->chCnt && gp->chIdxCnt < p->chsPerGroup; ++i)
- if(p->chArray[i].readyFl )
- {
- p->chArray[i].readyFl = false; // this ch is no longer ready because it is assigned
- p->chArray[i].groupIdx = groupIdx; // set this ch's group idx
- gp->chIdxArray[ gp->chIdxCnt ] = i; // assign channel to group
- gp->chIdxCnt += 1; // update the group ch count
- gp->createFl = true;
- p->updateFl = true;
- --readyChCnt;
- printf("%i ",i);
- }
-
- printf("\n");
-
- }
-
- return cmOkRC;
- }
-
- //=======================================================================================================================
-
- cmAudioNofM* cmAudioNofMAlloc( cmCtx* c, cmAudioNofM* p, cmReal_t srate, unsigned inChCnt, unsigned outChCnt, cmReal_t fadeTimeMs )
- {
- cmAudioNofM* op = cmObjAlloc(cmAudioNofM, c, p );
-
- if( srate != 0 )
- if( cmAudioNofMInit( op, srate, inChCnt, outChCnt, fadeTimeMs ) != cmOkRC )
- cmAudioNofMFree(&op);
- return op;
- }
-
- cmRC_t cmAudioNofMFree( cmAudioNofM** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmAudioNofM* p = *pp;
-
- if((rc = cmAudioNofMFinal(p)) != cmOkRC )
- return rc;
-
- cmMemFree(p->outArray);
- cmMemFree(p->inArray);
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmAudioNofMInit( cmAudioNofM* p, cmReal_t srate, unsigned iChCnt, unsigned oChCnt, cmReal_t fadeTimeMs )
- {
- cmRC_t rc;
- if((rc = cmAudioNofMFinal(p)) != cmOkRC )
- return rc;
-
- p->iChCnt = iChCnt;
- p->inArray = cmMemResizeZ(cmAudioNofM_In,p->inArray,iChCnt);
- p->oChCnt = oChCnt;
- p->outArray = cmMemResizeZ(cmAudioNofM_Out,p->outArray,oChCnt);
- p->nxtOutChIdx = 0;
-
- unsigned i;
- for(i=0; i<p->iChCnt; ++i)
- {
- p->inArray[i].fader = cmFaderAlloc(p->obj.ctx, NULL, srate, fadeTimeMs );
- p->inArray[i].outChIdx = cmInvalidIdx;
- }
-
- cmAudioNofMSetFadeMs( p, fadeTimeMs );
-
- return rc;
- }
-
- cmRC_t cmAudioNofMFinal( cmAudioNofM* p )
- {
- unsigned i;
- for(i=0; i<p->iChCnt; ++i)
- cmFaderFree(&p->inArray[i].fader);
- return cmOkRC;
- }
-
- cmRC_t cmAudioNofMSetChannelGate( cmAudioNofM* p, unsigned inChIdx, bool gateFl )
- {
- assert( inChIdx < p->iChCnt );
-
- cmAudioNofM_In* ip = p->inArray + inChIdx;
-
- if( ip->gateFl && gateFl == false )
- ip->offsetFl = true;
-
- if( ip->gateFl == false && gateFl )
- ip->onsetFl = true;
-
- ip->gateFl = gateFl;
-
- printf("nom: %p ch:%i gate:%i on:%i off:%i\n",p,inChIdx,ip->gateFl,ip->offsetFl,ip->onsetFl);
-
- return cmOkRC;
- }
-
- cmRC_t cmAudioNofMExec( cmAudioNofM* p, const cmSample_t* x[], unsigned inChCnt, cmSample_t* y[], unsigned outChCnt, unsigned n )
- {
- assert( inChCnt == p->iChCnt && outChCnt == p->oChCnt );
-
- unsigned i;
-
- // for each output channel
- for(i=0; i<p->oChCnt; ++i)
- {
- cmAudioNofM_Out* op = p->outArray + i;
- cmAudioNofM_In* ip = op->list;
- cmAudioNofM_In* pp = NULL;
-
- // for each input assigned to this output chanenl
- while( ip != NULL )
- {
- // if the channel is no longer active
- if( ip->offsetFl && ip->fader->gain == 0.0 )
- {
- printf("nom: off - out:%i\n",ip->outChIdx);
-
- // remove it from the output channels list
- ip->offsetFl = false;
- ip->outChIdx = cmInvalidIdx;
-
- if( pp == NULL )
- op->list = ip->link;
- else
- pp->link = ip->link;
-
-
- }
-
- pp = ip;
- ip = ip->link;
- }
-
- }
-
- // for each input channel
- for(i=0; i<inChCnt; ++i)
- {
- cmAudioNofM_In* ip = p->inArray + i;
-
- // if this channel is starting
- if( ip->onsetFl == true && ip->offsetFl == false )
- {
- // assign it to the next output channel
- ip->onsetFl = false;
- ip->outChIdx = p->nxtOutChIdx;
-
- ip->link = p->outArray[ ip->outChIdx ].list;
- p->outArray[ ip->outChIdx ].list = ip;
-
- p->nxtOutChIdx = (p->nxtOutChIdx + 1) % p->oChCnt;
-
- printf("nom: on - in:%i out:%i\n",i,ip->outChIdx);
- }
-
- // if this channel is active - then mix its input
- if( ip->outChIdx != cmInvalidIdx )
- {
- cmFaderExec( ip->fader, n, ip->gateFl, true, x[i], y[ ip->outChIdx ] );
-
- }
- }
- return cmOkRC;
- }
-
- cmRC_t cmAudioNofMSetFadeMs( cmAudioNofM* p, cmReal_t fadeTimeMs )
- {
- unsigned i;
- for(i=0; i<p->iChCnt; ++i)
- cmFaderSetFadeTime(p->inArray[i].fader,fadeTimeMs);
- return cmOkRC;
- }
-
-
- //=======================================================================================================================
- cmAdsr* cmAdsrAlloc( cmCtx* c, cmAdsr* p, cmReal_t srate, bool trigFl, cmReal_t minL, cmReal_t dlyMs, cmReal_t atkMs, cmReal_t atkL, cmReal_t dcyMs, cmReal_t susMs, cmReal_t susL, cmReal_t rlsMs )
- {
- cmAdsr* op = cmObjAlloc(cmAdsr, c, p );
-
- if( srate != 0 )
- if( cmAdsrInit( op, srate, trigFl, minL, dlyMs, atkMs, atkL, dcyMs, susMs, susL, rlsMs ) != cmOkRC )
- cmAdsrFree(&op);
- return op;
-
- }
-
- cmRC_t cmAdsrFree( cmAdsr** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmAdsr* p = *pp;
-
- if((rc = cmAdsrFinal(p)) != cmOkRC )
- return rc;
-
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
- cmRC_t cmAdsrInit( cmAdsr* p, cmReal_t srate, bool trigFl, cmReal_t minL, cmReal_t dlyMs, cmReal_t atkMs, cmReal_t atkL, cmReal_t dcyMs, cmReal_t susMs, cmReal_t susL, cmReal_t rlsMs )
- {
- cmRC_t rc;
- if((rc = cmAdsrFinal(p)) != cmOkRC )
- return rc;
-
- // this is a limitation of the design - the design should be replaced with one
- // which increments/decrements the level until it reaches a limit instead of calculating
- // durations
- //assert(atkL>=0 && minL>=0);
-
- p->srate = srate;
- p->trigModeFl = trigFl;
- p->levelMin = minL;
- p->scaleDur = 1.0;
-
- cmAdsrSetTime(p,dlyMs,kDlyAdsrId);
- cmAdsrSetTime(p,atkMs,kAtkAdsrId);
- cmAdsrSetTime(p,dcyMs,kDcyAdsrId);
- cmAdsrSetTime(p,susMs,kSusAdsrId);
- cmAdsrSetTime(p,rlsMs,kRlsAdsrId);
-
- cmAdsrSetLevel(p,atkL,kAtkAdsrId);
- cmAdsrSetLevel(p,susL,kSusAdsrId);
-
- p->state = kDoneAdsrId;
- p->durSmp = 0;
- p->level = p->levelMin;
- p->gateFl = false;
-
- p->atkDurSmp = 0;
- p->rlsDurSmp = 0;
-
-
- return cmOkRC;
- }
-
- cmRC_t cmAdsrFinal( cmAdsr* p )
- { return cmOkRC; }
-
- cmReal_t cmAdsrExec( cmAdsr* p, unsigned procSmpCnt, bool gateFl, cmReal_t tscale, cmReal_t ascale )
- {
- double scaleAmp = ascale;
- double scaleDur = tscale;
-
- // if onset
- if( p->gateFl == false && gateFl==true )
- {
- p->scaleDur = scaleDur==0 ? 1.0 : fabs(scaleDur);
-
-
- //printf("sd:%f %f\n",scaleDur,scaleAmp);
-
- switch( p->state )
- {
- case kDlyAdsrId:
- // if in delay mode when the re-attack occurs don't do anything
- break;
-
- case kAtkAdsrId:
- case kDcyAdsrId:
- case kSusAdsrId:
- case kRlsAdsrId:
- // if the atk level == 0 then fall through to kDoneAdsrId
- if( p->actAtkLevel != 0 )
- {
- // re-attak mode:
- // Scale the attack time to the current level relative to the attack level.
- // In general this will result in a decrease in the attack duration.
- p->atkDurSmp = cmMax(1,floor(p->atkSmp * (p->actAtkLevel - p->level) / p->actAtkLevel));
- p->atkBegLevel = p->level;
- p->durSmp = 0;
- p->state = kAtkAdsrId;
- p->actAtkLevel = p->atkLevel * scaleAmp;
- p->actSusLevel = p->susLevel * scaleAmp;
- break;
- }
-
- case kDoneAdsrId:
- p->atkBegLevel = p->levelMin;
- p->atkDurSmp = p->atkSmp;
- p->state = p->dlySmp == 0 ? kAtkAdsrId : kDlyAdsrId;
- p->durSmp = 0;
- p->actAtkLevel = p->atkLevel * scaleAmp;
- p->actSusLevel = p->susLevel * scaleAmp;
- break;
-
- default:
- { assert(0); }
- }
- }
-
- // if an offset occurred and we are not in trigger mode - then go into release mode
- if( p->trigModeFl==false && p->gateFl == true && gateFl == false )
- {
- switch( p->state )
- {
- case kDlyAdsrId:
- case kAtkAdsrId:
- case kDcyAdsrId:
- case kSusAdsrId:
- if( p->actSusLevel == 0 )
- p->state = kDoneAdsrId;
- else
- {
- // scale the release time to the current level relative to the sustain level
- p->rlsDurSmp = cmMax(1,floor(p->rlsSmp * p->level / p->actSusLevel));
- p->rlsLevel = p->level;
- p->durSmp = 0;
- }
- break;
-
- case kRlsAdsrId:
- case kDoneAdsrId:
- // nothing to do
- break;
-
- default:
- { assert(0); }
- }
-
- p->state = kRlsAdsrId;
-
- }
-
- p->gateFl = gateFl;
-
-
-
- switch( p->state )
- {
- case kDlyAdsrId:
- p->level = p->levelMin;
-
- if( p->durSmp >= p->dlySmp )
- {
- p->state = kAtkAdsrId;
- p->durSmp = 0;
-
- if( p->trigModeFl )
- {
- p->atkBegLevel = p->level;
- p->atkDurSmp = p->atkSmp;
- }
- }
- break;
-
- case kAtkAdsrId:
- if( p->atkDurSmp != 0 )
- p->level = p->atkBegLevel + (p->actAtkLevel - p->atkBegLevel) * cmMin(p->durSmp,p->atkDurSmp) / p->atkDurSmp;
-
- if( p->durSmp >= p->atkDurSmp || p->atkDurSmp == 0 )
- {
- p->state = kDcyAdsrId;
- p->durSmp = 0;
- }
- break;
-
- case kDcyAdsrId:
- if( p->dcySmp != 0 )
- p->level = p->actAtkLevel - ((p->actAtkLevel - p->actSusLevel) * cmMin(p->durSmp,p->dcySmp) / p->dcySmp );
-
- if( p->durSmp >= p->dcySmp || p->dcySmp==0 )
- {
- p->state = kSusAdsrId;
- p->durSmp = 0;
- }
- break;
-
- case kSusAdsrId:
- p->level = p->actSusLevel;
-
- if( p->trigModeFl==true && p->durSmp >= p->susSmp )
- {
- p->state = kRlsAdsrId;
- p->durSmp = 0;
- p->rlsLevel = p->level;
- p->rlsDurSmp = p->rlsSmp;
- }
- break;
-
- case kRlsAdsrId:
- if( p->rlsDurSmp != 0 )
- p->level = p->rlsLevel - ((p->rlsLevel - p->levelMin) * cmMin(p->durSmp,p->rlsDurSmp) / p->rlsDurSmp);
-
- if( p->durSmp >= p->rlsDurSmp || p->rlsDurSmp==0 )
- {
- p->state = kDoneAdsrId;
- p->durSmp = 0;
- }
-
- break;
-
- case kDoneAdsrId:
- p->level = p->levelMin;
- break;
-
- default:
- { assert(0); }
- }
-
- p->durSmp += floor(procSmpCnt/p->scaleDur);
-
- return p->level;
- }
-
- void _cmAdsrSetTime( cmAdsr* p, cmReal_t ms, int* smpPtr )
- {
- *smpPtr = cmMax(1,floor(p->srate * ms / 1000.0 ));
- }
-
- void cmAdsrSetTime( cmAdsr* p, cmReal_t ms, unsigned id )
- {
- switch( id )
- {
- case kDlyAdsrId:
- _cmAdsrSetTime(p,ms,&p->dlySmp);
- break;
-
- case kAtkAdsrId:
- _cmAdsrSetTime(p,ms,&p->atkSmp);
- break;
-
- case kDcyAdsrId:
- _cmAdsrSetTime(p,ms,&p->dcySmp);
- break;
-
- case kSusAdsrId:
- _cmAdsrSetTime(p,ms,&p->susSmp);
- break;
-
- case kRlsAdsrId:
- _cmAdsrSetTime(p,ms,&p->rlsSmp);
- break;
-
- default:
- { assert(0); }
- }
- }
-
- void cmAdsrSetLevel( cmAdsr* p, cmReal_t level, unsigned id )
- {
- switch( id )
- {
- case kDlyAdsrId:
- p->levelMin = level;
- break;
-
- case kAtkAdsrId:
- p->atkLevel = level;
- p->actAtkLevel = p->atkLevel;
- break;
-
- case kSusAdsrId:
- p->susLevel = level;
- p->actSusLevel = p->susLevel;
- break;
-
- default:
- { assert(0); }
- }
- }
-
- void cmAdsrReport( cmAdsr* p, cmRpt_t* rpt )
- {
- cmRptPrintf(rpt,"state:%i gate:%i phs:%i d:%i a:%i (%i) d:%i s:%i r:%i (%i) - min:%f atk:%f\n",p->state,p->gateFl,p->durSmp,p->dlySmp,p->atkSmp,p->atkDurSmp,p->dcySmp,p->susSmp,p->rlsSmp,p->rlsDurSmp, p->levelMin, p->atkLevel);
- }
-
- //=======================================================================================================================
-
- cmCompressor* cmCompressorAlloc( cmCtx* c, cmCompressor* p, cmReal_t srate, unsigned procSmpCnt, cmReal_t inGain, cmReal_t rmsWndMaxMs, cmReal_t rmsWndMs, cmReal_t threshDb, cmReal_t ratio_num, cmReal_t atkMs, cmReal_t rlsMs, cmReal_t outGain, bool bypassFl )
- {
- cmCompressor* op = cmObjAlloc(cmCompressor, c, p );
-
- if( srate != 0 )
- if( cmCompressorInit( op, srate, procSmpCnt, inGain, rmsWndMaxMs, rmsWndMs, threshDb, ratio_num, atkMs, rlsMs, outGain, bypassFl ) != cmOkRC )
- cmCompressorFree(&op);
- return op;
- }
-
- cmRC_t cmCompressorFree( cmCompressor** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmCompressor* p = *pp;
-
- if((rc = cmCompressorFinal(p)) != cmOkRC )
- return rc;
-
- cmMemFree(p->rmsWnd);
- cmObjFree(pp);
-
- return cmOkRC;
-
- }
-
-
-
- cmRC_t cmCompressorInit( cmCompressor* p, cmReal_t srate, unsigned procSmpCnt, cmReal_t inGain, cmReal_t rmsWndMaxMs, cmReal_t rmsWndMs, cmReal_t threshDb, cmReal_t ratio_num, cmReal_t atkMs, cmReal_t rlsMs, cmReal_t outGain, bool bypassFl )
- {
- cmRC_t rc;
- if((rc = cmCompressorFinal(p)) != cmOkRC )
- return rc;
-
- p->srate = srate;
- p->procSmpCnt = procSmpCnt;
- p->threshDb = threshDb;
- p->ratio_num = ratio_num;
-
- cmCompressorSetAttackMs(p,atkMs);
- cmCompressorSetReleaseMs(p,rlsMs);
-
- p->inGain = inGain;
- p->outGain = outGain;
- p->bypassFl = bypassFl;
-
- p->rmsWndAllocCnt = cmMax(1,(unsigned)floor(rmsWndMaxMs * srate / (1000.0 * procSmpCnt)));
- p->rmsWnd = cmMemResizeZ(cmSample_t,p->rmsWnd,p->rmsWndAllocCnt);
- cmCompressorSetRmsWndMs(p, rmsWndMs );
- p->rmsWndIdx = 0;
-
- p->state = kRlsCompId;
- p->timeConstDb = 10.0;
- p->accumDb = p->threshDb;
-
- return rc;
- }
-
- cmRC_t cmCompressorFinal( cmCompressor* p )
- { return cmOkRC; }
-
- /*
- The ratio determines to what degree a signal above the threshold is reduced.
- Given a 2:1 ratio, a signal 2dB above the threshold will be reduced to 1db above the threshold.
- Given a 4:1 ratio, a signal 2dB above the threshold will be reduced to 0.25db above the threshold.
- Gain_reduction_db = (thresh - signal) / ratio_numerator (difference between the threshold and signal level after reduction)
- Gain Coeff = 10^(gain_reduction_db / 20);
-
- Total_reduction_db = signal - threshold + Gain_reduc_db
- (total change in signal level)
-
- The attack can be viewed as beginning at the threshold and moving to the peak
- over some period of time. In linear terms this will go from 1.0 to the max gain
- reductions. In this case we step from thresh to peak at a fixed rate in dB
- based on the attack time.
-
- Db: thresh - [thesh:peak] / ratio_num
- Linear: pow(10, (thresh - [thesh:peak] / ratio_num)/20 );
-
- During attacks p->accumDb increments toward the p->pkDb.
- During release p->accumDb decrements toward the threshold.
-
- (thresh - accumDb) / ratio_num gives the signal level which will be achieved
- if this value is converted to linear form and applied as a gain coeff.
-
- See compressor.m
- */
-
- cmRC_t cmCompressorExec( cmCompressor* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- cmSample_t xx[n];
-
- cmVOS_MultVVS(xx,n,x,p->inGain); // apply input gain
-
- p->rmsWnd[ p->rmsWndIdx ] = cmVOS_RMS(xx, n, n ); // calc and store signal RMS
- p->rmsWndIdx = (p->rmsWndIdx + 1) % p->rmsWndCnt; // advance the RMS storage buffer
-
- cmReal_t rmsLin = cmVOS_Sum(p->rmsWnd,p->rmsWndCnt) / p->rmsWndCnt; // calc avg RMS
- cmReal_t rmsDb = cmMax(-100.0,20 * log10(cmMax(0.00001,rmsLin))); // convert avg RMS to dB
- rmsDb += 100.0;
-
- // if the compressor is bypassed
- if( p->bypassFl )
- {
- cmVOS_Copy(y,n,x); // copy through - with no input gain
- return cmOkRC;
- }
-
- // if the signal is above the threshold
- if( rmsDb <= p->threshDb )
- p->state = kRlsCompId;
- else
- {
- if( rmsDb > p->pkDb )
- p->pkDb = rmsDb;
-
- p->state = kAtkCompId;
- }
-
- switch( p->state )
- {
- case kAtkCompId:
- p->accumDb = cmMin(p->pkDb, p->accumDb + p->timeConstDb * n / p->atkSmp );
- break;
-
- case kRlsCompId:
- p->accumDb = cmMax(p->threshDb, p->accumDb - p->timeConstDb * n / p->rlsSmp );
- break;
- }
-
- p->gain = pow(10.0,(p->threshDb - p->accumDb) / (p->ratio_num * 20.0));
-
- cmVOS_MultVVS(y,n,xx,p->gain * p->outGain);
-
- return cmOkRC;
- }
-
- void _cmCompressorSetMs( cmCompressor* p, cmReal_t ms, unsigned* smpPtr )
- { *smpPtr = cmMax(1,(unsigned)floor(ms * p->srate / 1000.0)); }
-
- void cmCompressorSetAttackMs( cmCompressor* p, cmReal_t ms )
- { _cmCompressorSetMs(p,ms,&p->atkSmp); }
-
- void cmCompressorSetReleaseMs( cmCompressor* p, cmReal_t ms )
- { _cmCompressorSetMs(p,ms,&p->rlsSmp); }
-
- void cmCompressorSetThreshDb( cmCompressor* p, cmReal_t threshDb )
- { p->threshDb = cmMax(0.0,100 + threshDb); }
-
- void cmCompressorSetRmsWndMs( cmCompressor* p, cmReal_t ms )
- {
- p->rmsWndCnt = cmMax(1,(unsigned)floor(ms * p->srate / (1000.0 * p->procSmpCnt)));
-
- // do not allow rmsWndCnt to exceed rmsWndAllocCnt
- if( p->rmsWndCnt > p->rmsWndAllocCnt )
- p->rmsWndCnt = p->rmsWndAllocCnt;
- }
-
- //=======================================================================================================================
-
- cmBiQuadEq* cmBiQuadEqAlloc( cmCtx* c, cmBiQuadEq* p, cmReal_t srate, unsigned mode, cmReal_t f0Hz, cmReal_t Q, cmReal_t gainDb, bool bypassFl )
- {
- cmBiQuadEq* op = cmObjAlloc(cmBiQuadEq, c, p );
-
- if( srate != 0 )
- if( cmBiQuadEqInit( op, srate, mode, f0Hz, Q, gainDb, bypassFl ) != cmOkRC )
- cmBiQuadEqFree(&op);
- return op;
- }
-
- cmRC_t cmBiQuadEqFree( cmBiQuadEq** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmBiQuadEq* p = *pp;
-
- if((rc = cmBiQuadEqFinal(p)) != cmOkRC )
- return rc;
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- void _cmBiQuadEqInit( cmBiQuadEq* p )
- {
- cmReal_t w0 = 2*M_PI*p->f0Hz/p->srate;
- cmReal_t cos_w0 = cos(w0);
- cmReal_t alpha = sin(w0)/(2*p->Q);
-
- if( p->mode==kLowShelfBqId || p->mode==kHighShelfBqId )
- {
- cmReal_t c = p->mode==kLowShelfBqId ? 1.0 : -1.0;
- cmReal_t A = pow(10.0,p->gainDb/40.0);
- cmReal_t B = 2*sqrt(A)*alpha;
-
- p->b[0] = A*( (A+1) - c * (A-1)*cos_w0 + B );
- p->b[1] = c*2*A*( (A-1) - c * (A+1)*cos_w0);
- p->b[2] = A*( (A+1) - c * (A-1)*cos_w0 - B );
- p->a[0] = (A+1) + c * (A-1)*cos_w0 + B;
- p->a[1] = -c*2*( (A-1) + c * (A+1)*cos_w0);
- p->a[2] = (A+1) + c * (A-1)*cos_w0 - B;
- }
- else
- {
- if( p->mode != kPeakBqId )
- {
- p->a[0] = 1 + alpha;
- p->a[1] = -2*cos_w0;
- p->a[2] = 1 - alpha;
- }
-
- switch(p->mode)
- {
- case kLpfBqId:
- case kHpFBqId:
- {
- cmReal_t c = p->mode==kLpfBqId ? 1.0 : -1.0;
- p->b[0] = (1 - c * cos_w0)/2;
- p->b[1] = c * (1 - c * cos_w0);
- p->b[2] = (1 - c * cos_w0)/2;
- }
- break;
-
- case kBpfBqId:
- p->b[0] = p->Q*alpha;
- p->b[1] = 0;
- p->b[2] = -p->Q*alpha;
- break;
-
- case kNotchBqId:
- p->b[0] = 1;
- p->b[1] = -2*cos_w0;
- p->b[2] = 1;
- break;
-
- case kAllpassBqId:
- p->b[0] = 1 - alpha;
- p->b[1] = -2*cos_w0;
- p->b[2] = 1 + alpha;
- break;
-
- case kPeakBqId:
- {
- cmReal_t A = pow(10.0,p->gainDb/40.0);
- p->b[0] = 1 + alpha*A;
- p->b[1] = -2*cos_w0;
- p->b[2] = 1 - alpha*A;
- p->a[0] = 1 + alpha/A;
- p->a[1] = -2*cos_w0;
- p->a[2] = 1 - alpha/A;
- }
- break;
-
- }
-
- }
-
- cmReal_t a0 = p->a[0];
- unsigned i=0;
- for(; i<3; ++i)
- {
- p->b[i]/=a0;
- p->a[i]/=a0;
- }
-
- if(0)
- {
- printf("sr:%f mode:%i f0:%f q:%f gain:%f\n", p->srate,p->mode,p->f0Hz,p->Q,p->gainDb);
-
- for(i=0; i<3; ++i)
- printf("a[%i]=%f b[%i]=%f ",i,p->a[i],i,p->b[i]);
- printf("\n");
- }
-
- }
-
- cmRC_t cmBiQuadEqInit( cmBiQuadEq* p, cmReal_t srate, unsigned mode, cmReal_t f0Hz, cmReal_t Q, cmReal_t gainDb, bool bypassFl )
- {
- cmRC_t rc;
- if((rc = cmBiQuadEqFinal(p)) != cmOkRC )
- return rc;
-
- memset(p->d,0,sizeof(p->d));
-
- p->srate = srate;
- cmBiQuadEqSet(p, mode, f0Hz, Q, gainDb );
-
- _cmBiQuadEqInit(p);
-
- return rc;
- }
-
- cmRC_t cmBiQuadEqFinal( cmBiQuadEq* p )
- { return cmOkRC;}
-
- cmRC_t cmBiQuadEqExec( cmBiQuadEq* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- if( y == NULL )
- return cmOkRC;
-
- if( x == NULL )
- {
- cmVOS_Zero(y,n);
- return cmOkRC;
- }
-
- if( p->bypassFl )
- {
- cmVOS_Copy(y,n,x);
- return cmOkRC;
- }
-
- // Direct Form I implementation
- unsigned i=0;
- for(; i<n; ++i)
- {
- y[i] = p->b[0]*x[i] + p->b[1]*p->d[0] + p->b[2]*p->d[1] - p->a[1]*p->d[2] - p->a[2]*p->d[3];
- p->d[1] = p->d[0];
- p->d[0] = x[i];
- p->d[3] = p->d[2];
- p->d[2] = y[i];
- }
-
- return cmOkRC;
- }
-
-
- void cmBiQuadEqSet( cmBiQuadEq* p, unsigned mode, cmReal_t f0Hz, cmReal_t Q, cmReal_t gainDb )
- {
- p->mode = mode;
- p->f0Hz = f0Hz;
- p->Q = Q;
- p->gainDb= gainDb;
- _cmBiQuadEqInit(p);
- }
-
- //=======================================================================================================================
-
- cmDistDs* cmDistDsAlloc( cmCtx* c, cmDistDs* p, cmReal_t srate, cmReal_t inGain, cmReal_t downSrate, cmReal_t bits, bool rectFl, bool fullFl, cmReal_t clipDb, cmReal_t outGain, bool bypassFl )
- {
- cmDistDs* op = cmObjAlloc(cmDistDs, c, p );
-
- if( srate != 0 )
- if( cmDistDsInit( op, srate, inGain, downSrate, bits, rectFl, fullFl, clipDb, outGain, bypassFl ) != cmOkRC )
- cmDistDsFree(&op);
- return op;
-
- }
-
- cmRC_t cmDistDsFree( cmDistDs** pp )
- {
- cmRC_t rc = cmOkRC;
-
- if( pp == NULL || *pp == NULL )
- return cmOkRC;
-
- cmDistDs* p = *pp;
-
- if((rc = cmDistDsFinal(p)) != cmOkRC )
- return rc;
-
- cmObjFree(pp);
-
- return cmOkRC;
- }
-
- cmRC_t cmDistDsInit( cmDistDs* p, cmReal_t srate, cmReal_t inGain, cmReal_t downSrate, cmReal_t bits, bool rectFl, bool fullFl, cmReal_t clipDb, cmReal_t outGain, bool bypassFl )
- {
- cmRC_t rc;
- if((rc = cmDistDsFinal(p)) != cmOkRC )
- return rc;
-
- p->srate = srate;
- p->downSrate = downSrate;
- p->bits = bits;
- p->rectFl = rectFl;
- p->fullFl = fullFl;
- p->clipDb = clipDb;
- p->inGain = inGain;
- p->outGain = outGain;
- p->bypassFl = bypassFl;
- p->fracIdx = 0;
- p->lastVal = 0;
- p->lastY = 0;
- p->lastX = 0;
- return rc;
- }
-
- cmRC_t cmDistDsFinal( cmDistDs* p )
- { return cmOkRC; }
-
- void _cmDistDsExpr0( cmDistDs* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- unsigned i= 0;
- for(i=0; i<n; ++i)
- {
- p->lastY = fmod(p->lastY + fabs(x[i] - p->lastX),2.0);
- y[i] = cmVOS_RMS(x,n,n) * x[i] * (p->lastY - 1.0);
- p->lastX = x[i];
- }
- }
-
- void _cmDistDsExpr1( cmDistDs* p, cmSample_t* x, cmSample_t* y, unsigned n )
- {
- unsigned i= 0;
- for(i=0; i<n; ++i)
- {
- p->lastY = fmod(p->lastY + fabs(x[i] - p->lastX),2.0*M_PI);
- y[i] = x[i] * sin(p->lastY);
- p->lastX = x[i];
- }
- }
-
-
-
- cmRC_t cmDistDsExec( cmDistDs* p, const cmSample_t* x, cmSample_t* y, unsigned n )
- {
- if( x == NULL )
- {
- if( y != NULL )
- cmVOS_Zero(y,n);
- return cmOkRC;
- }
-
- if( p->bypassFl )
- {
- cmVOS_Copy(y,n,x);
- return cmOkRC;
- }
-
-
- unsigned maxVal = cmMax(2,(unsigned)round(pow(2.0,p->bits)));
- double incr = 1.0; // p->downSrate / p->srate;
- unsigned i;
- enum { kNoRectId, kFullRectId, kHalfRectId };
- unsigned rectCode = kNoRectId;
-
- //cmSample_t t[n];
- //_cmDistDsExpr0(p,x,t,n);
- //x = t;
-
- if( p->rectFl )
- {
-
- if( p->fullFl )
- rectCode = kFullRectId;
- else
- rectCode = kHalfRectId;
- }
-
- double clipLevel = p->clipDb < -100.0 ? 0.0 : pow(10.0,p->clipDb/20.0);
-
- for(i=0; i<n; ++i)
- {
- double ii = floor(p->fracIdx);
-
- p->fracIdx += incr;
-
- // if it is time to sample again
- if( floor(p->fracIdx) != ii )
- {
- cmSample_t v = p->inGain * floor(x[i] * maxVal) / maxVal;
-
- switch( rectCode )
- {
- case kFullRectId:
- v = (cmSample_t)fabs(v);
- break;
-
- case kHalfRectId:
- if( v < 0.0 )
- v = 0.0;
- break;
- }
-
- if( fabs(v) > clipLevel )
- v = v<0.0 ? -clipLevel : clipLevel;
-
- p->lastVal = v * p->outGain;
- }
-
- y[i] = p->lastVal;
- }
-
- return cmOkRC;
- }
|