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