5 * Created by Josh Parmenter on 2/4/05.
6 * Copyright 2005 __MyCompanyName__. All rights reserved.
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;
42 double b1
, y1
, y2
, curamp
, winPos
, winInc
; // envelope
44 float pan1
, pan2
, winType
;
47 struct GrainIn
: public Unit
49 int mNumActive
, m_channels
, mMaxGrains
;
57 double b1
, y1
, y2
, curamp
, winPos
, winInc
; // envelope
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
;
70 double m_cpstoinc
, m_radtoinc
;
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
;
84 struct GrainFM
: public Unit
86 int mNumActive
, m_channels
, mMaxGrains
;
90 double m_cpstoinc
, m_radtoinc
;
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
;
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
;
117 struct Warp1
: public Unit
123 WarpWinGrain mGrains
[16][kMaxGrains
];
126 ////////////////////////////////////////////////////////////////////////
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);
164 template <bool full_rate
>
165 inline float grain_in_at(Unit
* unit
, int index
, int offset
)
168 return GRAIN_IN_AT(unit
, index
, offset
);
170 if (INRATE(index
) == calc_DemandRate
)
171 return DEMANDINPUT_A(index
, offset
+ 1);
176 inline double sc_gloop(double in
, double hi
)
178 // avoid the divide if possible
181 if (in
< hi
) return in
;
182 } else if (in
< 0.) {
184 if (in
>= 0.) return in
;
187 return in
- hi
* floor(in
/hi
);
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; \
199 buf = world->mSndBufs + bufnum; \
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; \
215 winPos = winInc = w = b1 = y1 = y2 = y0 = amp = 0.; \
217 const float *windowData __attribute__((__unused__)) = 0;\
218 uint32 windowSamples __attribute__((__unused__)) = 0; \
219 uint32 windowFrames __attribute__((__unused__)) = 0; \
220 int windowGuardFrame = 0;
225 unit->mDone = true; \
226 ClearUnitOutputs(unit, inNumSamples); \
230 #define GET_GRAIN_WIN_RELAXED(WINTYPE) \
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; \
240 #define GET_GRAIN_WIN(WINTYPE) \
242 if (WINTYPE >= unit->mWorld->mNumSndBufs) { \
243 Print("Envelope buffer out of range!\n"); \
246 GET_GRAIN_WIN_RELAXED(WINTYPE) \
249 #define GRAIN_LOOP_BODY_4 \
250 float amp = y1 * y1; \
251 phase = sc_gloop(phase, loopMax); \
252 int32 iphase = (int32)phase; \
253 float* table1 = bufData + iphase; \
254 float* table0 = table1 - 1; \
255 float* table2 = table1 + 1; \
256 float* table3 = table1 + 2; \
258 table0 += bufSamples; \
259 } else if (iphase >= guardFrame) { \
260 if (iphase == guardFrame) { \
261 table3 -= bufSamples; \
263 table2 -= bufSamples; \
264 table3 -= bufSamples; \
267 float fracphase = phase - (double)iphase; \
268 float a = table0[0]; \
269 float b = table1[0]; \
270 float c = table2[0]; \
271 float d = table3[0]; \
272 float outval = amp * cubicinterp(fracphase, a, b, c, d) \
273 ZXP(out1) += outval; \
274 double y0 = b1 * y1 - y2; \
278 #define GRAIN_LOOP_BODY_2 \
279 float amp = y1 * y1; \
280 phase = sc_gloop(phase, loopMax); \
281 int32 iphase = (int32)phase; \
282 float* table1 = bufData + iphase; \
283 float* table2 = table1 + 1; \
284 if (iphase > guardFrame) { \
285 table2 -= bufSamples; \
287 double fracphase = phase - (double)iphase; \
288 float b = table1[0]; \
289 float c = table2[0]; \
290 float outval = amp * (b + fracphase * (c - b)); \
291 ZXP(out1) += outval; \
292 double y0 = b1 * y1 - y2; \
297 #define GRAIN_LOOP_BODY_1 \
298 float amp = y1 * y1; \
299 phase = sc_gloop(phase, loopMax); \
300 int32 iphase = (int32)phase; \
301 float outval = amp * bufData[iphase]; \
302 ZXP(out1) += outval; \
303 double y0 = b1 * y1 - y2; \
307 #define BUF_GRAIN_AMP \
309 int iWinPos = (int)winPos; \
310 double winFrac = winPos - (double)iWinPos; \
311 float* winTable1 = windowData + iWinPos; \
312 float* winTable2 = winTable1 + 1; \
313 if (winPos > windowGuardFrame) { \
314 winTable2 -= windowSamples; \
316 amp = lininterp(winFrac, winTable1[0], winTable2[0]);
318 #define BUF_GRAIN_LOOP_BODY_4 \
319 phase = sc_gloop(phase, loopMax); \
320 int32 iphase = (int32)phase; \
321 float* table1 = bufData + iphase; \
322 float* table0 = table1 - 1; \
323 float* table2 = table1 + 1; \
324 float* table3 = table1 + 2; \
326 table0 += bufSamples; \
327 } else if (iphase >= guardFrame) { \
328 if (iphase == guardFrame) { \
329 table3 -= bufSamples; \
331 table2 -= bufSamples; \
332 table3 -= bufSamples; \
335 float fracphase = phase - (double)iphase; \
336 float a = table0[0]; \
337 float b = table1[0]; \
338 float c = table2[0]; \
339 float d = table3[0]; \
340 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
343 #define BUF_GRAIN_LOOP_BODY_2 \
344 phase = sc_gloop(phase, loopMax); \
345 int32 iphase = (int32)phase; \
346 float* table1 = bufData + iphase; \
347 float* table2 = table1 + 1; \
348 if (iphase > guardFrame) { \
349 table2 -= bufSamples; \
351 float fracphase = phase - (double)iphase; \
352 float b = table1[0]; \
353 float c = table2[0]; \
354 float outval = amp * (b + fracphase * (c - b)); \
357 // amp needs to be calculated by looking up values in window
359 #define BUF_GRAIN_LOOP_BODY_1 \
360 phase = sc_gloop(phase, loopMax); \
361 int32 iphase = (int32)phase; \
362 float outval = amp * bufData[iphase]; \
367 uint32 numOutputs = unit->mNumOutputs; \
368 if (numOutputs > bufChannels) { \
369 unit->mDone = true; \
370 ClearUnitOutputs(unit, inNumSamples); \
374 for (uint32 i=0; i<numOutputs; ++i) out[i] = ZOUT(i);
377 #define CALC_GRAIN_PAN \
378 float panangle, pan1, pan2; \
379 float *out1, *out2; \
380 if (numOutputs > 1) { \
381 if (numOutputs == 2) pan = pan * 0.5f; \
382 pan = sc_wrap(pan * 0.5f, 0.f, 1.f); \
383 float cpan = numOutputs * pan + 0.5f; \
384 float ipan = floor(cpan); \
385 float panfrac = cpan - ipan; \
386 panangle = panfrac * pi2_f; \
387 grain->chan = (int)ipan; \
388 if (grain->chan >= (int)numOutputs) \
389 grain->chan -= numOutputs; \
390 pan1 = grain->pan1 = cos(panangle); \
391 pan2 = grain->pan2 = sin(panangle); \
394 pan1 = grain->pan1 = 1.; \
395 pan2 = grain->pan2 = 0.; \
398 #define GET_GRAIN_INIT_AMP \
399 if(grain->winType < 0.){ \
401 b1 = grain->b1 = 2. * cos(w); \
406 amp = windowData[0]; \
407 winPos = grain->winPos = 0.f; \
408 winInc = grain->winInc = (double)windowSamples / counter; \
411 #define CALC_NEXT_GRAIN_AMP_INTERNAL \
419 #define CALC_NEXT_GRAIN_AMP_CUSTOM \
422 int iWinPos = (int)winPos; \
423 double winFrac = winPos - (double)iWinPos; \
424 const float* winTable1 = windowData + iWinPos; \
425 const float* winTable2 = winTable1 + 1; \
428 if (winPos > windowGuardFrame) \
429 winTable2 -= windowSamples; \
430 amp = lininterp(winFrac, winTable1[0], winTable2[0]); \
435 #define CALC_NEXT_GRAIN_AMP \
436 if(grain->winType < 0.) { \
437 CALC_NEXT_GRAIN_AMP_INTERNAL; \
439 CALC_NEXT_GRAIN_AMP_CUSTOM; \
443 #define GET_GRAIN_AMP_PARAMS \
444 if(grain->winType < 0.){ \
448 amp = grain->curamp; \
450 GET_GRAIN_WIN_RELAXED(grain->winType); \
451 if (!windowData) break; \
452 winPos = grain->winPos; \
453 winInc = grain->winInc; \
454 amp = grain->curamp; \
457 #define SAVE_GRAIN_AMP_PARAMS \
460 grain->winPos = winPos; \
461 grain->winInc = winInc; \
462 grain->curamp = amp; \
463 grain->counter -= nsmps;
465 #define WRAP_CHAN(offset) \
466 out1 = OUT(grain->chan) + offset; \
467 if(numOutputs > 1) { \
468 if((grain->chan + 1) >= (int)numOutputs) \
469 out2 = OUT(0) + offset; \
471 out2 = OUT(grain->chan + 1) + offset; \
474 #define GET_PAN_PARAMS \
475 float pan1 = grain->pan1; \
476 uint32 chan1 = grain->chan; \
477 float *out1 = OUT(chan1); \
478 if(numOutputs > 1){ \
479 pan2 = grain->pan2; \
480 uint32 chan2 = chan1 + 1; \
481 if (chan2 >= numOutputs) chan2 = 0; \
486 //////////////////// InGrain ////////////////////
488 inline void GrainIn_next_play_active(GrainIn
* unit
, int inNumSamples
)
490 const uint32 numOutputs
= unit
->mNumOutputs
;
492 for (int i
=0; i
< unit
->mNumActive
; ) {
493 GrainInG
*grain
= unit
->mGrains
+ i
;
503 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
504 for (int j
=0; j
<nsmps
; ++j
) {
505 float outval
= amp
* in
[j
];
506 // begin change / add //
507 out1
[j
] += outval
* pan1
;
508 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
514 SAVE_GRAIN_AMP_PARAMS
516 if (grain
->counter
<= 0)
517 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
523 template <bool full_rate
>
524 inline void GrainIn_next_start_new(GrainIn
* unit
, int inNumSamples
, int position
)
526 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
527 Print("Too many grains!\n");
531 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
533 GET_GRAIN_WIN(winType
)
534 if (winType
>= 0 && (windowData
== NULL
))
537 GrainInG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
538 float winSize
= grain_in_at
<full_rate
>(unit
, 1, position
);
539 double counter
= winSize
* SAMPLERATE
;
540 counter
= sc_max(4., counter
);
541 grain
->counter
= (int)counter
;
542 grain
->winType
= winType
;
546 const uint32 numOutputs
= unit
->mNumOutputs
;
549 float *in1
= in
+ position
;
551 float pan
= grain_in_at
<full_rate
>(unit
, 3, position
);
557 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
558 for (int j
=0; j
<nsmps
; ++j
) {
559 float outval
= amp
* in1
[j
];
560 // begin add / change
561 out1
[j
] += outval
* pan1
;
562 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
567 SAVE_GRAIN_AMP_PARAMS
569 if (grain
->counter
<= 0)
570 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
573 void GrainIn_next_a(GrainIn
*unit
, int inNumSamples
)
575 ClearUnitOutputs(unit
, inNumSamples
);
579 GrainIn_next_play_active(unit
, inNumSamples
);
582 for (int i
=0; i
<inNumSamples
; ++i
) {
583 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
584 GrainIn_next_start_new
<true>(unit
, inNumSamples
, i
);
585 unit
->curtrig
= trig
[i
];
589 void GrainIn_next_k(GrainIn
*unit
, int inNumSamples
)
591 ClearUnitOutputs(unit
, inNumSamples
);
593 unit
->mFirst
= false;
594 float maxGrains
= IN0(5);
595 unit
->mMaxGrains
= (int)maxGrains
;
596 unit
->mGrains
= (GrainInG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainInG
));
599 GrainIn_next_play_active(unit
, inNumSamples
);
603 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
604 GrainIn_next_start_new
<false>(unit
, inNumSamples
, 0);
605 unit
->curtrig
= trig
;
609 void GrainIn_Ctor(GrainIn
*unit
)
611 if (INRATE(0) == calc_FullRate
)
612 SETCALC(GrainIn_next_a
);
614 SETCALC(GrainIn_next_k
);
616 unit
->mNumActive
= 0;
618 GrainIn_next_k(unit
, 1);
621 void GrainIn_Dtor(GrainIn
*unit
)
623 RTFree(unit
->mWorld
, unit
->mGrains
);
626 inline void GrainSin_next_play_active(GrainSin
* unit
, int inNumSamples
)
628 const unsigned int numOutputs
= unit
->mNumOutputs
;
630 float *table0
= ft
->mSineWavetable
;
631 float *table1
= table0
+ 1;
633 for (int i
=0; i
< unit
->mNumActive
; ) {
634 GrainSinG
*grain
= unit
->mGrains
+ i
;
647 int32 thisfreq
= grain
->freq
;
648 int32 oscphase
= grain
->oscphase
;
650 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
651 for (int j
=0; j
<nsmps
; ++j
) {
652 float outval
= amp
* lookupi1(table0
, table1
, oscphase
, unit
->m_lomask
);
653 // begin change / add //
654 out1
[j
] += outval
* pan1
;
655 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
659 oscphase
+= thisfreq
;
662 SAVE_GRAIN_AMP_PARAMS
664 grain
->oscphase
= oscphase
;
665 if (grain
->counter
<= 0)
666 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
672 template <bool full_rate
>
673 inline void GrainSin_next_start_new(GrainSin
* unit
, int inNumSamples
, int position
)
675 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
676 Print("Too many grains!\n");
680 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
682 GET_GRAIN_WIN(winType
)
683 if (winType
>= 0 && (windowData
== NULL
))
686 GrainSinG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
687 float freq
= grain_in_at
<full_rate
>(unit
, 2, position
);
688 float winSize
= grain_in_at
<full_rate
>(unit
, 1, position
);
689 int32 thisfreq
= grain
->freq
= (int32
)(unit
->m_cpstoinc
* freq
);
691 double counter
= winSize
* SAMPLERATE
;
692 counter
= sc_max(4., counter
);
693 grain
->counter
= (int)counter
;
694 grain
->winType
= winType
;
698 const uint32 numOutputs
= unit
->mNumOutputs
;
700 float *table0
= ft
->mSineWavetable
;
701 float *table1
= table0
+ 1;
704 float pan
= grain_in_at
<full_rate
>(unit
, 3, position
);
712 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
713 for (int j
=0; j
<nsmps
; ++j
) {
714 float outval
= amp
* lookupi1(table0
, table1
, oscphase
, unit
->m_lomask
);
715 // begin add / change
716 out1
[j
] += outval
* pan1
;
717 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
721 oscphase
+= thisfreq
;
723 grain
->oscphase
= oscphase
;
725 SAVE_GRAIN_AMP_PARAMS
727 if (grain
->counter
<= 0)
728 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
731 void GrainSin_next_a(GrainSin
*unit
, int inNumSamples
)
733 ClearUnitOutputs(unit
, inNumSamples
);
735 GrainSin_next_play_active(unit
, inNumSamples
);
738 for (int i
=0; i
<inNumSamples
; ++i
) {
739 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
740 GrainSin_next_start_new
<true>(unit
, inNumSamples
, i
);
741 unit
->curtrig
= trig
[i
];
745 void GrainSin_next_k(GrainSin
*unit
, int inNumSamples
)
747 ClearUnitOutputs(unit
, inNumSamples
);
749 unit
->mFirst
= false;
750 float maxGrains
= IN0(5);
751 unit
->mMaxGrains
= (int)maxGrains
;
752 unit
->mGrains
= (GrainSinG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainSinG
));
755 GrainSin_next_play_active(unit
, inNumSamples
);
760 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
761 GrainSin_next_start_new
<false>(unit
, inNumSamples
, 0);
762 unit
->curtrig
= trig
;
765 void GrainSin_Ctor(GrainSin
*unit
)
767 if (INRATE(0) == calc_FullRate
)
768 SETCALC(GrainSin_next_a
);
770 SETCALC(GrainSin_next_k
);
771 int tableSizeSin
= ft
->mSineSize
;
772 unit
->m_lomask
= (tableSizeSin
- 1) << 3;
773 unit
->m_radtoinc
= tableSizeSin
* (rtwopi
* 65536.);
774 unit
->m_cpstoinc
= tableSizeSin
* SAMPLEDUR
* 65536.;
776 unit
->mNumActive
= 0;
778 GrainSin_next_k(unit
, 1);
781 void GrainSin_Dtor(GrainSin
*unit
)
783 RTFree(unit
->mWorld
, unit
->mGrains
);
787 inline void GrainFM_next_play_active(GrainFM
*unit
, int inNumSamples
)
789 const uint32 numOutputs
= unit
->mNumOutputs
;
792 float *table0
= ft
->mSineWavetable
;
793 float *table1
= table0
+ 1;
795 for (int i
=0; i
< unit
->mNumActive
; ) {
796 GrainFMG
*grain
= unit
->mGrains
+ i
;
800 int32 mfreq
= grain
->mfreq
;
801 int32 moscphase
= grain
->moscphase
;
802 int32 coscphase
= grain
->coscphase
;
803 float deviation
= grain
->deviation
;
804 float carbase
= grain
->carbase
;
813 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
814 for (int j
=0; j
<nsmps
; ++j
) {
815 float thismod
= lookupi1(table0
, table1
, moscphase
, unit
->m_lomask
) * deviation
;
816 float outval
= amp
* lookupi1(table0
, table1
, coscphase
, unit
->m_lomask
);
817 // begin change / add //
818 out1
[j
] += outval
* pan1
;
819 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
823 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carbase
+ thismod
)); // needs to be calced in the loop!
826 } // need to save float carbase, int32 mfreq, float deviation
827 grain
->coscphase
= coscphase
;
828 grain
->moscphase
= moscphase
;
830 SAVE_GRAIN_AMP_PARAMS
832 if (grain
->counter
<= 0)
833 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
839 template <bool full_rate
>
840 inline void GrainFM_next_start_new(GrainFM
* unit
, int inNumSamples
, int position
)
842 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
843 Print("Too many grains!\n");
847 float winType
= grain_in_at
<full_rate
>(unit
, 6, position
);
849 GET_GRAIN_WIN(winType
)
850 if (winType
>= 0 && (windowData
== NULL
))
853 GrainFMG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
854 float winSize
= GRAIN_IN_AT(unit
, 1, position
);
855 float carfreq
= GRAIN_IN_AT(unit
, 2, position
);
856 float modfreq
= GRAIN_IN_AT(unit
, 3, position
);
857 float index
= GRAIN_IN_AT(unit
, 4, position
);
858 float deviation
= grain
->deviation
= index
* modfreq
;
859 int32 mfreq
= grain
->mfreq
= (int32
)(unit
->m_cpstoinc
* modfreq
);
860 grain
->carbase
= carfreq
;
863 double counter
= winSize
* SAMPLERATE
;
864 counter
= sc_max(4., counter
);
865 grain
->counter
= (int)counter
;
866 grain
->winType
= winType
; //GRAIN_IN_AT(unit, 6, i);
869 const uint32 numOutputs
= unit
->mNumOutputs
;
871 float *table0
= ft
->mSineWavetable
;
872 float *table1
= table0
+ 1;
875 float pan
= GRAIN_IN_AT(unit
, 5, position
);
882 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
883 for (int j
=0; j
<nsmps
; ++j
) {
884 float thismod
= lookupi1(table0
, table1
, moscphase
, unit
->m_lomask
) * deviation
;
885 float outval
= amp
* lookupi1(table0
, table1
, coscphase
, unit
->m_lomask
);
886 // begin add / change
887 out1
[j
] += outval
* pan1
;
888 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
892 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carfreq
+ thismod
)); // needs to be calced in the loop!
895 } // need to save float carbase, int32 mfreq, float deviation
896 grain
->coscphase
= coscphase
;
897 grain
->moscphase
= moscphase
;
899 SAVE_GRAIN_AMP_PARAMS
901 if (grain
->counter
<= 0)
902 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
905 void GrainFM_next_a(GrainFM
*unit
, int inNumSamples
)
907 ClearUnitOutputs(unit
, inNumSamples
);
909 GrainFM_next_play_active(unit
, inNumSamples
);
912 for (int i
=0; i
<inNumSamples
; ++i
) {
913 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
914 GrainFM_next_start_new
<true>(unit
, inNumSamples
, i
);
915 unit
->curtrig
= trig
[i
];
919 void GrainFM_next_k(GrainFM
*unit
, int inNumSamples
)
921 ClearUnitOutputs(unit
, inNumSamples
);
924 unit
->mFirst
= false;
925 float maxGrains
= IN0(7);
926 unit
->mMaxGrains
= (int)maxGrains
;
927 unit
->mGrains
= (GrainFMG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainFMG
));
930 GrainFM_next_play_active(unit
, inNumSamples
);
933 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
934 GrainFM_next_start_new
<false>(unit
, inNumSamples
, 0);
936 unit
->curtrig
= trig
;
939 void GrainFM_Ctor(GrainFM
*unit
)
941 if (INRATE(0) == calc_FullRate
)
942 SETCALC(GrainFM_next_a
);
944 SETCALC(GrainFM_next_k
);
945 int tableSizeSin
= ft
->mSineSize
;
946 unit
->m_lomask
= (tableSizeSin
- 1) << 3;
947 unit
->m_radtoinc
= tableSizeSin
* (rtwopi
* 65536.);
948 unit
->m_cpstoinc
= tableSizeSin
* SAMPLEDUR
* 65536.;
950 unit
->mNumActive
= 0;
952 GrainFM_next_k(unit
, 1);
955 void GrainFM_Dtor(GrainFM
*unit
)
957 RTFree(unit
->mWorld
, unit
->mGrains
);
960 #define GRAIN_BUF_LOOP_BODY_4_MONO \
961 phase = sc_gloop(phase, loopMax); \
962 int32 iphase = (int32)phase; \
963 const float* table1 = bufData + iphase; \
964 const float* table0 = table1 - 1; \
965 const float* table2 = table1 + 1; \
966 const float* table3 = table1 + 2; \
968 table0 += bufSamples; \
969 } else if (iphase >= guardFrame) { \
970 if (iphase == guardFrame) { \
971 table3 -= bufSamples; \
973 table2 -= bufSamples; \
974 table3 -= bufSamples; \
977 float fracphase = phase - (double)iphase; \
978 float a = table0[0]; \
979 float b = table1[0]; \
980 float c = table2[0]; \
981 float d = table3[0]; \
982 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
983 out1[j] += outval * pan1; \
985 #define GRAIN_BUF_LOOP_BODY_4_STEREO \
986 GRAIN_BUF_LOOP_BODY_4_MONO \
987 out2[j] += outval * pan2;
989 #define GRAIN_BUF_LOOP_BODY_2_MONO \
990 phase = sc_gloop(phase, loopMax); \
991 int32 iphase = (int32)phase; \
992 const float* table1 = bufData + iphase; \
993 const float* table2 = table1 + 1; \
994 if (iphase > guardFrame) { \
995 table2 -= bufSamples; \
997 float fracphase = phase - (double)iphase; \
998 float b = table1[0]; \
999 float c = table2[0]; \
1000 float outval = amp * (b + fracphase * (c - b)); \
1001 out1[j] += outval * pan1; \
1003 #define GRAIN_BUF_LOOP_BODY_2_STEREO \
1004 GRAIN_BUF_LOOP_BODY_2_MONO \
1005 out2[j] += outval * pan2;
1007 #define GRAIN_BUF_LOOP_BODY_1_MONO \
1008 phase = sc_gloop(phase, loopMax); \
1009 int32 iphase = (int32)phase; \
1010 float outval = amp * bufData[iphase]; \
1011 out1[j] += outval * pan1;
1013 #define GRAIN_BUF_LOOP_BODY_1_STEREO \
1014 GRAIN_BUF_LOOP_BODY_1_MONO \
1015 out2[j] += outval * pan2;
1018 #define GRAIN_BUF_PLAY_GRAIN(WINDOW) \
1020 if (numOutputs == 1) \
1022 if (grain->interp >= 4) { \
1023 for (int j=0; j<nsmps; j++) { \
1024 GRAIN_BUF_LOOP_BODY_4_MONO \
1025 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1028 } else if (grain->interp >= 2) { \
1029 for (int j=0; j<nsmps; j++) { \
1030 GRAIN_BUF_LOOP_BODY_2_MONO \
1031 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1035 for (int j=0; j<nsmps; j++) { \
1036 GRAIN_BUF_LOOP_BODY_1_MONO \
1037 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1042 if (grain->interp >= 4) { \
1043 for (int j=0; j<nsmps; j++) { \
1044 GRAIN_BUF_LOOP_BODY_4_STEREO \
1045 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1048 } else if (grain->interp >= 2) { \
1049 for (int j=0; j<nsmps; j++) { \
1050 GRAIN_BUF_LOOP_BODY_2_STEREO \
1051 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1055 for (int j=0; j<nsmps; j++) { \
1056 GRAIN_BUF_LOOP_BODY_1_STEREO \
1057 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1065 static inline bool GrainBuf_grain_cleanup(GrainBuf
* unit
, GrainBufG
* grain
)
1067 if (grain
->counter
<= 0)
1069 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
1076 template <bool IsMono
>
1077 static inline void GrainBuf_next_play_active(GrainBuf
*unit
, int inNumSamples
)
1079 const uint32 numOutputs
= IsMono
? 1 : unit
->mNumOutputs
;
1081 World
*world
= unit
->mWorld
;
1083 for (int i
=0; i
< unit
->mNumActive
; ) {
1084 GrainBufG
*grain
= unit
->mGrains
+ i
;
1085 uint32 bufnum
= grain
->bufnum
;
1090 grain
->counter
-= inNumSamples
;
1091 if (!GrainBuf_grain_cleanup(unit
, grain
))
1096 double loopMax
= (double)bufFrames
;
1097 double rate
= grain
->rate
;
1098 double phase
= grain
->phase
;
1101 GET_GRAIN_AMP_PARAMS
1108 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
1110 if (grain
->winType
< 0.)
1111 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
1113 GRAIN_BUF_PLAY_GRAIN(CUSTOM
);
1115 if (GrainBuf_grain_cleanup(unit
, grain
))
1119 grain
->phase
= phase
;
1121 SAVE_GRAIN_AMP_PARAMS
1125 template <bool full_rate
, bool IsMono
>
1126 static inline void GrainBuf_next_start_new(GrainBuf
*unit
, int inNumSamples
, int position
)
1128 World
*world
= unit
->mWorld
;
1130 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
1131 Print("Too many grains!\n");
1135 GrainBufG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
1136 float winType
= grain_in_at
<full_rate
>(unit
, 7, position
);
1138 GET_GRAIN_WIN(winType
)
1139 if (winType
>= 0 && (windowData
== NULL
))
1142 int32 bufnum
= grain_in_at
<full_rate
>(unit
, 2, position
);
1143 grain
->bufnum
= bufnum
;
1147 if ( (bufChannels
!= 1) || (!bufData
) ) {
1148 GrainBuf_grain_cleanup(unit
, grain
);
1152 float bufSampleRate
= buf
->samplerate
;
1153 float bufRateScale
= bufSampleRate
* SAMPLEDUR
;
1154 double loopMax
= (double)bufFrames
;
1156 double counter
= grain_in_at
<full_rate
>(unit
, 1, position
) * SAMPLERATE
;
1157 counter
= sc_max(4., counter
);
1158 grain
->counter
= (int)counter
;
1160 double rate
= grain
->rate
= grain_in_at
<full_rate
>(unit
, 3, position
) * bufRateScale
;
1161 double phase
= grain_in_at
<full_rate
>(unit
, 4, position
) * bufFrames
;
1162 grain
->interp
= (int)grain_in_at
<full_rate
>(unit
, 5, position
);
1163 grain
->winType
= winType
;
1167 const uint32 numOutputs
= IsMono
? 1 : unit
->mNumOutputs
;
1170 float pan
= grain_in_at
<full_rate
>(unit
, 6, position
);
1178 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
1180 if (grain
->winType
< 0.)
1181 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
1183 GRAIN_BUF_PLAY_GRAIN(CUSTOM
);
1185 grain
->phase
= phase
;
1187 SAVE_GRAIN_AMP_PARAMS
1189 GrainBuf_grain_cleanup(unit
, grain
);
1193 template <bool MultiChannel
>
1194 static void GrainBuf_next_a(GrainBuf
*unit
, int inNumSamples
)
1196 ClearUnitOutputs(unit
, inNumSamples
);
1198 GrainBuf_next_play_active
<MultiChannel
>(unit
, inNumSamples
);
1200 float *trig
= IN(0);
1201 for (int i
=0; i
<inNumSamples
; i
++) {
1202 if ((trig
[i
] > 0) && (unit
->curtrig
<=0))
1203 GrainBuf_next_start_new
<true, MultiChannel
>(unit
, inNumSamples
, i
);
1204 unit
->curtrig
= trig
[i
];
1208 template <bool MultiChannel
>
1209 static void GrainBuf_next_k(GrainBuf
* unit
, int inNumSamples
)
1211 ClearUnitOutputs(unit
, inNumSamples
);
1213 GrainBuf_next_play_active
<MultiChannel
>(unit
, inNumSamples
);
1215 float trig
= IN0(0);
1216 if ((trig
> 0) && (unit
->curtrig
<=0))
1217 GrainBuf_next_start_new
<false, MultiChannel
>(unit
, inNumSamples
, 0);
1218 unit
->curtrig
= trig
;
1221 FLATTEN
static void GrainBuf_next_k_1(GrainBuf
* unit
, int inNumSamples
)
1223 GrainBuf_next_k
<true>(unit
, inNumSamples
);
1226 FLATTEN
static void GrainBuf_next_k_2(GrainBuf
* unit
, int inNumSamples
)
1228 GrainBuf_next_k
<false>(unit
, inNumSamples
);
1231 FLATTEN
static void GrainBuf_next_a_1(GrainBuf
* unit
, int inNumSamples
)
1233 GrainBuf_next_a
<true>(unit
, inNumSamples
);
1236 FLATTEN
static void GrainBuf_next_a_2(GrainBuf
* unit
, int inNumSamples
)
1238 GrainBuf_next_a
<false>(unit
, inNumSamples
);
1241 void GrainBuf_Ctor(GrainBuf
*unit
)
1243 unit
->mNumActive
= 0;
1244 unit
->curtrig
= 0.f
;
1246 float maxGrains
= IN0(8);
1247 unit
->mMaxGrains
= (int)maxGrains
;
1248 unit
->mGrains
= (GrainBufG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainBufG
));
1250 if (unit
->mNumOutputs
== 1) {
1251 if (INRATE(0) == calc_FullRate
)
1252 SETCALC(GrainBuf_next_a_1
);
1254 SETCALC(GrainBuf_next_k_1
);
1256 if (INRATE(0) == calc_FullRate
)
1257 SETCALC(GrainBuf_next_a_2
);
1259 SETCALC(GrainBuf_next_k_2
);
1262 (unit
->mCalcFunc
)(unit
, 1);
1265 void GrainBuf_Dtor(GrainBuf
*unit
)
1267 RTFree(unit
->mWorld
, unit
->mGrains
);
1271 #define BUF_GRAIN_LOOP_BODY_4_N \
1272 phase = sc_gloop(phase, loopMax); \
1273 int32 iphase = (int32)phase; \
1274 const float* table1 = bufData + iphase * bufChannels; \
1275 const float* table0 = table1 - bufChannels; \
1276 const float* table2 = table1 + bufChannels; \
1277 const float* table3 = table2 + bufChannels; \
1278 if (iphase == 0) { \
1279 table0 += bufSamples; \
1280 } else if (iphase >= guardFrame) { \
1281 if (iphase == guardFrame) { \
1282 table3 -= bufSamples; \
1284 table2 -= bufSamples; \
1285 table3 -= bufSamples; \
1288 float fracphase = phase - (double)iphase; \
1289 float a = table0[n]; \
1290 float b = table1[n]; \
1291 float c = table2[n]; \
1292 float d = table3[n]; \
1293 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
1294 ZXP(out1) += outval; \
1296 #define BUF_GRAIN_LOOP_BODY_2_N \
1297 phase = sc_gloop(phase, loopMax); \
1298 int32 iphase = (int32)phase; \
1299 const float* table1 = bufData + iphase * bufChannels; \
1300 const float* table2 = table1 + bufChannels; \
1301 if (iphase > guardFrame) { \
1302 table2 -= bufSamples; \
1304 float fracphase = phase - (double)iphase; \
1305 float b = table1[n]; \
1306 float c = table2[n]; \
1307 float outval = amp * (b + fracphase * (c - b)); \
1308 ZXP(out1) += outval; \
1310 // amp needs to be calculated by looking up values in window
1312 #define BUF_GRAIN_LOOP_BODY_1_N \
1313 phase = sc_gloop(phase, loopMax); \
1314 int32 iphase = (int32)phase; \
1315 float outval = amp * bufData[iphase + n]; \
1316 ZXP(out1) += outval; \
1319 #define GET_WARP_WIN_RELAXED(WINTYPE) \
1321 assert(WINTYPE < unit->mWorld->mNumSndBufs); \
1322 window = unit->mWorld->mSndBufs + (int)WINTYPE; \
1323 while (!TRY_ACQUIRE_SNDBUF_SHARED(window)) { \
1324 RELEASE_SNDBUF_SHARED(buf); \
1325 ACQUIRE_SNDBUF_SHARED(buf); \
1327 windowData = window->data; \
1328 if (windowData == NULL) \
1329 RELEASE_SNDBUF_SHARED(window); \
1330 windowSamples = window->samples; \
1331 windowFrames = window->frames; \
1332 windowGuardFrame = windowFrames - 1; \
1335 #define GET_WARP_AMP_PARAMS \
1336 if(grain->winType < 0.){ \
1340 amp = grain->curamp; \
1342 GET_WARP_WIN_RELAXED(grain->winType); \
1343 if (!windowData) break; \
1344 winPos = grain->winPos; \
1345 winInc = grain->winInc; \
1346 amp = grain->curamp; \
1350 void Warp1_next(Warp1
*unit
, int inNumSamples
)
1352 ClearUnitOutputs(unit
, inNumSamples
);
1358 for (uint32 n
=0; n
< numOutputs
; n
++) {
1359 int nextGrain
= unit
->mNextGrain
[n
];
1360 for (int i
=0; i
< unit
->mNumActive
[n
]; ) {
1361 WarpWinGrain
*grain
= unit
->mGrains
[n
] + i
;
1363 double loopMax
= (double)bufFrames
;
1365 double rate
= grain
->rate
;
1366 double phase
= grain
->phase
;
1368 GET_GRAIN_AMP_PARAMS
1369 float *out1
= out
[n
];
1370 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
1371 if (grain
->interp
>= 4) {
1372 for (int j
=0; j
<nsmps
; ++j
) {
1373 BUF_GRAIN_LOOP_BODY_4_N
1377 } else if (grain
->interp
>= 2) {
1378 for (int j
=0; j
<nsmps
; ++j
) {
1379 BUF_GRAIN_LOOP_BODY_2_N
1384 for (int j
=0; j
<nsmps
; ++j
) {
1385 BUF_GRAIN_LOOP_BODY_1_N
1391 grain
->phase
= phase
;
1392 SAVE_GRAIN_AMP_PARAMS
1393 if (grain
->counter
<= 0)
1394 *grain
= unit
->mGrains
[n
][--unit
->mNumActive
[n
]]; // remove grain
1399 for (int i
=0; i
<inNumSamples
; ++i
) {
1401 if (nextGrain
== 0) {
1403 if (unit
->mNumActive
[n
]+1 >= kMaxGrains
) break;
1404 // uint32 bufnum = (uint32)GRAIN_IN_AT(unit, 0, i);
1405 // if (bufnum >= numBufs) break;
1407 float bufSampleRate
= buf
->samplerate
;
1408 float bufRateScale
= bufSampleRate
* SAMPLEDUR
;
1409 double loopMax
= (double)bufFrames
;
1411 WarpWinGrain
*grain
= unit
->mGrains
[n
] + unit
->mNumActive
[n
]++;
1412 // grain->bufnum = bufnum;
1414 float overlaps
= GRAIN_IN_AT(unit
, 5, i
);
1415 float counter
= GRAIN_IN_AT(unit
, 3, i
) * SAMPLERATE
;
1416 double winrandamt
= unit
->mParent
->mRGen
->frand2() * (double)GRAIN_IN_AT(unit
, 6, i
);
1417 counter
= sc_max(4., floor(counter
+ (counter
* winrandamt
)));
1418 grain
->counter
= (int)counter
;
1420 nextGrain
= (int)(counter
/ overlaps
);
1422 unit
->mNextGrain
[n
] = nextGrain
;
1424 float rate
= grain
->rate
= GRAIN_IN_AT(unit
, 2, i
) * bufRateScale
;
1425 float phase
= GRAIN_IN_AT(unit
, 1, i
) * (float)bufFrames
;
1426 grain
->interp
= (int)GRAIN_IN_AT(unit
, 7, i
);
1427 float winType
= grain
->winType
= (int)GRAIN_IN_AT(unit
, 4, i
); // the buffer that holds the grain shape
1430 if (winType
>= unit
->mWorld
->mNumSndBufs
) {
1431 Print("Envelope buffer out of range!\n");
1435 GET_GRAIN_WIN_RELAXED(winType
)
1436 if (windowData
|| (winType
< 0.)) {
1439 float *out1
= out
[n
] + i
;
1441 int nsmps
= sc_min(grain
->counter
, inNumSamples
- i
);
1442 if (grain
->interp
>= 4) {
1443 for (int j
=0; j
<nsmps
; ++j
) {
1444 BUF_GRAIN_LOOP_BODY_4_N
1448 } else if (grain
->interp
>= 2) {
1449 for (int j
=0; j
<nsmps
; ++j
) {
1450 BUF_GRAIN_LOOP_BODY_2_N
1455 for (int j
=0; j
<nsmps
; ++j
) {
1456 BUF_GRAIN_LOOP_BODY_1_N
1462 grain
->phase
= phase
;
1463 SAVE_GRAIN_AMP_PARAMS
1465 if (grain
->counter
<= 0)
1466 *grain
= unit
->mGrains
[n
][--unit
->mNumActive
[n
]]; // remove grain
1471 unit
->mNextGrain
[n
] = nextGrain
;
1475 void Warp1_Ctor(Warp1
*unit
)
1477 SETCALC(Warp1_next
);
1479 for(int i
= 0; i
< 16; i
++){
1480 unit
->mNumActive
[i
] = 0;
1481 unit
->mNextGrain
[i
] = 1;
1484 ClearUnitOutputs(unit
, 1);
1485 unit
->m_fbufnum
= -1e9f
;
1489 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1495 DefineDtorCantAliasUnit(GrainIn
);
1496 DefineDtorCantAliasUnit(GrainSin
);
1497 DefineDtorCantAliasUnit(GrainFM
);
1498 DefineDtorCantAliasUnit(GrainBuf
);
1499 DefineSimpleCantAliasUnit(Warp1
);