1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 //Concat, Concat2: real-time concatenative synthesis UGens by Nick Collins (after Schwarz, Casey, Sturm et al)
22 //originally for my PhD 2006
23
24 //I developed for 44100 sample rate, with 256 FFT (without overlap) for low latency operation. It will probably work at 48000 without major problems
25 //assumes block size is 64
26
27 //features- ZCR over last 1024 samples = 4 frames, RMS energy over frame, then from the FFT- spec centroid, spec variance, spec rolloff
28
29 #include "SC_PlugIn.h"
30 //#include "SCComplex.h"
31 //#include "FFT_UGens.h"
32 #include "SC_fftlib.h"
33 //#include "SC_Constants.h"
34 //
35 //#include <vecLib/vecLib.h>
36 //#include <string.h>
37 //#include <math.h>
38 //#include <stdlib.h>
39 #include <stdio.h>
40
41 static InterfaceTable *ft;
42
43 struct Concat : Unit {
44
45 //essential constants
46 int m_sr;
47 int m_blocksize;
48 int m_fftsize;
49 int m_nover2;
50 int m_blocksperframe;
51 int m_samplesforzcr;
52
53 //FFT data
54 int m_bufWritePos;
55
56 scfft *m_scfftsource, *m_scfftcontrol;
57 float * m_FFTBufsource, *m_FFTBufcontrol;
58
59 //To fix a database once captured enough
60 int m_freezestore;
61
62 //stored samples
63
64 float * m_controlstore;
65 float * m_sourcestore;
66 int m_controlcounter;
67 int m_sourcecounter;
68 int m_sourcesize;
69 int m_controlsize;
70
71 //stored features (for source stream only)
72 int m_sourceframes;
73 int m_featurecounter;
74
75 //time domain
76 float * m_rms;
77 float * m_zcr;
78
79 //frequency domain
80 float * m_speccentroid;
81 float * m_spectilt;
82
83 //control playback
84 int m_matchlocation;
85 int m_matchcounter;
86 int m_matchframes;
87 int m_fadeoutlocation;
88
89 };
90
91 struct Concat2 : public Concat {
92
93 int m_nover4;
94 float m_matchamp,m_fadeoutamp; //will also scale based on input amplitude, to avoid noise when no significant input
95
96 };
97
98
99 extern "C"
100 {
101 //required interface functions
102 void Concat_next(Concat *unit, int numSamples);
103 void Concat_Ctor(Concat *unit);
104 void Concat_Dtor(Concat *unit);
105
106 int Concat_CtorCommon(Concat *unit);
107 void Concat_DtorCommon(Concat *unit);
108
109 void Concat2_next(Concat2 *unit, int numSamples);
110 void Concat2_Ctor(Concat2 *unit);
111 void Concat2_Dtor(Concat2 *unit);
112
113 }
114
115 //other functions
116 void Concat_dofft(Concat *unit, scfft *, float *); //call FFT and in place data to powers
117 void sourcefeatures(Concat *unit, float * fftbuf);
118 void matchfeatures(Concat *unit, float * fftbuf);
119 float calcst(float * fftbuf);
120 float calcsc(float * fftbuf, int nover2);
121 float calcsc2(float * fftbuf, int nover2);
122 void sourcefeatures2(Concat2 *unit, float * fftbuf);
123 void matchfeatures2(Concat2 *unit, float * fftbuf);
124
125
126
Concat_CtorCommon(Concat * unit)127 int Concat_CtorCommon(Concat *unit) {
128
129 //CHECK SAMPLING RATE AND BUFFER SIZE
130 unit->m_blocksize = unit->mWorld->mFullRate.mBufLength;
131
132 if(unit->m_blocksize!=64) {
133 printf("Concat complains: block size not 64, you have %d\n", unit->m_blocksize);
134 return 0;
135 }
136
137 unit->m_sr = unit->mWorld->mSampleRate; //(int)(unit->mWorld->mSampleRate+0.1);
138
139 if(unit->m_sr!=44100) {
140 printf("Concat complains: sample rate not 44100, you have %d\n", unit->m_sr);
141 //return 0; //not necessarily catastrophic
142 }
143
144 //printf("sr %d block size %d \n", unit->m_sr, unit->m_blocksize);
145
146 ///set up sizes
147
148 unit->m_fftsize=256; //could make conditional on SR, blocksize must divide this!
149
150 unit->m_nover2=unit->m_fftsize/2;
151
152 unit->m_blocksperframe=unit->m_fftsize/unit->m_blocksize; //should be an integer- excat if power of two, else an approximation (good enough for RMS, zerocrossing counts)
153
154 unit->m_samplesforzcr= (unit->m_blocksperframe*unit->m_blocksize)*4; //will also give number of stored samples of the control input, calculated in this way to guarantee an integer
155
156 ////////FFT data///////////
157
158 unit->m_FFTBufsource = (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float));
159 unit->m_FFTBufcontrol = (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float));
160
161 //unit->m_FFTBufsourceafter = (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float));
162 //unit->m_FFTBufcontrolafter = (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float));
163
164 unit->m_bufWritePos = 0;
165
166
167 SCWorld_Allocator alloc(ft, unit->mWorld);
168 //no overlap
169 unit->m_scfftsource = scfft_create(unit->m_fftsize, unit->m_fftsize, kHannWindow, unit->m_FFTBufsource, unit->m_FFTBufsource, kForward, alloc);
170 unit->m_scfftcontrol = scfft_create(unit->m_fftsize, unit->m_fftsize, kHannWindow, unit->m_FFTBufcontrol, unit->m_FFTBufcontrol, kForward, alloc);
171
172 //stores
173 unit->m_sourcesize=(((int)(floor(ZIN0(2)*unit->m_sr + .5f)))/(unit->m_fftsize))*(unit->m_fftsize); //integer divide then multiply to make sure its an integer multiple of frames
174 unit->m_controlsize= unit->m_samplesforzcr;
175
176 unit->m_controlstore = (float*)RTAlloc(unit->mWorld, unit->m_controlsize * sizeof(float));
177 unit->m_sourcestore= (float*)RTAlloc(unit->mWorld, unit->m_sourcesize * sizeof(float));;
178 unit->m_controlcounter=0;
179 unit->m_sourcecounter=0;
180
181 Clear(unit->m_controlsize, unit->m_controlstore);
182 Clear(unit->m_sourcesize, unit->m_sourcestore);
183
184 //features
185 unit->m_sourceframes= unit->m_sourcesize/unit->m_fftsize; //should divide perfectly due to earlier correction
186 unit->m_featurecounter=0;
187
188 unit->m_rms= (float*)RTAlloc(unit->mWorld, unit->m_sourceframes * sizeof(float));
189 unit->m_zcr= (float*)RTAlloc(unit->mWorld, unit->m_sourceframes * sizeof(float));
190 unit->m_speccentroid= (float*)RTAlloc(unit->mWorld, unit->m_sourceframes * sizeof(float));
191 unit->m_spectilt= (float*)RTAlloc(unit->mWorld, unit->m_sourceframes * sizeof(float));
192
193 Clear(unit->m_sourceframes, unit->m_rms);
194 Clear(unit->m_sourceframes, unit->m_zcr);
195 Clear(unit->m_sourceframes, unit->m_speccentroid);
196 Clear(unit->m_sourceframes, unit->m_spectilt);
197
198 //match setup
199 unit->m_matchlocation=0;
200 unit->m_matchcounter=1; //immediately seek a match
201 unit->m_matchframes=1;
202 unit->m_fadeoutlocation= (-1); //negative means do nothing
203
204 return 1;
205
206 }
207
Concat_DtorCommon(Concat * unit)208 void Concat_DtorCommon(Concat *unit) {
209
210 if(unit->m_scfftsource) {
211 SCWorld_Allocator alloc(ft, unit->mWorld);
212 scfft_destroy(unit->m_scfftsource, alloc);
213 scfft_destroy(unit->m_scfftcontrol, alloc);
214 }
215
216 RTFree(unit->mWorld, unit->m_FFTBufsource);
217 RTFree(unit->mWorld, unit->m_FFTBufcontrol);
218 //RTFree(unit->mWorld, unit->m_hanning);
219
220 RTFree(unit->mWorld, unit->m_controlstore);
221 RTFree(unit->mWorld, unit->m_sourcestore);
222
223 RTFree(unit->mWorld, unit->m_rms);
224 RTFree(unit->mWorld, unit->m_zcr);
225 RTFree(unit->mWorld, unit->m_speccentroid);
226 RTFree(unit->mWorld, unit->m_spectilt);
227
228
229 }
230
231
232
233
Concat_Ctor(Concat * unit)234 void Concat_Ctor(Concat* unit) {
235
236 int check = Concat_CtorCommon(unit);
237
238 if (check==1)
239 unit->mCalcFunc = (UnitCalcFunc)&Concat_next;
240 else
241 {
242 SETCALC(*ClearUnitOutputs);
243 unit->mDone = true;
244 }
245 }
246
247
248
249
Concat2_Ctor(Concat2 * unit)250 void Concat2_Ctor(Concat2* unit) {
251
252 int check = Concat_CtorCommon(unit);
253
254 if (check==1) {
255
256 unit->m_nover4=unit->m_fftsize/4;
257
258 unit->m_matchamp=0.0;
259 unit->m_fadeoutamp=0.0;
260
261 unit->mCalcFunc = (UnitCalcFunc)&Concat2_next;
262
263 }
264 else {
265 SETCALC(*ClearUnitOutputs);
266 unit->mDone = true;
267 }
268 }
269
270
271
272
273
Concat_Dtor(Concat * unit)274 void Concat_Dtor(Concat *unit)
275 {
276
277 Concat_DtorCommon(unit);
278
279 }
280
Concat2_Dtor(Concat2 * unit)281 void Concat2_Dtor(Concat2 *unit)
282 {
283
284 Concat_DtorCommon(unit);
285
286 }
287
Concat_next(Concat * unit,int numSamples)288 void Concat_next(Concat *unit, int numSamples) {
289
290 float *controlin = IN(0);
291 float *sourcein = IN(1);
292
293 float *output = ZOUT(0);
294
295 float * store=unit->m_sourcestore;
296
297 int sourcecounter= unit->m_sourcecounter;
298 int sourcesize=unit->m_sourcesize;
299
300 float * control=unit->m_controlstore;
301 int controlcounter= unit->m_controlcounter;
302 int controlsize=unit->m_controlsize;
303
304 int bufpos= unit->m_bufWritePos;
305
306 float * fftbuf1=unit->m_FFTBufsource;
307 float * fftbuf2=unit->m_FFTBufcontrol;
308
309 float freeze = ZIN0(6);
310
311 for(int j=0; j<numSamples; ++j) {
312
313 float val1=sourcein[j];
314 float val2= controlin[j];
315
316 //only write into buffer if allowed
317 if(freeze<0.5) {
318 store[sourcecounter]= val1;
319
320 sourcecounter= (sourcecounter+1)%sourcesize;
321 }
322
323 fftbuf1[bufpos]=val1;
324
325 control[controlcounter]= val2;
326 controlcounter= (controlcounter+1)%controlsize;
327 fftbuf2[bufpos]=val2;
328
329 ++bufpos;
330 }
331
332 unit->m_sourcecounter=sourcecounter;
333 unit->m_controlcounter=controlcounter;
334
335 if (bufpos==unit->m_fftsize) {
336
337 //only update source features if recording
338 if (freeze<0.5) {
339 //frame ready- could be within if?
340 Concat_dofft(unit,unit->m_scfftsource, fftbuf1);
341 //calc source FFT and features to store
342 sourcefeatures(unit,fftbuf1);
343 }
344
345
346 //if new match required
347 //calc control FFT and features for match
348 if(unit->m_matchcounter>= unit->m_matchframes) {
349
350 Concat_dofft(unit,unit->m_scfftcontrol, fftbuf2);
351 matchfeatures(unit, fftbuf2);
352
353 } else
354 //otherwise increase matchcounter (it was reset in the other branch)
355 ++unit->m_matchcounter;
356
357 //feature counter ALWAYS updated to keep in step with write position- updated after matchfeatures so matchfeatures references to the nearest last frame
358 unit->m_featurecounter=(unit->m_featurecounter+1)%(unit->m_sourceframes);
359
360
361 //restart FFT data collection
362 bufpos=0;
363 }
364
365 unit->m_bufWritePos=bufpos;
366
367 int readpos= unit->m_matchlocation;
368
369 int fadepos= unit->m_fadeoutlocation;
370
371 //crossfade on this block
372 if(fadepos>=0) {
373
374 for (int i=0; i<numSamples; ++i) {
375
376 float fade= (float)i/((float)numSamples);
377 //fade *= fade;
378
379 *++output = ((1.0-fade)*store[fadepos]) + (fade*store[readpos]);
380 ++readpos;
381 ++fadepos;
382 }
383
384 unit->m_fadeoutlocation = (-1);
385 } else { //else just read
386
387 for (int i=0; i<numSamples; ++i) {
388 *++output = store[readpos];
389 ++readpos;
390 }
391
392 }
393
394 //only need to modulo here since 64 always divides store size
395 unit->m_matchlocation= (readpos)%sourcesize;
396
397 }
398
399
400
Concat2_next(Concat2 * unit,int numSamples)401 void Concat2_next(Concat2 *unit, int numSamples)
402 {
403 float *controlin = IN(0);
404 float *sourcein = IN(1);
405
406 float *output = ZOUT(0);
407
408 float * store=unit->m_sourcestore;
409
410 int sourcecounter= unit->m_sourcecounter;
411 int sourcesize=unit->m_sourcesize;
412
413 float * control=unit->m_controlstore;
414 int controlcounter= unit->m_controlcounter;
415 int controlsize=unit->m_controlsize;
416
417 int bufpos= unit->m_bufWritePos;
418
419 float * fftbuf1=unit->m_FFTBufsource;
420 float * fftbuf2=unit->m_FFTBufcontrol;
421
422 float freeze = ZIN0(6);
423
424 for(int j=0; j<numSamples; ++j) {
425
426 float val1=sourcein[j];
427 float val2= controlin[j];
428
429 //only write into buffer if allowed
430 if(freeze<0.5) {
431 store[sourcecounter]= val1;
432
433 sourcecounter= (sourcecounter+1)%sourcesize;
434 }
435
436 fftbuf1[bufpos]=val1;
437
438 control[controlcounter]= val2;
439 controlcounter= (controlcounter+1)%controlsize;
440 fftbuf2[bufpos]=val2;
441
442 ++bufpos;
443 }
444
445 unit->m_sourcecounter=sourcecounter;
446 unit->m_controlcounter=controlcounter;
447
448 if (bufpos==unit->m_fftsize) {
449
450 //printf("fft block\t");
451
452 //frame ready
453 Concat_dofft(unit,unit->m_scfftsource, fftbuf1);
454
455 //only update source features if recording
456 if (freeze<0.5)
457 //calc source FFT and features to store
458 sourcefeatures2(unit,fftbuf1);
459
460 //frame ready, amazingly, this line was missing before! so was calculating based on time domain versus frequency domain!
461
462 if(unit->m_matchcounter>= unit->m_matchframes) {
463 //if new match required
464 //calc control FFT and features for match
465 Concat_dofft(unit,unit->m_scfftcontrol, fftbuf2);
466 matchfeatures2(unit, fftbuf2);
467
468 } else
469 //otherwise increase matchcounter (it was reset in the other branch)
470 ++unit->m_matchcounter;
471
472 //feature counter ALWAYS updated to keep in step with write position- updated after matchfeatures so matchfeatures references to the nearest last frame
473 unit->m_featurecounter=(unit->m_featurecounter+1)%(unit->m_sourceframes);
474
475
476 //restart FFT data collection
477 bufpos=0;
478 }
479
480 unit->m_bufWritePos=bufpos;
481
482 int readpos= unit->m_matchlocation;
483
484 int fadepos= unit->m_fadeoutlocation;
485
486 float readamp= unit->m_matchamp;
487
488 float fadeamp= unit->m_fadeoutamp;
489
490 //crossfade on this block
491 if(fadepos>=0) {
492
493 for (int i=0; i<numSamples; ++i) {
494
495 float fade= (float)i/((float)numSamples);
496 //fade *= fade;
497
498 *++output = ((1.0-fade)*store[fadepos]*fadeamp) + (fade*store[readpos]*readamp);
499 ++readpos;
500 ++fadepos;
501 }
502
503 unit->m_fadeoutlocation = (-1);
504 } else { //else just read
505
506 for (int i=0; i<numSamples; ++i) {
507 *++output = store[readpos]*readamp;
508 ++readpos;
509 }
510
511 }
512
513 //only need to modulo here since 64 always divides store size
514 unit->m_matchlocation= (readpos)%sourcesize;
515
516 }
517
518
519
520
521
522 //calculated with SC findlogbins program
523
524 //find log bins program for 10 bins, for sr=44100, fftsize=256
525 //
526 //(
527 //var sr, binsize, fftsize, nyquist, num, numbins, divisions;
528 //var logbin;
529 //var top, bottom;
530 //var tmp;
531 //
532 //sr=44100;
533 //fftsize=256;
534 //numbins=fftsize.div(2);
535 //
536 //binsize=sr/fftsize;
537 //
538 //num=10;
539 //
540 //nyquist= sr*0.5;
541 //
542 //top= log10(nyquist);
543 //bottom=log10(binsize);
544 //
545 //tmp= (top-bottom)*((num).reciprocal);
546 //
547 //divisions=bottom+Array.series(num,tmp,tmp);
548 //
549 //Post << divisions << nl;
550 //
551 ////logbin= Array.fill(numbins, {arg i; log10((i+1)*binsize +0.001)});
552 //
553 ////invert to find bin positions
554 //((10**divisions)/binsize).floor.asInteger; //.round(1.0).asInteger
555 //)
556
557 int stbins[11]= {0, 1, 2, 4, 6, 11, 18, 29, 48, 78, 128 };
558
559 //avoid bin 0
560 //int stbins[11]= {1, 2, 3, 5, 9, 14, 21, 34, 52, 82, 128};
561
calcst(float * fftbuf)562 float calcst(float * fftbuf) {
563
564 int i;
565
566 float sum;
567
568 //take bins into 10 log spaced bins (averaging power), take log of the power, calculate the slope of the least-squares line ((8) prob and stats, p280 , 2nd ed., Schaum's)
569 float average[10];
570
571 int j, firstindex, secondindex;
572
573 float avav=0.0;
574
575 for (i=0; i<10; ++i) {
576
577 sum=0.0;
578
579 firstindex=stbins[i];
580 secondindex=stbins[i+1];
581
582 for (j=firstindex; j<secondindex; ++j) {
583 sum += fftbuf[j];
584 }
585
586 average[i]= log10(sum/(secondindex-firstindex)+0.001);
587 avav +=average[i];
588 }
589
590 avav /=10;
591
592 float topsum=0.0, bottomsum=0.0;
593 float tmp;
594
595 for (i=0; i<10; ++i) {
596
597 tmp=(average[i]-avav);
598
599 topsum += tmp*((i+1)-5.5);
600 bottomsum += tmp*tmp;
601
602 }
603
604 float st;
605
606 if (bottomsum>0.001)
607 st= topsum/bottomsum;
608 else
609 st=(-1000.0);
610
611 //
612 // if(st<0.0) st= -(log10(1-st));
613 // else st= log10(1+st);
614 //
615 // //clamp
616 // if(st<-2) st=-2;
617 // if (st>2) st=2;
618 //
619 // st= (st+2)*0.25;
620 //
621
622 st= atan(st); //now between -pi/2 and pi/2
623
624 st= (st+pi2)/pi;
625
626 //printf("c1 %f avav %f topsum %f bottomsum %f st %f test %f test2 %f \n", average[0], avav, topsum, bottomsum, st, topsum/bottomsum, atan(topsum/bottomsum));
627
628 return st;
629
630 }
631
632
calcsc(float * fftbuf,int nover2)633 float calcsc(float * fftbuf, int nover2) {
634
635 int i;
636 float sum=1.0f, val;
637 float centroid=0.0f;
638
639 for (i=1; i<nover2; ++i) {
640
641 val= fftbuf[i];
642
643 centroid+= val*i;
644 sum+= val;
645 }
646
647 //printf("sum %f\n", sum);
648 //centroid=centroid/sum;
649
650 //avoid division by zero threat
651 if(sum>0.01f)
652 centroid=centroid/sum;
653 else
654 centroid=centroid;
655
656 centroid=log2((centroid/(nover2))+1.0f);
657
658 return centroid; //normalised bin location
659 }
660
661
662
calcsc2(float * fftbuf,int nover2)663 float calcsc2(float * fftbuf, int nover2) {
664
665 int i;
666 float sum=1.0f, val;
667 float centroid=0.0f;
668
669 for (i=1; i<nover2; ++i) {
670
671 val= log(fftbuf[i]+1); //no log before!
672
673 centroid+= val*i;
674 sum+= val;
675 }
676
677 //causes divide by zero
678 //centroid=centroid/sum;
679
680 if(sum>0.01f)
681 centroid=centroid/sum;
682 else
683 centroid=centroid;
684
685 centroid=log2((centroid/(nover2))+1);
686
687 return centroid; //normalised bin location
688 }
689
690
691
sourcefeatures(Concat * unit,float * fftbuf)692 void sourcefeatures(Concat *unit, float * fftbuf) {
693 int i, pos;
694
695 float * store=unit->m_sourcestore;
696
697 int sourcecounter= unit->m_sourcecounter;
698 int sourcesize=unit->m_sourcesize;
699
700 int featurecounter= unit->m_featurecounter;
701
702 ////////ZCR feature (counts - to + only)
703
704 int zcrsize= unit->m_samplesforzcr;
705
706 int zcrstart= (sourcecounter + sourcesize- zcrsize)%sourcesize;
707
708 int zcrcount=0;
709
710 float prevval=0.0, val;
711
712 for (i=0; i<zcrsize; ++i) {
713
714 pos= (zcrstart+i)%sourcesize;
715
716 val= store[pos];
717
718 if ((val>=(-0.00000001)) && (prevval<0.00000001))
719 ++zcrcount;
720
721 prevval=val;
722 }
723
724 float zcrfeature= log10(zcrcount/(0.5*zcrsize*0.2)+1);
725
726 if(zcrfeature>2) zcrfeature=2;
727
728 unit->m_zcr[featurecounter]= zcrfeature*0.5; //normalise how? divide by zcrsize/2 or more and clamp to 1? Could correct with weighting
729
730 ////RMS
731 int framesize=unit->m_fftsize;
732 int framestart= (sourcecounter + sourcesize- framesize)%sourcesize;
733
734 //float sum=0.0;
735 float maxrms=0.0;
736
737 for (i=0; i<framesize; ++i) {
738
739 pos= (framestart+i)%sourcesize;
740
741 val= store[pos];
742
743 val=val*val;
744
745 if(val>maxrms) {
746 maxrms=val;
747 }
748
749 //sum+= val*val;
750 }
751
752 //sum=sum/framesize;
753
754 //take into pseudo-decibels to even out volume differences on a more psychoacoustic scale
755 unit->m_rms[featurecounter]= log10(1+(maxrms*9)); //sqrt(sum/framesize); //root mean square from 0.0 to 1.0
756
757 //printf("SOURCE rms %f counter %d\n",unit->m_rms[featurecounter], featurecounter);
758
759
760 unit->m_speccentroid[featurecounter]=calcsc(fftbuf, unit->m_nover2);
761
762 //spectral tilt
763 unit->m_spectilt[featurecounter]=calcst(fftbuf);
764
765 //update
766 //printf("zcr %f rms %f sc %f st %f counter %d\n",unit->m_zcr[featurecounter],unit->m_rms[featurecounter],unit->m_speccentroid[featurecounter],unit->m_spectilt[featurecounter], featurecounter);
767
768 }
769
770
771
772
773
774
775 //calculate features for current control input then find a match in the source
matchfeatures(Concat * unit,float * fftbuf)776 void matchfeatures(Concat *unit, float * fftbuf) {
777 int i, pos;
778
779 float * store=unit->m_controlstore;
780
781 int controlcounter= unit->m_controlcounter;
782 int controlsize=unit->m_controlsize;
783
784 ////////ZCR feature (counts - to + only)
785 int zcrsize= unit->m_samplesforzcr;
786
787 int zcrcount=0;
788
789 float prevval=0.0, val;
790
791 for (i=0; i<zcrsize; ++i) {
792
793 val= store[i];
794
795 if ((val>=(-0.00000001)) && (prevval<0.00000001))
796 ++zcrcount;
797
798 prevval=val;
799 }
800
801 float zcrfeature= log10(zcrcount/(0.5*zcrsize*0.2)+1);
802
803 if(zcrfeature>2) zcrfeature=2;
804
805 zcrfeature= zcrfeature*0.5;
806
807 //float zcrfeature= zcrcount/(0.5*zcrsize); //normalise how? divide by zcrsize/2 or more and clamp to 1? Could correct with weighting
808
809 ////RMS
810 int framesize=unit->m_fftsize;
811 int framestart= (controlcounter + controlsize- framesize)%controlsize;
812
813 //float sum=0.0;
814 float maxrms=0.0;
815
816 for (i=0; i<framesize; ++i) {
817
818 pos= (framestart+i)%controlsize;
819
820 val= store[pos];
821
822 val=val*val;
823
824 if(val>maxrms) {
825 maxrms=val;
826 }
827
828 //sum+= val*val;
829 }
830
831 //sum/framesize
832 float rmsfeature= log10(1+((maxrms)*9)); //sqrt(sum/framesize); //root mean square from 0.0 to 1.0
833
834 //printf("TARGET rms %f\n",rmsfeature);
835
836 float scfeature=calcsc(fftbuf, unit->m_nover2);
837
838 float stfeature=calcst(fftbuf);
839
840 //find locations to search
841 float seekstart= ZIN0(3); //in seconds
842 float seekdur= ZIN0(4); //in seconds
843
844 int featurecounter= unit->m_featurecounter;
845
846
847 int sourceframes= unit->m_sourceframes;
848
849 int beginsearch= (featurecounter + sourceframes - ((int)((seekstart*unit->m_sr)/(unit->m_fftsize))))%(sourceframes);
850 int searchlength= (int)((seekdur*unit->m_sr)/(unit->m_fftsize));
851
852 searchlength= sc_max(searchlength,1);
853
854 //find best match
855
856 float * zcr= unit->m_zcr;
857 float * rms= unit->m_rms;
858 float * sc= unit->m_speccentroid;
859 float * st= unit->m_spectilt;
860
861 float zcrweight= ZIN0(7);
862 float rmsweight= ZIN0(8);
863 float scweight= ZIN0(9);
864 float stweight= ZIN0(10);
865
866 int best=0;
867 float bestscore= 1000000000.0;
868
869 float zcrdiff, rmsdiff, scdiff, stdiff, score;
870
871 //not sure if I like this or not!
872 float randscore= ZIN0(11);
873
874 RGen& rgen = *unit->mParent->mRGen;
875
876 for (i=0; i<searchlength; ++i) {
877
878 pos= (beginsearch+i)%sourceframes;
879
880 zcrdiff= zcrfeature- zcr[pos];
881 rmsdiff= rmsfeature- rms[pos];
882 scdiff= scfeature- sc[pos];
883 stdiff= stfeature- st[pos];
884
885 score= zcrweight*(zcrdiff*zcrdiff) + rmsweight*(rmsdiff*rmsdiff) + scweight*(scdiff*scdiff) + stweight*(stdiff*stdiff)+(rgen.frand()*randscore);
886
887 //could add match randomisation factor here score=score+ZIN0()
888
889 if (score< bestscore) {
890 bestscore= score;
891 best=i;
892 }
893 }
894
895 int answer= (beginsearch+best)%sourceframes;
896
897 //printf("zcr %f rms %f sc %f\n",zcrfeature,rmsfeature,scfeature);
898
899 zcrdiff= zcrfeature- zcr[answer];
900 rmsdiff= rmsfeature- rms[answer];
901 scdiff= scfeature- sc[answer];
902
903 score= zcrweight*(zcrdiff*zcrdiff) + rmsweight*(rmsdiff*rmsdiff) + scweight*(scdiff*scdiff);
904
905 //printf("zcrdiff %f rmsdiff %f scdiff %f score %f answer %d\n",zcrdiff,rmsdiff,scdiff,score, answer);
906
907 //store best match sample and reset read pointer and fft frame counter
908 //setting read out on current sample read
909
910 unit->m_fadeoutlocation= unit->m_matchlocation; //next sample to be read now faded
911 unit->m_matchlocation=answer*(unit->m_fftsize);
912 unit->m_matchcounter=0;
913
914 float matchlength= ZIN0(5);
915
916 int matchframes= (int)((matchlength*unit->m_sr)/(unit->m_fftsize));
917
918 unit->m_matchframes= sc_max(matchframes,1);
919
920 //printf("begin %d length %d answer %d\n",beginsearch, searchlength, answer);
921
922 }
923
924
925
926
927
928
sourcefeatures2(Concat2 * unit,float * fftbuf)929 void sourcefeatures2(Concat2 *unit, float * fftbuf) {
930 int i, pos;
931
932 float * store=unit->m_sourcestore;
933
934 int sourcecounter= unit->m_sourcecounter;
935 int sourcesize=unit->m_sourcesize;
936
937 int featurecounter= unit->m_featurecounter;
938
939 ////////ZCR feature (counts - to + only)
940
941 int zcrsize= unit->m_samplesforzcr;
942
943 int zcrstart= (sourcecounter + sourcesize- zcrsize)%sourcesize;
944
945 int zcrcount=0;
946
947 float prevval=0.0, val;
948
949 for (i=0; i<zcrsize; ++i) {
950
951 pos= (zcrstart+i)%sourcesize;
952
953 val= store[pos];
954
955 if ((val>=(-0.00000001)) && (prevval<0.00000001))
956 ++zcrcount;
957
958 prevval=val;
959 }
960
961 float zcrfeature= log10(zcrcount/(0.5*zcrsize*0.2)+1);
962
963 if(zcrfeature>2) zcrfeature=2;
964
965 unit->m_zcr[featurecounter]= zcrfeature*0.5; //normalise how? divide by zcrsize/2 or more and clamp to 1? Could correct with weighting
966
967 ////RMS
968 int framesize=unit->m_fftsize;
969 int framestart= (sourcecounter + sourcesize- framesize)%sourcesize;
970
971 float maxrms=0.0; //sum=0.0,
972
973 for (i=0; i<framesize; ++i) {
974
975 pos= (framestart+i)%sourcesize;
976
977 val= store[pos];
978
979 val=val*val;
980
981 if(val>maxrms) {
982 maxrms=val;
983 }
984
985 //sum+= val*val;
986 }
987
988 //sum=sum/framesize;
989
990 //rmsfeature= sc_min(rmsfeature,1.0); //if want clamped to 1
991
992 //take into pseudo-decibels to even out volume differences on a more psychoacoustic scale
993 unit->m_rms[featurecounter]= log10(1+(maxrms*9)); //sqrt(sum/framesize); //root mean square from 0.0 to 1.0
994
995 //printf("SOURCE rms %f counter %d\n",unit->m_rms[featurecounter], featurecounter);
996
997
998 unit->m_speccentroid[featurecounter]=sc_min(2*calcsc2(fftbuf, unit->m_nover4),1.0); //was unit->m_nover2 and no clamp
999
1000 //spectral tilt
1001 unit->m_spectilt[featurecounter]=calcst(fftbuf);
1002
1003 //update
1004 //printf("zcr %f rms %f sc %f st %f counter %d\n",unit->m_zcr[featurecounter],unit->m_rms[featurecounter],unit->m_speccentroid[featurecounter],unit->m_spectilt[featurecounter], featurecounter);
1005
1006 }
1007
1008
1009
1010
1011
1012
1013 //calculate features for current control input then find a match in the source
matchfeatures2(Concat2 * unit,float * fftbuf)1014 void matchfeatures2(Concat2 *unit, float * fftbuf) {
1015 int i, pos;
1016 float val;
1017 int matchfailure;
1018
1019 float threshold= ZIN0(12);
1020
1021 matchfailure= 0;
1022
1023 float * store=unit->m_controlstore;
1024
1025 int controlcounter= unit->m_controlcounter;
1026 int controlsize=unit->m_controlsize;
1027
1028 ////RMS
1029 int framesize=unit->m_fftsize;
1030 int framestart= (controlcounter + controlsize- framesize)%controlsize;
1031
1032 float maxrms=0.0; //sum=0.0,
1033
1034 for (i=0; i<framesize; ++i) {
1035
1036 pos= (framestart+i)%controlsize;
1037
1038 val= store[pos];
1039
1040 val=val*val;
1041
1042 if(val>maxrms) {
1043 maxrms=val;
1044 }
1045
1046 //sum+= val*val;
1047 }
1048
1049 //sum/framesize
1050
1051 //log of sum?
1052
1053 float rmsfeature= log10(1+((maxrms)*9)); //sqrt(sum/framesize); //root mean square from 0.0 to 1.0
1054
1055 //could sc_min(rmsfeature,1.0) if want clamped to 0.0 to 1
1056
1057 //rmsfeature>0.01
1058 //printf("TARGET rms %f maxrms %f \n",rmsfeature, maxrms);
1059
1060
1061 //may have as param
1062 if(rmsfeature>threshold) {
1063
1064
1065 ////////ZCR feature (counts - to + only)
1066 int zcrsize= unit->m_samplesforzcr;
1067
1068 int zcrcount=0;
1069
1070 float prevval=0.0;
1071
1072 for (i=0; i<zcrsize; ++i) {
1073
1074 val= store[i];
1075
1076 if ((val>=(-0.00000001)) && (prevval<0.00000001))
1077 ++zcrcount;
1078
1079 prevval=val;
1080 }
1081
1082 float zcrfeature= log10(zcrcount/(0.5*zcrsize*0.2)+1);
1083
1084 if(zcrfeature>2) zcrfeature=2;
1085
1086 zcrfeature= zcrfeature*0.5;
1087
1088 //float zcrfeature= zcrcount/(0.5*zcrsize); //normalise how? divide by zcrsize/2 or more and clamp to 1? Could correct with weighting
1089
1090
1091 float scfeature=calcsc2(fftbuf, unit->m_nover4); //was m_nover2
1092
1093 scfeature= sc_min(2*scfeature,1.0);
1094
1095 float stfeature=calcst(fftbuf);
1096
1097 //find locations to search
1098 float seekstart= ZIN0(3); //in seconds
1099 float seekdur= ZIN0(4); //in seconds
1100
1101 int featurecounter= unit->m_featurecounter;
1102
1103
1104 int sourceframes= unit->m_sourceframes;
1105
1106 int beginsearch= (featurecounter + sourceframes - ((int)((seekstart*unit->m_sr)/(unit->m_fftsize))))%(sourceframes);
1107 int searchlength= (int)((seekdur*unit->m_sr)/(unit->m_fftsize));
1108
1109 searchlength= sc_max(searchlength,1);
1110
1111 //find best match
1112
1113 float * zcr= unit->m_zcr;
1114 float * rms= unit->m_rms;
1115 float * sc= unit->m_speccentroid;
1116 float * st= unit->m_spectilt;
1117
1118 float zcrweight= ZIN0(7);
1119 float rmsweight= ZIN0(8);
1120 float scweight= ZIN0(9);
1121 float stweight= ZIN0(10);
1122
1123 int best=(-1);
1124 float bestscore= 1000000000.0;
1125
1126 float zcrdiff, rmsdiff, scdiff, stdiff, score;
1127
1128 //not sure if I like this or not!
1129 float randscore= ZIN0(11);
1130
1131 RGen& rgen = *unit->mParent->mRGen;
1132
1133 for (i=0; i<searchlength; ++i) {
1134
1135 pos= (beginsearch+i)%sourceframes;
1136
1137 zcrdiff= zcrfeature- zcr[pos];
1138
1139 float rmstest= rms[pos];
1140
1141 if(rmstest>threshold) {
1142
1143 rmsdiff= rmsfeature- rmstest;
1144 scdiff= scfeature- sc[pos];
1145 stdiff= stfeature- st[pos];
1146
1147 score= zcrweight*(zcrdiff*zcrdiff) + rmsweight*(rmsdiff*rmsdiff) + scweight*(scdiff*scdiff) + stweight*(stdiff*stdiff)+(rgen.frand()*randscore);
1148
1149 //could add match randomisation factor here score=score+ZIN0()
1150
1151 if (score< bestscore) {
1152 bestscore= score;
1153 best=i;
1154 }
1155
1156 }
1157 }
1158
1159 if(best>=0) {
1160
1161 int answer= (beginsearch+best)%sourceframes;
1162
1163 //printf("zcr %f rms %f sc %f\n",zcrfeature,rmsfeature,scfeature);
1164
1165 zcrdiff= zcrfeature- zcr[answer];
1166 rmsdiff= rmsfeature- rms[answer];
1167 scdiff= scfeature- sc[answer];
1168
1169 score= zcrweight*(zcrdiff*zcrdiff) + rmsweight*(rmsdiff*rmsdiff) + scweight*(scdiff*scdiff);
1170
1171 //printf("zcrdiff %f rmsdiff %f scdiff %f score %f answer %d\n",zcrdiff,rmsdiff,scdiff,score, answer);
1172
1173 //store best match sample and reset read pointer and fft frame counter
1174 //setting read out on current sample read
1175
1176 unit->m_fadeoutlocation= unit->m_matchlocation; //next sample to be read now faded
1177
1178 unit->m_fadeoutamp= unit->m_matchamp;
1179 unit->m_matchlocation=answer*(unit->m_fftsize);
1180 unit->m_matchcounter=0;
1181
1182 unit->m_matchamp=1.0;
1183
1184 float matchlength= ZIN0(5);
1185
1186 int matchframes= (int)((matchlength*unit->m_sr)/(unit->m_fftsize));
1187
1188 unit->m_matchframes= sc_max(matchframes,1);
1189
1190 } else {
1191 matchfailure=1;
1192
1193 }
1194
1195
1196 //printf("begin %d length %d answer %d\n",beginsearch, searchlength, answer);
1197 } else {
1198
1199
1200 matchfailure=1;
1201
1202 }
1203
1204
1205 //cope with match failure- so output zeroes, must finish fade of any current material
1206 if(matchfailure==1) {
1207
1208 //always fade out old at this point, will be silent
1209 unit->m_fadeoutlocation= unit->m_matchlocation; //next sample to be read now faded
1210 unit->m_fadeoutamp= unit->m_matchamp;
1211
1212 //just read something random but at zero amp
1213 unit->m_matchamp=0.0;
1214 unit->m_matchlocation=0;
1215 unit->m_matchcounter=0;
1216 unit->m_matchframes= 1;
1217
1218 }
1219
1220 }
1221
1222
1223
1224
1225
1226
1227
1228 //calculation function once FFT data ready, in place on fftbuf passed in
Concat_dofft(Concat * unit,scfft * scf,float * fftbuf)1229 void Concat_dofft(Concat *unit,scfft * scf, float * fftbuf) {
1230
1231 int i;
1232
1233 scfft_dofft(scf);
1234
1235 int n= unit->m_fftsize;
1236
1237 //format is dc, nyquist, bin[1] ,real, bin[1].imag, etc
1238
1239 //fftbuf[0] already bin 0
1240 fftbuf[0]= fftbuf[0]* fftbuf[0]; //get power
1241
1242 float val1, val2;
1243 // Squared Absolute so get power
1244 for (i=2; i<n; i+=2) {
1245 val1 = fftbuf[i];
1246 val2 = fftbuf[i+1];
1247 //i>>1 is i/2
1248 fftbuf[i>>1] = (val1*val1)+(val2*val2);
1249 }
1250
1251 }
1252
1253
1254
PluginLoad(Concat)1255 PluginLoad(Concat) {
1256
1257 ft = inTable;
1258
1259 DefineDtorUnit(Concat);
1260 DefineDtorUnit(Concat2);
1261 }
1262