12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656 |
- #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;
- }
-
- //==========================================================================================================================================
- 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;
- }
|