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; \
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");
249 assert(wintype
< unit
->mWorld
->mNumSndBufs
);
252 return true; // use default hann window
254 window
= unit
->mWorld
->mSndBufs
+ (int)wintype
;
255 windowData
= window
->data
;
259 windowSamples
= window
->samples
;
260 windowFrames
= window
->frames
;
261 windowGuardFrame
= windowFrames
- 1;
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; \
275 table0 += bufSamples; \
276 } else if (iphase >= guardFrame) { \
277 if (iphase == guardFrame) { \
278 table3 -= bufSamples; \
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; \
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; \
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; \
324 #define BUF_GRAIN_AMP \
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; \
343 table0 += bufSamples; \
344 } else if (iphase >= guardFrame) { \
345 if (iphase == guardFrame) { \
346 table3 -= bufSamples; \
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); \
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)); \
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]; \
384 uint32 numOutputs = unit->mNumOutputs; \
385 if (numOutputs > bufChannels) { \
386 unit->mDone = true; \
387 ClearUnitOutputs(unit, inNumSamples); \
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); \
411 pan1 = grain->pan1 = 1.; \
412 pan2 = grain->pan2 = 0.; \
415 #define GET_GRAIN_INIT_AMP \
416 if(grain->winType < 0.){ \
418 b1 = grain->b1 = 2. * cos(w); \
423 amp = windowData[0]; \
424 winPos = grain->winPos = 0.f; \
425 winInc = grain->winInc = (double)windowSamples / counter; \
428 #define CALC_NEXT_GRAIN_AMP_INTERNAL \
436 #define CALC_NEXT_GRAIN_AMP_CUSTOM \
439 int iWinPos = (int)winPos; \
440 double winFrac = winPos - (double)iWinPos; \
441 const float* winTable1 = windowData + iWinPos; \
442 const float* winTable2 = winTable1 + 1; \
445 if (winPos > windowGuardFrame) \
446 winTable2 -= windowSamples; \
447 amp = lininterp(winFrac, winTable1[0], winTable2[0]); \
452 #define CALC_NEXT_GRAIN_AMP \
453 if(grain->winType < 0.) { \
454 CALC_NEXT_GRAIN_AMP_INTERNAL; \
456 CALC_NEXT_GRAIN_AMP_CUSTOM; \
460 #define GET_GRAIN_AMP_PARAMS \
461 if(grain->winType < 0.){ \
465 amp = grain->curamp; \
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 \
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; \
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; \
503 //////////////////// InGrain ////////////////////
505 inline void GrainIn_next_play_active(GrainIn
* unit
, int inNumSamples
)
507 const uint32 numOutputs
= unit
->mNumOutputs
;
509 for (int i
=0; i
< unit
->mNumActive
; ) {
510 GrainInG
*grain
= unit
->mGrains
+ i
;
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
;
531 SAVE_GRAIN_AMP_PARAMS
533 if (grain
->counter
<= 0)
534 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
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");
548 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
550 bool success
= getGrainWin(unit
, winType
, window
, windowData
, windowSamples
, windowFrames
, windowGuardFrame
);
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
;
563 const uint32 numOutputs
= unit
->mNumOutputs
;
566 float *in1
= in
+ position
;
568 float pan
= grain_in_at
<full_rate
>(unit
, 3, 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
;
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
);
596 GrainIn_next_play_active(unit
, inNumSamples
);
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
);
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
);
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
);
631 SETCALC(GrainIn_next_k
);
633 unit
->mNumActive
= 0;
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
;
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
;
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
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");
697 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
699 bool success
= getGrainWin(unit
, winType
, window
, windowData
, windowSamples
, windowFrames
, windowGuardFrame
);
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
);
708 double counter
= winSize
* SAMPLERATE
;
709 counter
= sc_max(4., counter
);
710 grain
->counter
= (int)counter
;
711 grain
->winType
= winType
;
715 const uint32 numOutputs
= unit
->mNumOutputs
;
717 float *table0
= ft
->mSineWavetable
;
718 float *table1
= table0
+ 1;
721 float pan
= grain_in_at
<full_rate
>(unit
, 3, position
);
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
;
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
);
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
);
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
);
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
);
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.;
793 unit
->mNumActive
= 0;
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
;
809 float *table0
= ft
->mSineWavetable
;
810 float *table1
= table0
+ 1;
812 for (int i
=0; i
< unit
->mNumActive
; ) {
813 GrainFMG
*grain
= unit
->mGrains
+ i
;
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
;
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
;
840 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carbase
+ thismod
)); // needs to be calced in the loop!
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
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");
864 float winType
= grain_in_at
<full_rate
>(unit
, 6, position
);
866 bool success
= getGrainWin(unit
, winType
, window
, windowData
, windowSamples
, windowFrames
, windowGuardFrame
);
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
;
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);
886 const uint32 numOutputs
= unit
->mNumOutputs
;
888 float *table0
= ft
->mSineWavetable
;
889 float *table1
= table0
+ 1;
892 float pan
= GRAIN_IN_AT(unit
, 5, position
);
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
;
909 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carfreq
+ thismod
)); // needs to be calced in the loop!
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
);
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
);
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
);
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
);
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.;
967 unit
->mNumActive
= 0;
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; \
985 table0 += bufSamples; \
986 } else if (iphase >= guardFrame) { \
987 if (iphase == guardFrame) { \
988 table3 -= bufSamples; \
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) \
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; \
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; \
1052 for (int j=0; j<nsmps; j++) { \
1053 GRAIN_BUF_LOOP_BODY_1_MONO \
1054 CALC_NEXT_GRAIN_AMP_##WINDOW; \
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; \
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; \
1072 for (int j=0; j<nsmps; j++) { \
1073 GRAIN_BUF_LOOP_BODY_1_STEREO \
1074 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1082 static inline bool GrainBuf_grain_cleanup(GrainBuf
* unit
, GrainBufG
* grain
)
1084 if (grain
->counter
<= 0)
1086 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
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
;
1106 if (!bufData
|| (bufChannels
!= 1)) {
1107 grain
->counter
-= inNumSamples
;
1108 if (!GrainBuf_grain_cleanup(unit
, grain
))
1113 double loopMax
= (double)bufFrames
;
1114 double rate
= grain
->rate
;
1115 double phase
= grain
->phase
;
1118 GET_GRAIN_AMP_PARAMS
1127 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
1129 if (grain
->winType
< 0.)
1130 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
1132 GRAIN_BUF_PLAY_GRAIN(CUSTOM
);
1134 if (GrainBuf_grain_cleanup(unit
, grain
))
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");
1154 float winType
= grain_in_at
<full_rate
>(unit
, 7, position
);
1156 bool success
= getGrainWin(unit
, winType
, window
, windowData
, windowSamples
, windowFrames
, windowGuardFrame
);
1160 GrainBufG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
1161 int32 bufnum
= grain_in_at
<full_rate
>(unit
, 2, position
);
1162 grain
->bufnum
= bufnum
;
1166 if ( (bufChannels
!= 1) || (!bufData
) ) {
1167 GrainBuf_grain_cleanup(unit
, grain
);
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
);
1186 grain
->interp
= (int)grain_in_at
<full_rate
>(unit
, 5, position
);
1187 grain
->winType
= winType
;
1191 const uint32 numOutputs
= IsMono
? 1 : unit
->mNumOutputs
;
1194 float pan
= grain_in_at
<full_rate
>(unit
, 6, position
);
1202 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
1204 if (grain
->winType
< 0.)
1205 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
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
);
1278 SETCALC(GrainBuf_next_k_1
);
1280 if (INRATE(0) == calc_FullRate
)
1281 SETCALC(GrainBuf_next_a_2
);
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; \
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) \
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; \
1359 #define GET_WARP_AMP_PARAMS \
1360 if(grain->winType < 0.){ \
1364 amp = grain->curamp; \
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
);
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
;
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
1401 } else if (grain
->interp
>= 2) {
1402 for (int j
=0; j
<nsmps
; ++j
) {
1403 BUF_GRAIN_LOOP_BODY_2_N
1408 for (int j
=0; j
<nsmps
; ++j
) {
1409 BUF_GRAIN_LOOP_BODY_1_N
1415 grain
->phase
= phase
;
1416 SAVE_GRAIN_AMP_PARAMS
1417 if (grain
->counter
<= 0)
1418 *grain
= unit
->mGrains
[n
][--unit
->mNumActive
[n
]]; // remove grain
1423 for (int i
=0; i
<inNumSamples
; ++i
) {
1425 if (nextGrain
== 0) {
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
1454 if (winType
>= unit
->mWorld
->mNumSndBufs
) {
1455 Print("Envelope buffer out of range!\n");
1459 GET_GRAIN_WIN_RELAXED(winType
)
1460 if (windowData
|| (winType
< 0.)) {
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
1472 } else if (grain
->interp
>= 2) {
1473 for (int j
=0; j
<nsmps
; ++j
) {
1474 BUF_GRAIN_LOOP_BODY_2_N
1479 for (int j
=0; j
<nsmps
; ++j
) {
1480 BUF_GRAIN_LOOP_BODY_1_N
1486 grain
->phase
= phase
;
1487 SAVE_GRAIN_AMP_PARAMS
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 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1519 DefineDtorCantAliasUnit(GrainIn
);
1520 DefineDtorCantAliasUnit(GrainSin
);
1521 DefineDtorCantAliasUnit(GrainFM
);
1522 DefineDtorCantAliasUnit(GrainBuf
);
1523 DefineSimpleCantAliasUnit(Warp1
);