123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672 |
- #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 "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;
- }
|