Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / plugins / GrainUGens.cpp
blob12f5a6b42bb0701f3986fe397f82a76398d09fc7
1 /*
2 * JoshUGens.cpp
3 * xSC3plugins
5 * Created by Josh Parmenter on 2/4/05.
6 * Copyright 2005 __MyCompanyName__. All rights reserved.
8 */
9 /*
10 SuperCollider real time audio synthesis system
11 Copyright (c) 2002 James McCartney. All rights reserved.
12 http://www.audiosynth.com
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 #include "SC_PlugIn.h"
32 #include "function_attributes.h"
34 static InterfaceTable *ft;
36 const int kMaxGrains = 64;
38 const int kMaxSynthGrains = 512;
40 struct GrainInG
42 double b1, y1, y2, curamp, winPos, winInc; // envelope
43 int counter, chan;
44 float pan1, pan2, winType;
47 struct GrainIn : public Unit
49 int mNumActive, m_channels, mMaxGrains;
50 float curtrig;
51 bool mFirst;
52 GrainInG *mGrains;
55 struct GrainSinG
57 double b1, y1, y2, curamp, winPos, winInc; // envelope
58 int counter, chan;
59 float pan1, pan2, winType;
60 int32 oscphase; // the phase of the osc inside this grain
61 int32 freq; // the freq of the osc inside this grain in phase inc
64 struct GrainSin : public Unit
66 int mNumActive, m_channels, mMaxGrains;
67 uint32 m_lomask;
68 float curtrig;
69 bool mFirst;
70 double m_cpstoinc, m_radtoinc;
71 GrainSinG *mGrains;
74 struct GrainFMG
76 int32 coscphase, moscphase; // the phase of the osc inside this grain
77 int32 mfreq; // the freq of the osc inside this grain in phase inc
78 double b1, y1, y2, curamp, winPos, winInc; // envelope
79 float deviation, carbase, pan1, pan2, winType;
80 int counter, chan;
84 struct GrainFM : public Unit
86 int mNumActive, m_channels, mMaxGrains;
87 uint32 m_lomask;
88 float curtrig;
89 bool mFirst;
90 double m_cpstoinc, m_radtoinc;
91 GrainFMG *mGrains;
94 struct GrainBufG
96 double phase, rate;
97 double b1, y1, y2, curamp, winPos, winInc;
98 float pan1, pan2, winType;
99 int counter, chan, bufnum, interp;
102 struct GrainBuf : public Unit
104 int mNumActive, m_channels, mMaxGrains;
105 float curtrig;
106 GrainBufG *mGrains;
109 struct WarpWinGrain
111 double phase, rate;
112 double winPos, winInc, b1, y1, y2, curamp; // tells the grain where to look in the winBuf for an amp value
113 int counter, bufnum, interp;
114 float winType;
117 struct Warp1 : public Unit
119 float m_fbufnum;
120 SndBuf* m_buf;
121 int mNumActive[16];
122 int mNextGrain[16];
123 WarpWinGrain mGrains[16][kMaxGrains];
126 ////////////////////////////////////////////////////////////////////////
128 extern "C"
131 void GrainIn_Ctor(GrainIn* unit);
132 void GrainIn_Dtor(GrainIn* unit);
133 void GrainIn_next_a(GrainIn *unit, int inNumSamples);
134 void GrainIn_next_k(GrainIn *unit, int inNumSamples);
136 void GrainSin_Ctor(GrainSin* unit);
137 void GrainSin_Dtor(GrainSin* unit);
138 void GrainSin_next_a(GrainSin *unit, int inNumSamples);
139 void GrainSin_next_k(GrainSin *unit, int inNumSamples);
141 void GrainFM_Ctor(GrainFM* unit);
142 void GrainFM_Dtor(GrainFM* unit);
143 void GrainFM_next_a(GrainFM *unit, int inNumSamples);
144 void GrainFM_next_k(GrainFM *unit, int inNumSamples);
146 void GrainBuf_Ctor(GrainBuf* unit);
147 void GrainBuf_Dtor(GrainBuf* unit);
149 void Warp1_next(Warp1 *unit, int inNumSamples);
150 void Warp1_Ctor(Warp1* unit);
153 ////////////////////////////////////////////////////////////////////////////////////////////////////////
154 //////////////////////////////// Granular UGens ////////////////////////////////////////////////////////
155 ////////////////////////////////////////////////////////////////////////////////////////////////////////
157 inline float GRAIN_IN_AT(Unit* unit, int index, int offset)
159 if (INRATE(index) == calc_FullRate) return IN(index)[offset];
160 if (INRATE(index) == calc_DemandRate) return DEMANDINPUT_A(index, offset + 1);
161 return IN0(index);
164 template <bool full_rate>
165 inline float grain_in_at(Unit* unit, int index, int offset)
167 if (full_rate)
168 return GRAIN_IN_AT(unit, index, offset);
170 if (INRATE(index) == calc_DemandRate)
171 return DEMANDINPUT_A(index, offset + 1);
172 else
173 return IN0(index);
176 inline double sc_gloop(double in, double hi)
178 // avoid the divide if possible
179 if (in >= hi) {
180 in -= hi;
181 if (in < hi) return in;
182 } else if (in < 0.) {
183 in += hi;
184 if (in >= 0.) return in;
185 } else return in;
187 return in - hi * floor(in/hi);
190 #define GRAIN_BUF \
191 const SndBuf *buf; \
192 if (bufnum >= world->mNumSndBufs) { \
193 int localBufNum = bufnum - world->mNumSndBufs; \
194 Graph *parent = unit->mParent; \
195 if(localBufNum <= parent->localBufNum) { \
196 buf = parent->mLocalSndBufs + localBufNum; \
197 } else { \
198 bufnum = 0; \
199 buf = world->mSndBufs + bufnum; \
201 } else { \
202 if (bufnum < 0) { bufnum = 0; } \
203 buf = world->mSndBufs + bufnum; \
205 LOCK_SNDBUF_SHARED(buf); \
206 const float *bufData __attribute__((__unused__)) = buf->data; \
207 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
208 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
209 uint32 bufFrames = buf->frames; \
210 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
212 #define DECLARE_WINDOW \
213 double winPos, winInc, w, b1, y1, y2, y0; \
214 float amp; \
215 winPos = winInc = w = b1 = y1 = y2 = y0 = amp = 0.; \
216 SndBuf *window; \
217 const float *windowData __attribute__((__unused__)) = 0;\
218 uint32 windowSamples __attribute__((__unused__)) = 0; \
219 uint32 windowFrames __attribute__((__unused__)) = 0; \
220 int windowGuardFrame = 0;
223 #define CHECK_BUF \
224 if (!bufData) { \
225 unit->mDone = true; \
226 ClearUnitOutputs(unit, inNumSamples); \
227 return; \
230 #define GET_GRAIN_WIN_RELAXED(WINTYPE) \
231 do { \
232 assert(WINTYPE < unit->mWorld->mNumSndBufs); \
233 window = unit->mWorld->mSndBufs + (int)WINTYPE; \
234 windowData = window->data; \
235 windowSamples = window->samples; \
236 windowFrames = window->frames; \
237 windowGuardFrame = windowFrames - 1; \
238 } while (0);
241 static inline bool getGrainWin(Unit * unit, float wintype, SndBuf *& window, const float * & windowData,
242 uint32 & windowSamples, uint32 & windowFrames, int & windowGuardFrame)
244 if (wintype >= unit->mWorld->mNumSndBufs) {
245 Print("Envelope buffer out of range!\n");
246 return false;
249 assert(wintype < unit->mWorld->mNumSndBufs);
251 if (wintype < 0)
252 return true; // use default hann window
254 window = unit->mWorld->mSndBufs + (int)wintype;
255 windowData = window->data;
256 if (!windowData)
257 return false;
259 windowSamples = window->samples;
260 windowFrames = window->frames;
261 windowGuardFrame = windowFrames - 1;
263 return true;
266 #define GRAIN_LOOP_BODY_4 \
267 float amp = y1 * y1; \
268 phase = sc_gloop(phase, loopMax); \
269 int32 iphase = (int32)phase; \
270 float* table1 = bufData + iphase; \
271 float* table0 = table1 - 1; \
272 float* table2 = table1 + 1; \
273 float* table3 = table1 + 2; \
274 if (iphase == 0) { \
275 table0 += bufSamples; \
276 } else if (iphase >= guardFrame) { \
277 if (iphase == guardFrame) { \
278 table3 -= bufSamples; \
279 } else { \
280 table2 -= bufSamples; \
281 table3 -= bufSamples; \
284 float fracphase = phase - (double)iphase; \
285 float a = table0[0]; \
286 float b = table1[0]; \
287 float c = table2[0]; \
288 float d = table3[0]; \
289 float outval = amp * cubicinterp(fracphase, a, b, c, d) \
290 ZXP(out1) += outval; \
291 double y0 = b1 * y1 - y2; \
292 y2 = y1; \
293 y1 = y0;
295 #define GRAIN_LOOP_BODY_2 \
296 float amp = y1 * y1; \
297 phase = sc_gloop(phase, loopMax); \
298 int32 iphase = (int32)phase; \
299 float* table1 = bufData + iphase; \
300 float* table2 = table1 + 1; \
301 if (iphase > guardFrame) { \
302 table2 -= bufSamples; \
304 double fracphase = phase - (double)iphase; \
305 float b = table1[0]; \
306 float c = table2[0]; \
307 float outval = amp * (b + fracphase * (c - b)); \
308 ZXP(out1) += outval; \
309 double y0 = b1 * y1 - y2; \
310 y2 = y1; \
311 y1 = y0;
314 #define GRAIN_LOOP_BODY_1 \
315 float amp = y1 * y1; \
316 phase = sc_gloop(phase, loopMax); \
317 int32 iphase = (int32)phase; \
318 float outval = amp * bufData[iphase]; \
319 ZXP(out1) += outval; \
320 double y0 = b1 * y1 - y2; \
321 y2 = y1; \
322 y1 = y0;
324 #define BUF_GRAIN_AMP \
325 winPos += winInc; \
326 int iWinPos = (int)winPos; \
327 double winFrac = winPos - (double)iWinPos; \
328 float* winTable1 = windowData + iWinPos; \
329 float* winTable2 = winTable1 + 1; \
330 if (winPos > windowGuardFrame) { \
331 winTable2 -= windowSamples; \
333 amp = lininterp(winFrac, winTable1[0], winTable2[0]);
335 #define BUF_GRAIN_LOOP_BODY_4 \
336 phase = sc_gloop(phase, loopMax); \
337 int32 iphase = (int32)phase; \
338 float* table1 = bufData + iphase; \
339 float* table0 = table1 - 1; \
340 float* table2 = table1 + 1; \
341 float* table3 = table1 + 2; \
342 if (iphase == 0) { \
343 table0 += bufSamples; \
344 } else if (iphase >= guardFrame) { \
345 if (iphase == guardFrame) { \
346 table3 -= bufSamples; \
347 } else { \
348 table2 -= bufSamples; \
349 table3 -= bufSamples; \
352 float fracphase = phase - (double)iphase; \
353 float a = table0[0]; \
354 float b = table1[0]; \
355 float c = table2[0]; \
356 float d = table3[0]; \
357 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
358 ZXP(out1) += outval;
360 #define BUF_GRAIN_LOOP_BODY_2 \
361 phase = sc_gloop(phase, loopMax); \
362 int32 iphase = (int32)phase; \
363 float* table1 = bufData + iphase; \
364 float* table2 = table1 + 1; \
365 if (iphase > guardFrame) { \
366 table2 -= bufSamples; \
368 float fracphase = phase - (double)iphase; \
369 float b = table1[0]; \
370 float c = table2[0]; \
371 float outval = amp * (b + fracphase * (c - b)); \
372 ZXP(out1) += outval;
374 // amp needs to be calculated by looking up values in window
376 #define BUF_GRAIN_LOOP_BODY_1 \
377 phase = sc_gloop(phase, loopMax); \
378 int32 iphase = (int32)phase; \
379 float outval = amp * bufData[iphase]; \
380 ZXP(out1) += outval;
383 #define SETUP_OUT \
384 uint32 numOutputs = unit->mNumOutputs; \
385 if (numOutputs > bufChannels) { \
386 unit->mDone = true; \
387 ClearUnitOutputs(unit, inNumSamples); \
388 return; \
390 float *out[16]; \
391 for (uint32 i=0; i<numOutputs; ++i) out[i] = ZOUT(i);
394 #define CALC_GRAIN_PAN \
395 float panangle, pan1, pan2; \
396 float *out1, *out2; \
397 if (numOutputs > 1) { \
398 if (numOutputs == 2) pan = pan * 0.5f; \
399 pan = sc_wrap(pan * 0.5f, 0.f, 1.f); \
400 float cpan = numOutputs * pan + 0.5f; \
401 float ipan = floor(cpan); \
402 float panfrac = cpan - ipan; \
403 panangle = panfrac * pi2_f; \
404 grain->chan = (int)ipan; \
405 if (grain->chan >= (int)numOutputs) \
406 grain->chan -= numOutputs; \
407 pan1 = grain->pan1 = cos(panangle); \
408 pan2 = grain->pan2 = sin(panangle); \
409 } else { \
410 grain->chan = 0; \
411 pan1 = grain->pan1 = 1.; \
412 pan2 = grain->pan2 = 0.; \
415 #define GET_GRAIN_INIT_AMP \
416 if(grain->winType < 0.){ \
417 w = pi / counter; \
418 b1 = grain->b1 = 2. * cos(w); \
419 y1 = sin(w); \
420 y2 = 0.; \
421 amp = y1 * y1; \
422 } else { \
423 amp = windowData[0]; \
424 winPos = grain->winPos = 0.f; \
425 winInc = grain->winInc = (double)windowSamples / counter; \
428 #define CALC_NEXT_GRAIN_AMP_INTERNAL \
429 do { \
430 y0 = b1 * y1 - y2; \
431 y2 = y1; \
432 y1 = y0; \
433 amp = y1 * y1; \
434 } while(0)
436 #define CALC_NEXT_GRAIN_AMP_CUSTOM \
437 do { \
438 winPos += winInc; \
439 int iWinPos = (int)winPos; \
440 double winFrac = winPos - (double)iWinPos; \
441 const float* winTable1 = windowData + iWinPos; \
442 const float* winTable2 = winTable1 + 1; \
443 if (!windowData) \
444 break; \
445 if (winPos > windowGuardFrame) \
446 winTable2 -= windowSamples; \
447 amp = lininterp(winFrac, winTable1[0], winTable2[0]); \
448 } while (0); \
449 if (!windowData) \
450 break; \
452 #define CALC_NEXT_GRAIN_AMP \
453 if(grain->winType < 0.) { \
454 CALC_NEXT_GRAIN_AMP_INTERNAL; \
455 } else { \
456 CALC_NEXT_GRAIN_AMP_CUSTOM; \
460 #define GET_GRAIN_AMP_PARAMS \
461 if(grain->winType < 0.){ \
462 b1 = grain->b1; \
463 y1 = grain->y1; \
464 y2 = grain->y2; \
465 amp = grain->curamp; \
466 } else { \
467 GET_GRAIN_WIN_RELAXED(grain->winType); \
468 if (!windowData) break; \
469 winPos = grain->winPos; \
470 winInc = grain->winInc; \
471 amp = grain->curamp; \
474 #define SAVE_GRAIN_AMP_PARAMS \
475 grain->y1 = y1; \
476 grain->y2 = y2; \
477 grain->winPos = winPos; \
478 grain->winInc = winInc; \
479 grain->curamp = amp; \
480 grain->counter -= nsmps;
482 #define WRAP_CHAN(offset) \
483 out1 = OUT(grain->chan) + offset; \
484 if(numOutputs > 1) { \
485 if((grain->chan + 1) >= (int)numOutputs) \
486 out2 = OUT(0) + offset; \
487 else \
488 out2 = OUT(grain->chan + 1) + offset; \
491 #define GET_PAN_PARAMS \
492 float pan1 = grain->pan1; \
493 uint32 chan1 = grain->chan; \
494 float *out1 = OUT(chan1); \
495 if(numOutputs > 1){ \
496 pan2 = grain->pan2; \
497 uint32 chan2 = chan1 + 1; \
498 if (chan2 >= numOutputs) chan2 = 0; \
499 out2 = OUT(chan2); \
503 //////////////////// InGrain ////////////////////
505 inline void GrainIn_next_play_active(GrainIn * unit, int inNumSamples)
507 const uint32 numOutputs = unit->mNumOutputs;
508 float *in = IN(2);
509 for (int i=0; i < unit->mNumActive; ) {
510 GrainInG *grain = unit->mGrains + i;
511 DECLARE_WINDOW
512 GET_GRAIN_AMP_PARAMS
513 // begin add //
515 float pan2 = 0.f;
516 float *out2;
518 GET_PAN_PARAMS
519 // end add //
520 int nsmps = sc_min(grain->counter, inNumSamples);
521 for (int j=0; j<nsmps; ++j) {
522 float outval = amp * in[j];
523 // begin change / add //
524 out1[j] += outval * pan1;
525 if(numOutputs > 1) out2[j] += outval * pan2;
526 // end change //
528 CALC_NEXT_GRAIN_AMP
531 SAVE_GRAIN_AMP_PARAMS
533 if (grain->counter <= 0)
534 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
535 else
536 ++i;
540 template <bool full_rate>
541 inline void GrainIn_next_start_new(GrainIn * unit, int inNumSamples, int position)
543 if (unit->mNumActive+1 >= unit->mMaxGrains) {
544 Print("Too many grains!\n");
545 return;
548 float winType = grain_in_at<full_rate>(unit, 4, position);
549 DECLARE_WINDOW
550 bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame);
551 if (!success)
552 return;
554 GrainInG *grain = unit->mGrains + unit->mNumActive++;
555 float winSize = grain_in_at<full_rate>(unit, 1, position);
556 double counter = winSize * SAMPLERATE;
557 counter = sc_max(4., counter);
558 grain->counter = (int)counter;
559 grain->winType = winType;
561 GET_GRAIN_INIT_AMP
563 const uint32 numOutputs = unit->mNumOutputs;
564 float *in = IN(2);
566 float *in1 = in + position;
567 // begin add //
568 float pan = grain_in_at<full_rate>(unit, 3, position);
570 CALC_GRAIN_PAN
572 WRAP_CHAN(position)
574 int nsmps = sc_min(grain->counter, inNumSamples - position);
575 for (int j=0; j<nsmps; ++j) {
576 float outval = amp * in1[j];
577 // begin add / change
578 out1[j] += outval * pan1;
579 if(numOutputs > 1) out2[j] += outval * pan2;
580 // end add / change
581 CALC_NEXT_GRAIN_AMP
584 SAVE_GRAIN_AMP_PARAMS
586 if (grain->counter <= 0)
587 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
590 void GrainIn_next_a(GrainIn *unit, int inNumSamples)
592 ClearUnitOutputs(unit, inNumSamples);
593 //begin add
594 // end add
596 GrainIn_next_play_active(unit, inNumSamples);
598 float *trig = IN(0);
599 for (int i=0; i<inNumSamples; ++i) {
600 if ((unit->curtrig <= 0) && (trig[i] > 0.0))
601 GrainIn_next_start_new<true>(unit, inNumSamples, i);
602 unit->curtrig = trig[i];
606 void GrainIn_next_k(GrainIn *unit, int inNumSamples)
608 ClearUnitOutputs(unit, inNumSamples);
609 if(unit->mFirst){
610 unit->mFirst = false;
611 float maxGrains = IN0(5);
612 unit->mMaxGrains = (int)maxGrains;
613 unit->mGrains = (GrainInG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainInG));
616 GrainIn_next_play_active(unit, inNumSamples);
618 float trig = IN0(0);
620 if ((unit->curtrig <= 0) && (trig > 0.0))
621 GrainIn_next_start_new<false>(unit, inNumSamples, 0);
622 unit->curtrig = trig;
626 void GrainIn_Ctor(GrainIn *unit)
628 if (INRATE(0) == calc_FullRate)
629 SETCALC(GrainIn_next_a);
630 else
631 SETCALC(GrainIn_next_k);
632 unit->mFirst = true;
633 unit->mNumActive = 0;
634 unit->curtrig = 0.f;
635 GrainIn_next_k(unit, 1);
638 void GrainIn_Dtor(GrainIn *unit)
640 RTFree(unit->mWorld, unit->mGrains);
643 inline void GrainSin_next_play_active(GrainSin * unit, int inNumSamples)
645 const unsigned int numOutputs = unit->mNumOutputs;
647 float *table0 = ft->mSineWavetable;
648 float *table1 = table0 + 1;
650 for (int i=0; i < unit->mNumActive; ) {
651 GrainSinG *grain = unit->mGrains + i;
652 DECLARE_WINDOW
653 GET_GRAIN_AMP_PARAMS
655 // begin add //
657 float pan2 = 0.f;
658 float *out2;
660 GET_PAN_PARAMS
662 // end add //
664 int32 thisfreq = grain->freq;
665 int32 oscphase = grain->oscphase;
667 int nsmps = sc_min(grain->counter, inNumSamples);
668 for (int j=0; j<nsmps; ++j) {
669 float outval = amp * lookupi1(table0, table1, oscphase, unit->m_lomask);
670 // begin change / add //
671 out1[j] += outval * pan1;
672 if(numOutputs > 1) out2[j] += outval * pan2;
673 // end change //
674 CALC_NEXT_GRAIN_AMP
676 oscphase += thisfreq;
679 SAVE_GRAIN_AMP_PARAMS
681 grain->oscphase = oscphase;
682 if (grain->counter <= 0)
683 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
684 else
685 ++i;
689 template <bool full_rate>
690 inline void GrainSin_next_start_new(GrainSin * unit, int inNumSamples, int position)
692 if (unit->mNumActive+1 >= unit->mMaxGrains) {
693 Print("Too many grains!\n");
694 return;
697 float winType = grain_in_at<full_rate>(unit, 4, position);
698 DECLARE_WINDOW
699 bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame);
700 if (!success)
701 return;
703 GrainSinG *grain = unit->mGrains + unit->mNumActive++;
704 float freq = grain_in_at<full_rate>(unit, 2, position);
705 float winSize = grain_in_at<full_rate>(unit, 1, position);
706 int32 thisfreq = grain->freq = (int32)(unit->m_cpstoinc * freq);
707 int32 oscphase = 0;
708 double counter = winSize * SAMPLERATE;
709 counter = sc_max(4., counter);
710 grain->counter = (int)counter;
711 grain->winType = winType;
713 GET_GRAIN_INIT_AMP
715 const uint32 numOutputs = unit->mNumOutputs;
717 float *table0 = ft->mSineWavetable;
718 float *table1 = table0 + 1;
720 // begin add //
721 float pan = grain_in_at<full_rate>(unit, 3, position);
723 CALC_GRAIN_PAN
725 WRAP_CHAN(position)
727 // end add //
729 int nsmps = sc_min(grain->counter, inNumSamples - position);
730 for (int j=0; j<nsmps; ++j) {
731 float outval = amp * lookupi1(table0, table1, oscphase, unit->m_lomask);
732 // begin add / change
733 out1[j] += outval * pan1;
734 if(numOutputs > 1) out2[j] += outval * pan2;
735 // end add / change
736 CALC_NEXT_GRAIN_AMP
738 oscphase += thisfreq;
740 grain->oscphase = oscphase;
742 SAVE_GRAIN_AMP_PARAMS
744 if (grain->counter <= 0)
745 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
748 void GrainSin_next_a(GrainSin *unit, int inNumSamples)
750 ClearUnitOutputs(unit, inNumSamples);
752 GrainSin_next_play_active(unit, inNumSamples);
754 float *trig = IN(0);
755 for (int i=0; i<inNumSamples; ++i) {
756 if ((unit->curtrig <= 0) && (trig[i] > 0.0))
757 GrainSin_next_start_new<true>(unit, inNumSamples, i);
758 unit->curtrig = trig[i];
762 void GrainSin_next_k(GrainSin *unit, int inNumSamples)
764 ClearUnitOutputs(unit, inNumSamples);
765 if(unit->mFirst){
766 unit->mFirst = false;
767 float maxGrains = IN0(5);
768 unit->mMaxGrains = (int)maxGrains;
769 unit->mGrains = (GrainSinG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainSinG));
772 GrainSin_next_play_active(unit, inNumSamples);
774 float trig = IN0(0);
777 if ((unit->curtrig <= 0) && (trig > 0.0))
778 GrainSin_next_start_new<false>(unit, inNumSamples, 0);
779 unit->curtrig = trig;
782 void GrainSin_Ctor(GrainSin *unit)
784 if (INRATE(0) == calc_FullRate)
785 SETCALC(GrainSin_next_a);
786 else
787 SETCALC(GrainSin_next_k);
788 int tableSizeSin = ft->mSineSize;
789 unit->m_lomask = (tableSizeSin - 1) << 3;
790 unit->m_radtoinc = tableSizeSin * (rtwopi * 65536.);
791 unit->m_cpstoinc = tableSizeSin * SAMPLEDUR * 65536.;
792 unit->curtrig = 0.f;
793 unit->mNumActive = 0;
794 unit->mFirst = true;
795 GrainSin_next_k(unit, 1);
798 void GrainSin_Dtor(GrainSin *unit)
800 RTFree(unit->mWorld, unit->mGrains);
804 inline void GrainFM_next_play_active(GrainFM *unit, int inNumSamples)
806 const uint32 numOutputs = unit->mNumOutputs;
807 // end add
809 float *table0 = ft->mSineWavetable;
810 float *table1 = table0 + 1;
812 for (int i=0; i < unit->mNumActive; ) {
813 GrainFMG *grain = unit->mGrains + i;
814 DECLARE_WINDOW
815 GET_GRAIN_AMP_PARAMS
817 int32 mfreq = grain->mfreq;
818 int32 moscphase = grain->moscphase;
819 int32 coscphase = grain->coscphase;
820 float deviation = grain->deviation;
821 float carbase = grain->carbase;
822 // begin add //
824 float pan2 = 0.f;
825 float *out2;
827 GET_PAN_PARAMS
829 // end add //
830 int nsmps = sc_min(grain->counter, inNumSamples);
831 for (int j=0; j<nsmps; ++j) {
832 float thismod = lookupi1(table0, table1, moscphase, unit->m_lomask) * deviation;
833 float outval = amp * lookupi1(table0, table1, coscphase, unit->m_lomask);
834 // begin change / add //
835 out1[j] += outval * pan1;
836 if(numOutputs > 1) out2[j] += outval * pan2;
837 // end change //
838 CALC_NEXT_GRAIN_AMP
840 int32 cfreq = (int32)(unit->m_cpstoinc * (carbase + thismod)); // needs to be calced in the loop!
841 coscphase += cfreq;
842 moscphase += mfreq;
843 } // need to save float carbase, int32 mfreq, float deviation
844 grain->coscphase = coscphase;
845 grain->moscphase = moscphase;
847 SAVE_GRAIN_AMP_PARAMS
849 if (grain->counter <= 0)
850 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
851 else
852 ++i;
856 template <bool full_rate>
857 inline void GrainFM_next_start_new(GrainFM * unit, int inNumSamples, int position)
859 if (unit->mNumActive+1 >= unit->mMaxGrains) {
860 Print("Too many grains!\n");
861 return;
864 float winType = grain_in_at<full_rate>(unit, 6, position);
865 DECLARE_WINDOW
866 bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame);
867 if (!success)
868 return;
870 GrainFMG *grain = unit->mGrains + unit->mNumActive++;
871 float winSize = GRAIN_IN_AT(unit, 1, position);
872 float carfreq = GRAIN_IN_AT(unit, 2, position);
873 float modfreq = GRAIN_IN_AT(unit, 3, position);
874 float index = GRAIN_IN_AT(unit, 4, position);
875 float deviation = grain->deviation = index * modfreq;
876 int32 mfreq = grain->mfreq = (int32)(unit->m_cpstoinc * modfreq);
877 grain->carbase = carfreq;
878 int32 coscphase = 0;
879 int32 moscphase = 0;
880 double counter = winSize * SAMPLERATE;
881 counter = sc_max(4., counter);
882 grain->counter = (int)counter;
883 grain->winType = winType; //GRAIN_IN_AT(unit, 6, i);
885 GET_GRAIN_INIT_AMP
886 const uint32 numOutputs = unit->mNumOutputs;
888 float *table0 = ft->mSineWavetable;
889 float *table1 = table0 + 1;
891 // begin add //
892 float pan = GRAIN_IN_AT(unit, 5, position);
894 CALC_GRAIN_PAN
896 WRAP_CHAN(position)
898 // end add //
899 int nsmps = sc_min(grain->counter, inNumSamples - position);
900 for (int j=0; j<nsmps; ++j) {
901 float thismod = lookupi1(table0, table1, moscphase, unit->m_lomask) * deviation;
902 float outval = amp * lookupi1(table0, table1, coscphase, unit->m_lomask);
903 // begin add / change
904 out1[j] += outval * pan1;
905 if(numOutputs > 1) out2[j] += outval * pan2;
906 // end add / change
907 CALC_NEXT_GRAIN_AMP
909 int32 cfreq = (int32)(unit->m_cpstoinc * (carfreq + thismod)); // needs to be calced in the loop!
910 coscphase += cfreq;
911 moscphase += mfreq;
912 } // need to save float carbase, int32 mfreq, float deviation
913 grain->coscphase = coscphase;
914 grain->moscphase = moscphase;
916 SAVE_GRAIN_AMP_PARAMS
918 if (grain->counter <= 0)
919 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
922 void GrainFM_next_a(GrainFM *unit, int inNumSamples)
924 ClearUnitOutputs(unit, inNumSamples);
926 GrainFM_next_play_active(unit, inNumSamples);
928 float *trig = IN(0);
929 for (int i=0; i<inNumSamples; ++i) {
930 if ((unit->curtrig <= 0) && (trig[i] > 0.0))
931 GrainFM_next_start_new<true>(unit, inNumSamples, i);
932 unit->curtrig = trig[i];
936 void GrainFM_next_k(GrainFM *unit, int inNumSamples)
938 ClearUnitOutputs(unit, inNumSamples);
940 if (unit->mFirst) {
941 unit->mFirst = false;
942 float maxGrains = IN0(7);
943 unit->mMaxGrains = (int)maxGrains;
944 unit->mGrains = (GrainFMG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainFMG));
947 GrainFM_next_play_active(unit, inNumSamples);
949 float trig = IN0(0);
950 if ((unit->curtrig <= 0) && (trig > 0.0))
951 GrainFM_next_start_new<false>(unit, inNumSamples, 0);
953 unit->curtrig = trig;
956 void GrainFM_Ctor(GrainFM *unit)
958 if (INRATE(0) == calc_FullRate)
959 SETCALC(GrainFM_next_a);
960 else
961 SETCALC(GrainFM_next_k);
962 int tableSizeSin = ft->mSineSize;
963 unit->m_lomask = (tableSizeSin - 1) << 3;
964 unit->m_radtoinc = tableSizeSin * (rtwopi * 65536.);
965 unit->m_cpstoinc = tableSizeSin * SAMPLEDUR * 65536.;
966 unit->curtrig = 0.f;
967 unit->mNumActive = 0;
968 unit->mFirst = true;
969 GrainFM_next_k(unit, 1);
972 void GrainFM_Dtor(GrainFM *unit)
974 RTFree(unit->mWorld, unit->mGrains);
977 #define GRAIN_BUF_LOOP_BODY_4_MONO \
978 phase = sc_gloop(phase, loopMax); \
979 int32 iphase = (int32)phase; \
980 const float* table1 = bufData + iphase; \
981 const float* table0 = table1 - 1; \
982 const float* table2 = table1 + 1; \
983 const float* table3 = table1 + 2; \
984 if (iphase == 0) { \
985 table0 += bufSamples; \
986 } else if (iphase >= guardFrame) { \
987 if (iphase == guardFrame) { \
988 table3 -= bufSamples; \
989 } else { \
990 table2 -= bufSamples; \
991 table3 -= bufSamples; \
994 float fracphase = phase - (double)iphase; \
995 float a = table0[0]; \
996 float b = table1[0]; \
997 float c = table2[0]; \
998 float d = table3[0]; \
999 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
1000 out1[j] += outval * pan1; \
1002 #define GRAIN_BUF_LOOP_BODY_4_STEREO \
1003 GRAIN_BUF_LOOP_BODY_4_MONO \
1004 out2[j] += outval * pan2;
1006 #define GRAIN_BUF_LOOP_BODY_2_MONO \
1007 phase = sc_gloop(phase, loopMax); \
1008 int32 iphase = (int32)phase; \
1009 const float* table1 = bufData + iphase; \
1010 const float* table2 = table1 + 1; \
1011 if (iphase > guardFrame) { \
1012 table2 -= bufSamples; \
1014 float fracphase = phase - (double)iphase; \
1015 float b = table1[0]; \
1016 float c = table2[0]; \
1017 float outval = amp * (b + fracphase * (c - b)); \
1018 out1[j] += outval * pan1; \
1020 #define GRAIN_BUF_LOOP_BODY_2_STEREO \
1021 GRAIN_BUF_LOOP_BODY_2_MONO \
1022 out2[j] += outval * pan2;
1024 #define GRAIN_BUF_LOOP_BODY_1_MONO \
1025 phase = sc_gloop(phase, loopMax); \
1026 int32 iphase = (int32)phase; \
1027 float outval = amp * bufData[iphase]; \
1028 out1[j] += outval * pan1;
1030 #define GRAIN_BUF_LOOP_BODY_1_STEREO \
1031 GRAIN_BUF_LOOP_BODY_1_MONO \
1032 out2[j] += outval * pan2;
1035 #define GRAIN_BUF_PLAY_GRAIN(WINDOW) \
1036 do {\
1037 if (numOutputs == 1) \
1039 if (grain->interp >= 4) { \
1040 for (int j=0; j<nsmps; j++) { \
1041 GRAIN_BUF_LOOP_BODY_4_MONO \
1042 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1043 phase += rate; \
1045 } else if (grain->interp >= 2) { \
1046 for (int j=0; j<nsmps; j++) { \
1047 GRAIN_BUF_LOOP_BODY_2_MONO \
1048 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1049 phase += rate; \
1051 } else { \
1052 for (int j=0; j<nsmps; j++) { \
1053 GRAIN_BUF_LOOP_BODY_1_MONO \
1054 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1055 phase += rate; \
1058 } else { \
1059 if (grain->interp >= 4) { \
1060 for (int j=0; j<nsmps; j++) { \
1061 GRAIN_BUF_LOOP_BODY_4_STEREO \
1062 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1063 phase += rate; \
1065 } else if (grain->interp >= 2) { \
1066 for (int j=0; j<nsmps; j++) { \
1067 GRAIN_BUF_LOOP_BODY_2_STEREO \
1068 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1069 phase += rate; \
1071 } else { \
1072 for (int j=0; j<nsmps; j++) { \
1073 GRAIN_BUF_LOOP_BODY_1_STEREO \
1074 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1075 phase += rate; \
1079 } while (0)
1082 static inline bool GrainBuf_grain_cleanup(GrainBuf * unit, GrainBufG * grain)
1084 if (grain->counter <= 0)
1086 *grain = unit->mGrains[--unit->mNumActive]; // remove grain
1087 return true;
1089 else
1090 return false;
1093 template <bool IsMono>
1094 static inline void GrainBuf_next_play_active(GrainBuf *unit, int inNumSamples)
1096 const uint32 numOutputs = IsMono ? 1 : unit->mNumOutputs;
1098 World *world = unit->mWorld;
1100 for (int i=0; i < unit->mNumActive; ) {
1101 GrainBufG *grain = unit->mGrains + i;
1102 uint32 bufnum = grain->bufnum;
1104 GRAIN_BUF
1106 if (!bufData || (bufChannels != 1)) {
1107 grain->counter -= inNumSamples;
1108 if (!GrainBuf_grain_cleanup(unit, grain))
1109 ++i;
1110 continue;
1113 double loopMax = (double)bufFrames;
1114 double rate = grain->rate;
1115 double phase = grain->phase;
1117 DECLARE_WINDOW
1118 GET_GRAIN_AMP_PARAMS
1122 // begin add //
1123 float pan2 = 0.f;
1124 float *out2;
1125 GET_PAN_PARAMS
1126 // end add //
1127 int nsmps = sc_min(grain->counter, inNumSamples);
1129 if (grain->winType < 0.)
1130 GRAIN_BUF_PLAY_GRAIN(INTERNAL);
1131 else
1132 GRAIN_BUF_PLAY_GRAIN(CUSTOM);
1134 if (GrainBuf_grain_cleanup(unit, grain))
1135 continue;
1136 ++i;
1138 grain->phase = phase;
1140 SAVE_GRAIN_AMP_PARAMS
1144 template <bool full_rate, bool IsMono>
1145 static inline void GrainBuf_next_start_new(GrainBuf *unit, int inNumSamples, int position)
1147 World *world = unit->mWorld;
1149 if (unit->mNumActive+1 >= unit->mMaxGrains) {
1150 Print("Too many grains!\n");
1151 return;
1154 float winType = grain_in_at<full_rate>(unit, 7, position);
1155 DECLARE_WINDOW
1156 bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame);
1157 if (!success)
1158 return;
1160 GrainBufG *grain = unit->mGrains + unit->mNumActive++;
1161 int32 bufnum = grain_in_at<full_rate>(unit, 2, position);
1162 grain->bufnum = bufnum;
1164 GRAIN_BUF
1166 if ( (bufChannels != 1) || (!bufData) ) {
1167 GrainBuf_grain_cleanup(unit, grain);
1168 return;
1171 float bufSampleRate = buf->samplerate;
1172 float bufRateScale = bufSampleRate * SAMPLEDUR;
1173 double loopMax = (double)bufFrames;
1175 double counter = grain_in_at<full_rate>(unit, 1, position) * SAMPLERATE;
1176 counter = sc_max(4., counter);
1177 grain->counter = (int)counter;
1179 double rate = grain->rate = grain_in_at<full_rate>(unit, 3, position) * bufRateScale;
1180 double phase = grain_in_at<full_rate>(unit, 4, position) * bufFrames;
1181 if (sc_isnan(phase)) {
1182 GrainBuf_grain_cleanup(unit, grain);
1183 return;
1186 grain->interp = (int)grain_in_at<full_rate>(unit, 5, position);
1187 grain->winType = winType;
1189 GET_GRAIN_INIT_AMP
1191 const uint32 numOutputs = IsMono ? 1 : unit->mNumOutputs;
1193 // begin add //
1194 float pan = grain_in_at<full_rate>(unit, 6, position);
1196 CALC_GRAIN_PAN
1198 WRAP_CHAN(position)
1200 // end add //
1202 int nsmps = sc_min(grain->counter, inNumSamples - position);
1204 if (grain->winType < 0.)
1205 GRAIN_BUF_PLAY_GRAIN(INTERNAL);
1206 else
1207 GRAIN_BUF_PLAY_GRAIN(CUSTOM);
1209 grain->phase = phase;
1211 SAVE_GRAIN_AMP_PARAMS
1213 GrainBuf_grain_cleanup(unit, grain);
1217 template <bool MultiChannel>
1218 static void GrainBuf_next_a(GrainBuf *unit, int inNumSamples)
1220 ClearUnitOutputs(unit, inNumSamples);
1222 GrainBuf_next_play_active<MultiChannel>(unit, inNumSamples);
1224 float *trig = IN(0);
1225 for (int i=0; i<inNumSamples; i++) {
1226 if ((trig[i] > 0) && (unit->curtrig <=0))
1227 GrainBuf_next_start_new<true, MultiChannel>(unit, inNumSamples, i);
1228 unit->curtrig = trig[i];
1232 template <bool MultiChannel>
1233 static void GrainBuf_next_k(GrainBuf * unit, int inNumSamples)
1235 ClearUnitOutputs(unit, inNumSamples);
1237 GrainBuf_next_play_active<MultiChannel>(unit, inNumSamples);
1239 float trig = IN0(0);
1240 if ((trig > 0) && (unit->curtrig <=0))
1241 GrainBuf_next_start_new<false, MultiChannel>(unit, inNumSamples, 0);
1242 unit->curtrig = trig;
1245 FLATTEN static void GrainBuf_next_k_1(GrainBuf * unit, int inNumSamples)
1247 GrainBuf_next_k<true>(unit, inNumSamples);
1250 FLATTEN static void GrainBuf_next_k_2(GrainBuf * unit, int inNumSamples)
1252 GrainBuf_next_k<false>(unit, inNumSamples);
1255 FLATTEN static void GrainBuf_next_a_1(GrainBuf * unit, int inNumSamples)
1257 GrainBuf_next_a<true>(unit, inNumSamples);
1260 FLATTEN static void GrainBuf_next_a_2(GrainBuf * unit, int inNumSamples)
1262 GrainBuf_next_a<false>(unit, inNumSamples);
1265 void GrainBuf_Ctor(GrainBuf *unit)
1267 unit->mNumActive = 0;
1268 unit->curtrig = 0.f;
1270 float maxGrains = IN0(8);
1271 unit->mMaxGrains = (int)maxGrains;
1272 unit->mGrains = (GrainBufG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainBufG));
1274 if (unit->mNumOutputs == 1) {
1275 if (INRATE(0) == calc_FullRate)
1276 SETCALC(GrainBuf_next_a_1);
1277 else
1278 SETCALC(GrainBuf_next_k_1);
1279 } else {
1280 if (INRATE(0) == calc_FullRate)
1281 SETCALC(GrainBuf_next_a_2);
1282 else
1283 SETCALC(GrainBuf_next_k_2);
1286 (unit->mCalcFunc)(unit, 1);
1289 void GrainBuf_Dtor(GrainBuf *unit)
1291 RTFree(unit->mWorld, unit->mGrains);
1295 #define BUF_GRAIN_LOOP_BODY_4_N \
1296 phase = sc_gloop(phase, loopMax); \
1297 int32 iphase = (int32)phase; \
1298 const float* table1 = bufData + iphase * bufChannels; \
1299 const float* table0 = table1 - bufChannels; \
1300 const float* table2 = table1 + bufChannels; \
1301 const float* table3 = table2 + bufChannels; \
1302 if (iphase == 0) { \
1303 table0 += bufSamples; \
1304 } else if (iphase >= guardFrame) { \
1305 if (iphase == guardFrame) { \
1306 table3 -= bufSamples; \
1307 } else { \
1308 table2 -= bufSamples; \
1309 table3 -= bufSamples; \
1312 float fracphase = phase - (double)iphase; \
1313 float a = table0[n]; \
1314 float b = table1[n]; \
1315 float c = table2[n]; \
1316 float d = table3[n]; \
1317 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
1318 ZXP(out1) += outval; \
1320 #define BUF_GRAIN_LOOP_BODY_2_N \
1321 phase = sc_gloop(phase, loopMax); \
1322 int32 iphase = (int32)phase; \
1323 const float* table1 = bufData + iphase * bufChannels; \
1324 const float* table2 = table1 + bufChannels; \
1325 if (iphase > guardFrame) { \
1326 table2 -= bufSamples; \
1328 float fracphase = phase - (double)iphase; \
1329 float b = table1[n]; \
1330 float c = table2[n]; \
1331 float outval = amp * (b + fracphase * (c - b)); \
1332 ZXP(out1) += outval; \
1334 // amp needs to be calculated by looking up values in window
1336 #define BUF_GRAIN_LOOP_BODY_1_N \
1337 phase = sc_gloop(phase, loopMax); \
1338 int32 iphase = (int32)phase; \
1339 float outval = amp * bufData[iphase + n]; \
1340 ZXP(out1) += outval; \
1343 #define GET_WARP_WIN_RELAXED(WINTYPE) \
1344 do { \
1345 assert(WINTYPE < unit->mWorld->mNumSndBufs); \
1346 window = unit->mWorld->mSndBufs + (int)WINTYPE; \
1347 while (!TRY_ACQUIRE_SNDBUF_SHARED(window)) { \
1348 RELEASE_SNDBUF_SHARED(buf); \
1349 ACQUIRE_SNDBUF_SHARED(buf); \
1351 windowData = window->data; \
1352 if (windowData == NULL) \
1353 RELEASE_SNDBUF_SHARED(window); \
1354 windowSamples = window->samples; \
1355 windowFrames = window->frames; \
1356 windowGuardFrame = windowFrames - 1; \
1357 } while (0);
1359 #define GET_WARP_AMP_PARAMS \
1360 if(grain->winType < 0.){ \
1361 b1 = grain->b1; \
1362 y1 = grain->y1; \
1363 y2 = grain->y2; \
1364 amp = grain->curamp; \
1365 } else { \
1366 GET_WARP_WIN_RELAXED(grain->winType); \
1367 if (!windowData) break; \
1368 winPos = grain->winPos; \
1369 winInc = grain->winInc; \
1370 amp = grain->curamp; \
1374 void Warp1_next(Warp1 *unit, int inNumSamples)
1376 ClearUnitOutputs(unit, inNumSamples);
1378 GET_BUF
1379 SETUP_OUT
1380 CHECK_BUF
1382 for (uint32 n=0; n < numOutputs; n++) {
1383 int nextGrain = unit->mNextGrain[n];
1384 for (int i=0; i < unit->mNumActive[n]; ) {
1385 WarpWinGrain *grain = unit->mGrains[n] + i;
1387 double loopMax = (double)bufFrames;
1389 double rate = grain->rate;
1390 double phase = grain->phase;
1391 DECLARE_WINDOW
1392 GET_GRAIN_AMP_PARAMS
1393 float *out1 = out[n];
1394 int nsmps = sc_min(grain->counter, inNumSamples);
1395 if (grain->interp >= 4) {
1396 for (int j=0; j<nsmps; ++j) {
1397 BUF_GRAIN_LOOP_BODY_4_N
1398 CALC_NEXT_GRAIN_AMP
1399 phase += rate;
1401 } else if (grain->interp >= 2) {
1402 for (int j=0; j<nsmps; ++j) {
1403 BUF_GRAIN_LOOP_BODY_2_N
1404 CALC_NEXT_GRAIN_AMP
1405 phase += rate;
1407 } else {
1408 for (int j=0; j<nsmps; ++j) {
1409 BUF_GRAIN_LOOP_BODY_1_N
1410 CALC_NEXT_GRAIN_AMP
1411 phase += rate;
1415 grain->phase = phase;
1416 SAVE_GRAIN_AMP_PARAMS
1417 if (grain->counter <= 0)
1418 *grain = unit->mGrains[n][--unit->mNumActive[n]]; // remove grain
1419 else
1420 ++i;
1423 for (int i=0; i<inNumSamples; ++i) {
1424 --nextGrain;
1425 if (nextGrain == 0) {
1426 // start a grain
1427 if (unit->mNumActive[n]+1 >= kMaxGrains) break;
1428 // uint32 bufnum = (uint32)GRAIN_IN_AT(unit, 0, i);
1429 // if (bufnum >= numBufs) break;
1431 float bufSampleRate = buf->samplerate;
1432 float bufRateScale = bufSampleRate * SAMPLEDUR;
1433 double loopMax = (double)bufFrames;
1435 WarpWinGrain *grain = unit->mGrains[n] + unit->mNumActive[n]++;
1436 // grain->bufnum = bufnum;
1438 float overlaps = GRAIN_IN_AT(unit, 5, i);
1439 float counter = GRAIN_IN_AT(unit, 3, i) * SAMPLERATE;
1440 double winrandamt = unit->mParent->mRGen->frand2() * (double)GRAIN_IN_AT(unit, 6, i);
1441 counter = sc_max(4., floor(counter + (counter * winrandamt)));
1442 grain->counter = (int)counter;
1444 nextGrain = (int)(counter / overlaps);
1446 unit->mNextGrain[n] = nextGrain;
1448 float rate = grain->rate = GRAIN_IN_AT(unit, 2, i) * bufRateScale;
1449 float phase = GRAIN_IN_AT(unit, 1, i) * (float)bufFrames;
1450 grain->interp = (int)GRAIN_IN_AT(unit, 7, i);
1451 float winType = grain->winType = (int)GRAIN_IN_AT(unit, 4, i); // the buffer that holds the grain shape
1452 DECLARE_WINDOW
1454 if (winType >= unit->mWorld->mNumSndBufs) {
1455 Print("Envelope buffer out of range!\n");
1456 break;
1459 GET_GRAIN_WIN_RELAXED(winType)
1460 if (windowData || (winType < 0.)) {
1461 GET_GRAIN_INIT_AMP
1463 float *out1 = out[n] + i;
1465 int nsmps = sc_min(grain->counter, inNumSamples - i);
1466 if (grain->interp >= 4) {
1467 for (int j=0; j<nsmps; ++j) {
1468 BUF_GRAIN_LOOP_BODY_4_N
1469 CALC_NEXT_GRAIN_AMP
1470 phase += rate;
1472 } else if (grain->interp >= 2) {
1473 for (int j=0; j<nsmps; ++j) {
1474 BUF_GRAIN_LOOP_BODY_2_N
1475 CALC_NEXT_GRAIN_AMP
1476 phase += rate;
1478 } else {
1479 for (int j=0; j<nsmps; ++j) {
1480 BUF_GRAIN_LOOP_BODY_1_N
1481 CALC_NEXT_GRAIN_AMP
1482 phase += rate;
1486 grain->phase = phase;
1487 SAVE_GRAIN_AMP_PARAMS
1488 // end change
1489 if (grain->counter <= 0)
1490 *grain = unit->mGrains[n][--unit->mNumActive[n]]; // remove grain
1495 unit->mNextGrain[n] = nextGrain;
1499 void Warp1_Ctor(Warp1 *unit)
1501 SETCALC(Warp1_next);
1503 for(int i = 0; i < 16; i++){
1504 unit->mNumActive[i] = 0;
1505 unit->mNextGrain[i] = 1;
1508 ClearUnitOutputs(unit, 1);
1509 unit->m_fbufnum = -1e9f;
1513 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1515 PluginLoad(Grain)
1517 ft = inTable;
1519 DefineDtorCantAliasUnit(GrainIn);
1520 DefineDtorCantAliasUnit(GrainSin);
1521 DefineDtorCantAliasUnit(GrainFM);
1522 DefineDtorCantAliasUnit(GrainBuf);
1523 DefineSimpleCantAliasUnit(Warp1);