1 //Spencer Jackson
2 //stuck.c
3 #include<lv2.h>
4 #include<stdlib.h>
5 #include<stdio.h>
6 #include<string.h>
7 #include<math.h>
8 #include"rms_calc.h"
9 #include"stuck.h"
10
11 //#define CV_PORTS
12 #define AUTOCORR
13 //#define COMP
14
15 #ifdef AUTOCORR
16 #define START_SCORE 0
17 #else //least squared error
18 #define START_SCORE 200
19 #endif
20
21 enum states
22 {
23 INACTIVE = 0,
24 LOADING,
25 MATCHING,
26 LOADING_XFADE,
27 XFADE_ONLY,
28 PLAYING,
29 RELEASING,
30 QUICK_RELEASING,
31 DEBUGGING,
32 };
33
34 typedef struct _STUCK
35 {
36 uint16_t indx;//current write point in buffer
37 uint16_t indx2;//working/read point in buffer
38 uint16_t bufsize;//size of buffer
39 uint16_t wavesize;//size of waveform
40 uint16_t acorr_size;//size of autocorrelation
41 uint16_t xfade_size;
42 uint16_t wave_min;//int16_test allowed wavesize
43 uint16_t wave_max;//int32_test allowed wavesize
44 uint8_t state;
45 uint8_t stack;
46 uint8_t dbg;//used for whatever, delete it
47 double sample_freq;
48
49 float *buf;
50 float gain;
51 float env;//envelope gain to normalize compression to
52 float score;
53 float shortscore;
54
55 RMS_CALC rms_calc;
56
57 float *input_p;
58 float *output_p;
59 float *trigger_p;
60 float *stick_it_p;
61 float *drone_gain_p;
62 float *release_p;
63 float *dbg_p;
64 float *output2_p;
65
66 float *xf_func;
67 } STUCK;
68
run_stuck(LV2_Handle handle,uint32_t nframes)69 void run_stuck(LV2_Handle handle, uint32_t nframes)
70 {
71 STUCK* plug = (STUCK*)handle;
72 uint32_t i,j,k,t,chunk=0;
73 double slope = 0;
74 double interp;
75
76 if(plug->stack)
77 for(i=0;i<nframes;i++)
78 plug->output_p[i] = 0;
79 else
80 memcpy(plug->output_p,plug->input_p,nframes*sizeof(float));
81
82 interp = nframes>64?nframes:64;
83
84 //Evaluate port values and see if it requires any state changes
85 if(plug->state == INACTIVE)
86 {
87 //decide if triggered
88 #ifdef CV_PORTS
89 if(*plug->stick_it_p >= 1 || plug->trigger_p[nframes-1] >= 1)
90 #else
91 if(*plug->stick_it_p >= 1)
92 #endif
93 {
94 plug->state = LOADING;
95 #ifdef COMP
96 plug->env = plug->rms_calc.rms;
97 }
98 else
99 {
100 rms_block_fill(&plug->rms_calc, plug->input_p,nframes);
101 #else
102 }
103 else{
104 #endif
105 return;
106 }
107 }
108 else if(plug->state < LOADING_XFADE)
109 {
110 //decide if need to abort
111 #ifdef CV_PORTS
112 if(*plug->stick_it_p < 1 && plug->trigger_p[nframes-1] < 1)
113 #else
114 if(*plug->stick_it_p < 1)
115 #endif
116 {
117 //reinit
118 plug->indx = 0;
119 plug->indx2 = plug->wave_min;
120 plug->state = INACTIVE;
121 plug->gain = 0;
122 plug->wavesize = plug->wave_max;
123 plug->score = START_SCORE;
124 plug->shortscore = .25*START_SCORE;
125 #ifdef COMP
126 rms_block_fill(&plug->rms_calc, plug->input_p,nframes);
127 #endif
128 return;
129 }
130 }
131 else if(plug->state < RELEASING)
132 {
133 //decide if released
134 #ifdef CV_PORTS
135 if(*plug->stick_it_p < 1 && plug->trigger_p[nframes-1] < 1)
136 #else
137 if(*plug->stick_it_p < 1)
138 #endif
139 {
140 plug->state = RELEASING;
141
142 }
143 }
144 else if(plug->state == RELEASING)
145 {
146 //decide if new trigger has been sent before release is complete
147 #ifdef CV_PORTS
148 if(*plug->stick_it_p >= 1 || plug->trigger_p[nframes-1] >= 1)
149 #else
150 if(*plug->stick_it_p >= 1)
151 #endif
152 {
153 plug->state = QUICK_RELEASING;
154 }
155 #ifdef COMP
156 else
157 {
158 rms_block_fill(&plug->rms_calc, plug->input_p,nframes);
159 }
160 #endif
161 }
162
163 //now run the state machine
164 for(i=0; i<nframes;)
165 {
166 chunk = nframes - i;
167 if(plug->state == LOADING)//load enough frames to start calculating the autocorrelation
168 {
169 //decide if reaching minimum length in this period
170 if(plug->indx+chunk >= plug->wave_min+plug->acorr_size)
171 {
172 chunk = plug->wave_min + plug->acorr_size - plug->indx;
173 plug->state = MATCHING;
174 }
175 //load buffer with compressed signal
176 for(j=0; j<chunk; j++)
177 {
178 #ifdef COMP
179 plug->buf[plug->indx++] = plug->input_p[i]*plug->env/rms_shift(&plug->rms_calc,plug->input_p[i]);
180 #else
181 plug->buf[plug->indx++] = plug->input_p[i];
182 #endif
183 i++;
184 }
185 }
186 else if(plug->state == MATCHING)//find autocorrelation
187 {
188 if(plug->indx2+chunk >= plug->wave_max)
189 {
190 chunk = plug->wave_max - plug->indx2;
191 plug->state = LOADING_XFADE;
192 }
193 // calculate autocorrelation of sample in buffer, save the minimum
194 float tmp,score;
195 for(j=0; j<chunk; j++)
196 {
197 #ifdef COMP
198 plug->buf[plug->indx++] = plug->input_p[i]*plug->env/rms_shift(&plug->rms_calc,plug->input_p[i]);
199 #else
200 plug->buf[plug->indx++] = plug->input_p[i];
201 #endif
202 i++;
203
204 score = 0;
205 t=0;
206 #ifdef AUTOCORR
207 for(k=plug->indx2; k<plug->indx2+(plug->acorr_size>>2); k++)
208 {
209 score += plug->buf[k]*plug->buf[t++];
210 }
211 if(score >= plug->shortscore)
212 {
213 //full calc
214 plug->shortscore = .9*score;
215 for( ; k<plug->indx2+plug->acorr_size; k++)
216 score += plug->buf[k]*plug->buf[t++];
217 }
218 //save place if score is higher than last highest
219 if(score>=plug->score)
220 #else
221 for(k=plug->indx2; k<plug->indx2+plug->acorr_size && score<=plug->score; k++)
222 {
223 tmp = plug->buf[k] - plug->buf[t++];//jsyk this isn't the strict definition of an autocorrelation, a variation on the principle
224 score += tmp*tmp;
225 }
226 //save place if score is lower than last minimum
227 if(score<=plug->score)
228 #endif
229 {
230 plug->wavesize = plug->indx2;
231 plug->score = score;
232 }
233 plug->indx2++;
234 }
235 if(plug->indx2>=plug->wave_max)
236 {
237 plug->indx2 = 0;//reset indx2
238 //xfade in beginning of sample, these will be halved in the next state
239 for(k=0; k<plug->xfade_size; k++)
240 plug->buf[k] *= k/plug->xfade_size;
241 }
242 }
243 else if(plug->state == LOADING_XFADE)//xfade end of buffer with start (loop it) over an entire wave and fade in drone
244 {
245 slope = (*plug->drone_gain_p-plug->gain)/interp;
246 //decide if xfade ends in this period
247 if(plug->indx2+chunk >= plug->wavesize)
248 {
249 //this means it has already played through the loop once and finished the xfade (layering really)
250 chunk = plug->wavesize - plug->indx2;
251 plug->state = PLAYING;
252 }
253 //decide if going to overflow
254 if(plug->indx+chunk >= plug->bufsize)
255 {
256 //this means we've already filled the buffer, but haven't finished the xfade
257 chunk = plug->bufsize - plug->indx;
258 plug->state = XFADE_ONLY;
259 }
260 //load buffer with xfade
261 for(j=0; j<chunk; j++)
262 {
263 //still loading end of buffer
264 #ifdef COMP
265 plug->buf[plug->indx++] = plug->input_p[i]*plug->env/rms_shift(&plug->rms_calc,plug->input_p[i]);
266 #else
267 plug->buf[plug->indx++] = plug->input_p[i];
268 #endif
269
270 //layer 2 full cycles on top of each other
271 plug->buf[plug->indx2] = .5*plug->buf[plug->indx2+plug->wavesize] + .5*plug->buf[plug->indx2];
272
273 //but now also playing back start of buffer
274 plug->output_p[i++] += plug->gain*plug->buf[plug->indx2++];
275 plug->gain += slope;
276
277 }
278 //xfade out end if we're there else we'll do it in the next state
279 if(plug->indx2>=plug->wavesize)//TODO: this must actually be ==
280 {
281 for(k=0; k<plug->xfade_size; k++)
282 plug->buf[k] += .5*(1-k/plug->xfade_size)*plug->buf[plug->indx2+plug->wavesize+k];
283 plug->indx2 = 0;
284 }
285 }
286 else if(plug->state == XFADE_ONLY)//xfade after buffer is full, in practice we never get here, but we might change our smoothing strategy again
287 {
288 slope = (*plug->drone_gain_p-plug->gain)/interp;
289 //decide if xfade ends in this period
290 if(plug->indx2+chunk >= plug->wavesize)
291 {
292 chunk = plug->wavesize - plug->indx2;
293 plug->state = PLAYING;
294 }
295 //xfade buffer
296 for(j=0; j<chunk; j++)
297 {
298 //continue layering the 2 cycles
299 plug->buf[plug->indx2] = .5*plug->buf[plug->indx2+plug->wavesize] + .5*plug->buf[plug->indx2];
300 plug->output_p[i++] += plug->gain*plug->buf[plug->indx2++];
301 plug->gain += slope;
302 }
303 //xfade out end
304 if(plug->indx2>=plug->wavesize)//TODO: this must acutally be ==
305 {
306 for(k=0; k<plug->xfade_size; k++)
307 plug->buf[k] += .5*(1-k/plug->xfade_size)*plug->buf[plug->indx2+plug->wavesize+k];
308 plug->indx2 = 0;
309 }
310 }
311 else if(plug->state == PLAYING)//just loop buffer and track gain changes
312 {
313 slope = (*plug->drone_gain_p-plug->gain)/interp;
314 for(j=0; j<chunk; j++)
315 {
316 plug->output_p[i++] += plug->gain*plug->buf[plug->indx2++];
317 plug->gain += slope;
318 plug->indx2 = plug->indx2<plug->wavesize?plug->indx2:0;
319 }
320 }
321 else if(plug->state == RELEASING)
322 {
323 slope = -*plug->drone_gain_p/(*plug->release_p*plug->sample_freq);
324 //decide if released in this period
325 if(plug->gain + chunk*slope < slope)
326 {
327 chunk = -plug->gain/slope;
328 plug->state = INACTIVE;
329 }
330 for(j=0; j<chunk; j++)
331 {
332 plug->output_p[i++] += plug->gain*plug->buf[plug->indx2++];
333 plug->gain += slope;
334 plug->indx2 = plug->indx2<plug->wavesize?plug->indx2:0;
335 }
336 if(plug->gain <= -slope)
337 {
338 plug->indx = 0;
339 plug->indx2 = plug->wave_min;
340 plug->state = INACTIVE;
341 plug->gain = 0;
342 plug->wavesize = plug->wave_max;
343 plug->score = START_SCORE;
344 plug->shortscore = .25*START_SCORE;
345 return;
346 }
347 }
348 else if(plug->state == QUICK_RELEASING)
349 {
350 slope = -*plug->drone_gain_p/(double)plug->wave_min;
351 //decide if released in this period
352 if(plug->gain + chunk*slope < slope)
353 {
354 chunk = -plug->gain/slope;
355 plug->state = LOADING;
356 }
357 for(j=0; j<chunk; j++)
358 {
359 plug->output_p[i++] += plug->gain*plug->buf[plug->indx2++];
360 plug->gain += slope;
361 plug->indx2 = plug->indx2<plug->wavesize?plug->indx2:0;
362 }
363 #ifdef COMP
364 rms_block_fill(&plug->rms_calc, plug->input_p,chunk);
365 #endif
366 if(plug->gain <= -slope)
367 {
368 plug->indx = 0;
369 plug->indx2 = plug->wave_min;
370 plug->state = LOADING;
371 plug->wavesize = plug->wave_max;
372 plug->score = START_SCORE;
373 plug->shortscore = .25*START_SCORE;
374 #ifdef COMP
375 plug->env = plug->rms_calc.rms;
376 #endif
377 }
378 }
379 }
380 return;
381 }
382
init_stuck(const LV2_Descriptor * descriptor,double sample_freq,const char * bundle_path,const LV2_Feature * const * host_features)383 LV2_Handle init_stuck(const LV2_Descriptor *descriptor,double sample_freq, const char *bundle_path,const LV2_Feature * const* host_features)
384 {
385 STUCK* plug = malloc(sizeof(STUCK));
386
387 uint16_t tmp;
388 uint8_t i;
389 plug->sample_freq = sample_freq;
390 tmp = 0x8000;//15 bits
391 if(sample_freq<100000)//88.1 or 96.1kHz
392 tmp = tmp>>1;//14 bits
393 if(sample_freq<50000)//44.1 or 48kHz
394 tmp = tmp>>1;//13 bits //8192
395 plug->buf = (float*)malloc(tmp*sizeof(float));
396 plug->bufsize = tmp;
397 plug->acorr_size = tmp>>3;//1024 if you mess with this, keep in mind it may need change in the default score value
398 plug->xfade_size = tmp>>6;//128
399 plug->wave_max = (tmp - plug->xfade_size)>>1;//4064
400 plug->wave_min = tmp>>6;//128
401 plug->wavesize = plug->wave_max;
402 plug->indx = 0;
403 plug->indx2 = plug->wave_min;
404 plug->state = INACTIVE;
405 plug->gain = 0;
406 plug->score = START_SCORE;
407 plug->shortscore = .25*START_SCORE;
408 plug->env = 0;
409 plug->stack = 0;
410 plug->dbg = 0;
411
412 //half rasied cosine for equal power xfade
413 plug->xf_func = (float*)malloc(plug->xfade_size*sizeof(float));
414 for (i = 0; i < plug->xfade_size; i++) plug->xf_func[i] = 0.5 * (1 - cos((M_PI * i / plug->xfade_size)));
415
416 rms_init(&plug->rms_calc,tmp>>3);
417
418 return plug;
419 }
420
init_stuckstacker(const LV2_Descriptor * descriptor,double sample_freq,const char * bundle_path,const LV2_Feature * const * host_features)421 LV2_Handle init_stuckstacker(const LV2_Descriptor *descriptor,double sample_freq, const char *bundle_path,const LV2_Feature * const* host_features)
422 {
423 STUCK* plug = (STUCK*)init_stuck(descriptor, sample_freq, bundle_path, host_features);
424 plug->stack = 1;
425 return plug;
426 }
427
connect_stuck_ports(LV2_Handle handle,uint32_t port,void * data)428 void connect_stuck_ports(LV2_Handle handle, uint32_t port, void *data)
429 {
430 STUCK* plug = (STUCK*)handle;
431 switch(port)
432 {
433 case IN:
434 plug->input_p = (float*)data;
435 break;
436 case OUT:
437 plug->output_p = (float*)data;
438 break;
439 case TRIGGER:
440 plug->trigger_p = (float*)data;
441 break;
442 case STICKIT:
443 plug->stick_it_p = (float*)data;
444 break;
445 case DRONEGAIN:
446 plug->drone_gain_p = (float*)data;
447 break;
448 case RELEASE:
449 plug->release_p = (float*)data;
450 break;
451 case DBG:
452 plug->dbg_p = (float*)data;
453 break;
454 case OUT2:
455 plug->output2_p = (float*)data;
456 break;
457 default:
458 puts("UNKNOWN PORT YO!!");
459 }
460 }
461
cleanup_stuck(LV2_Handle handle)462 void cleanup_stuck(LV2_Handle handle)
463 {
464 STUCK* plug = (STUCK*)handle;
465 rms_deinit(&plug->rms_calc);
466 free(plug->buf);
467 free(plug->xf_func);
468 free(plug);
469 }
470
471 static const LV2_Descriptor stuck_descriptor=
472 {
473 STUCK_URI,
474 init_stuck,
475 connect_stuck_ports,
476 0,//activate
477 run_stuck,
478 0,//deactivate
479 cleanup_stuck,
480 0//extension
481 };
482 static const LV2_Descriptor stuckstacker_descriptor=
483 {
484 STUCKSTACKER_URI,
485 init_stuckstacker,
486 connect_stuck_ports,
487 0,//activate
488 run_stuck,
489 0,//deactivate
490 cleanup_stuck,
491 0//extension
492 };
493
494 LV2_SYMBOL_EXPORT
lv2_descriptor(uint32_t index)495 const LV2_Descriptor* lv2_descriptor(uint32_t index)
496 {
497 switch (index)
498 {
499 case 0:
500 return &stuck_descriptor;
501 case 1:
502 return &stuckstacker_descriptor;
503 default:
504 return 0;
505 }
506 }
507