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 #if defined (__GNUC__) && !defined(__clang__)
33 #define inline_functions __attribute__ ((flatten))
35 #define inline_functions
38 static InterfaceTable
*ft
;
40 const int kMaxGrains
= 64;
42 const int kMaxSynthGrains
= 512;
46 double b1
, y1
, y2
, curamp
, winPos
, winInc
; // envelope
48 float pan1
, pan2
, winType
;
51 struct GrainIn
: public Unit
53 int mNumActive
, m_channels
, mMaxGrains
;
61 double b1
, y1
, y2
, curamp
, winPos
, winInc
; // envelope
63 float pan1
, pan2
, winType
;
64 int32 oscphase
; // the phase of the osc inside this grain
65 int32 freq
; // the freq of the osc inside this grain in phase inc
68 struct GrainSin
: public Unit
70 int mNumActive
, m_channels
, mMaxGrains
;
74 double m_cpstoinc
, m_radtoinc
;
80 int32 coscphase
, moscphase
; // the phase of the osc inside this grain
81 int32 mfreq
; // the freq of the osc inside this grain in phase inc
82 double b1
, y1
, y2
, curamp
, winPos
, winInc
; // envelope
83 float deviation
, carbase
, pan1
, pan2
, winType
;
88 struct GrainFM
: public Unit
90 int mNumActive
, m_channels
, mMaxGrains
;
94 double m_cpstoinc
, m_radtoinc
;
101 double b1
, y1
, y2
, curamp
, winPos
, winInc
;
102 float pan1
, pan2
, winType
;
103 int counter
, chan
, bufnum
, interp
;
106 struct GrainBuf
: public Unit
108 int mNumActive
, m_channels
, mMaxGrains
;
116 double winPos
, winInc
, b1
, y1
, y2
, curamp
; // tells the grain where to look in the winBuf for an amp value
117 int counter
, bufnum
, interp
;
121 struct Warp1
: public Unit
127 WarpWinGrain mGrains
[16][kMaxGrains
];
130 ////////////////////////////////////////////////////////////////////////
135 void GrainIn_Ctor(GrainIn
* unit
);
136 void GrainIn_Dtor(GrainIn
* unit
);
137 void GrainIn_next_a(GrainIn
*unit
, int inNumSamples
);
138 void GrainIn_next_k(GrainIn
*unit
, int inNumSamples
);
140 void GrainSin_Ctor(GrainSin
* unit
);
141 void GrainSin_Dtor(GrainSin
* unit
);
142 void GrainSin_next_a(GrainSin
*unit
, int inNumSamples
);
143 void GrainSin_next_k(GrainSin
*unit
, int inNumSamples
);
145 void GrainFM_Ctor(GrainFM
* unit
);
146 void GrainFM_Dtor(GrainFM
* unit
);
147 void GrainFM_next_a(GrainFM
*unit
, int inNumSamples
);
148 void GrainFM_next_k(GrainFM
*unit
, int inNumSamples
);
150 void GrainBuf_Ctor(GrainBuf
* unit
);
151 void GrainBuf_Dtor(GrainBuf
* unit
);
153 void Warp1_next(Warp1
*unit
, int inNumSamples
);
154 void Warp1_Ctor(Warp1
* unit
);
157 ////////////////////////////////////////////////////////////////////////////////////////////////////////
158 //////////////////////////////// Granular UGens ////////////////////////////////////////////////////////
159 ////////////////////////////////////////////////////////////////////////////////////////////////////////
161 inline float GRAIN_IN_AT(Unit
* unit
, int index
, int offset
)
163 if (INRATE(index
) == calc_FullRate
) return IN(index
)[offset
];
164 if (INRATE(index
) == calc_DemandRate
) return DEMANDINPUT_A(index
, offset
+ 1);
168 template <bool full_rate
>
169 inline float grain_in_at(Unit
* unit
, int index
, int offset
)
172 return GRAIN_IN_AT(unit
, index
, offset
);
174 if (INRATE(index
) == calc_DemandRate
)
175 return DEMANDINPUT_A(index
, offset
+ 1);
180 inline double sc_gloop(double in
, double hi
)
182 // avoid the divide if possible
185 if (in
< hi
) return in
;
186 } else if (in
< 0.) {
188 if (in
>= 0.) return in
;
191 return in
- hi
* floor(in
/hi
);
196 if (bufnum >= world->mNumSndBufs) { \
197 int localBufNum = bufnum - world->mNumSndBufs; \
198 Graph *parent = unit->mParent; \
199 if(localBufNum <= parent->localBufNum) { \
200 buf = parent->mLocalSndBufs + localBufNum; \
203 buf = world->mSndBufs + bufnum; \
206 if (bufnum < 0) { bufnum = 0; } \
207 buf = world->mSndBufs + bufnum; \
209 LOCK_SNDBUF_SHARED(buf); \
210 const float *bufData __attribute__((__unused__)) = buf->data; \
211 uint32 bufChannels __attribute__((__unused__)) = buf->channels; \
212 uint32 bufSamples __attribute__((__unused__)) = buf->samples; \
213 uint32 bufFrames = buf->frames; \
214 int guardFrame __attribute__((__unused__)) = bufFrames - 2;
216 #define DECLARE_WINDOW \
217 double winPos, winInc, w, b1, y1, y2, y0; \
219 winPos = winInc = w = b1 = y1 = y2 = y0 = amp = 0.; \
221 const float *windowData __attribute__((__unused__)) = 0;\
222 uint32 windowSamples __attribute__((__unused__)) = 0; \
223 uint32 windowFrames __attribute__((__unused__)) = 0; \
224 int windowGuardFrame = 0;
229 unit->mDone = true; \
230 ClearUnitOutputs(unit, inNumSamples); \
234 #define GET_GRAIN_WIN_RELAXED(WINTYPE) \
236 assert(WINTYPE < unit->mWorld->mNumSndBufs); \
237 window = unit->mWorld->mSndBufs + (int)WINTYPE; \
238 windowData = window->data; \
239 windowSamples = window->samples; \
240 windowFrames = window->frames; \
241 windowGuardFrame = windowFrames - 1; \
244 #define GET_GRAIN_WIN(WINTYPE) \
246 if (WINTYPE >= unit->mWorld->mNumSndBufs) { \
247 Print("Envelope buffer out of range!\n"); \
250 GET_GRAIN_WIN_RELAXED(WINTYPE) \
253 #define GRAIN_LOOP_BODY_4 \
254 float amp = y1 * y1; \
255 phase = sc_gloop(phase, loopMax); \
256 int32 iphase = (int32)phase; \
257 float* table1 = bufData + iphase; \
258 float* table0 = table1 - 1; \
259 float* table2 = table1 + 1; \
260 float* table3 = table1 + 2; \
262 table0 += bufSamples; \
263 } else if (iphase >= guardFrame) { \
264 if (iphase == guardFrame) { \
265 table3 -= bufSamples; \
267 table2 -= bufSamples; \
268 table3 -= bufSamples; \
271 float fracphase = phase - (double)iphase; \
272 float a = table0[0]; \
273 float b = table1[0]; \
274 float c = table2[0]; \
275 float d = table3[0]; \
276 float outval = amp * cubicinterp(fracphase, a, b, c, d) \
277 ZXP(out1) += outval; \
278 double y0 = b1 * y1 - y2; \
282 #define GRAIN_LOOP_BODY_2 \
283 float amp = y1 * y1; \
284 phase = sc_gloop(phase, loopMax); \
285 int32 iphase = (int32)phase; \
286 float* table1 = bufData + iphase; \
287 float* table2 = table1 + 1; \
288 if (iphase > guardFrame) { \
289 table2 -= bufSamples; \
291 double fracphase = phase - (double)iphase; \
292 float b = table1[0]; \
293 float c = table2[0]; \
294 float outval = amp * (b + fracphase * (c - b)); \
295 ZXP(out1) += outval; \
296 double y0 = b1 * y1 - y2; \
301 #define GRAIN_LOOP_BODY_1 \
302 float amp = y1 * y1; \
303 phase = sc_gloop(phase, loopMax); \
304 int32 iphase = (int32)phase; \
305 float outval = amp * bufData[iphase]; \
306 ZXP(out1) += outval; \
307 double y0 = b1 * y1 - y2; \
311 #define BUF_GRAIN_AMP \
313 int iWinPos = (int)winPos; \
314 double winFrac = winPos - (double)iWinPos; \
315 float* winTable1 = windowData + iWinPos; \
316 float* winTable2 = winTable1 + 1; \
317 if (winPos > windowGuardFrame) { \
318 winTable2 -= windowSamples; \
320 amp = lininterp(winFrac, winTable1[0], winTable2[0]);
322 #define BUF_GRAIN_LOOP_BODY_4 \
323 phase = sc_gloop(phase, loopMax); \
324 int32 iphase = (int32)phase; \
325 float* table1 = bufData + iphase; \
326 float* table0 = table1 - 1; \
327 float* table2 = table1 + 1; \
328 float* table3 = table1 + 2; \
330 table0 += bufSamples; \
331 } else if (iphase >= guardFrame) { \
332 if (iphase == guardFrame) { \
333 table3 -= bufSamples; \
335 table2 -= bufSamples; \
336 table3 -= bufSamples; \
339 float fracphase = phase - (double)iphase; \
340 float a = table0[0]; \
341 float b = table1[0]; \
342 float c = table2[0]; \
343 float d = table3[0]; \
344 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
347 #define BUF_GRAIN_LOOP_BODY_2 \
348 phase = sc_gloop(phase, loopMax); \
349 int32 iphase = (int32)phase; \
350 float* table1 = bufData + iphase; \
351 float* table2 = table1 + 1; \
352 if (iphase > guardFrame) { \
353 table2 -= bufSamples; \
355 float fracphase = phase - (double)iphase; \
356 float b = table1[0]; \
357 float c = table2[0]; \
358 float outval = amp * (b + fracphase * (c - b)); \
361 // amp needs to be calculated by looking up values in window
363 #define BUF_GRAIN_LOOP_BODY_1 \
364 phase = sc_gloop(phase, loopMax); \
365 int32 iphase = (int32)phase; \
366 float outval = amp * bufData[iphase]; \
371 uint32 numOutputs = unit->mNumOutputs; \
372 if (numOutputs > bufChannels) { \
373 unit->mDone = true; \
374 ClearUnitOutputs(unit, inNumSamples); \
378 for (uint32 i=0; i<numOutputs; ++i) out[i] = ZOUT(i);
381 #define CALC_GRAIN_PAN \
382 float panangle, pan1, pan2; \
383 float *out1, *out2; \
384 if (numOutputs > 1) { \
385 if (numOutputs == 2) pan = pan * 0.5f; \
386 pan = sc_wrap(pan * 0.5f, 0.f, 1.f); \
387 float cpan = numOutputs * pan + 0.5f; \
388 float ipan = floor(cpan); \
389 float panfrac = cpan - ipan; \
390 panangle = panfrac * pi2_f; \
391 grain->chan = (int)ipan; \
392 if (grain->chan >= (int)numOutputs) \
393 grain->chan -= numOutputs; \
394 pan1 = grain->pan1 = cos(panangle); \
395 pan2 = grain->pan2 = sin(panangle); \
398 pan1 = grain->pan1 = 1.; \
399 pan2 = grain->pan2 = 0.; \
402 #define GET_GRAIN_INIT_AMP \
403 if(grain->winType < 0.){ \
405 b1 = grain->b1 = 2. * cos(w); \
410 amp = windowData[0]; \
411 winPos = grain->winPos = 0.f; \
412 winInc = grain->winInc = (double)windowSamples / counter; \
415 #define CALC_NEXT_GRAIN_AMP_INTERNAL \
423 #define CALC_NEXT_GRAIN_AMP_CUSTOM \
426 int iWinPos = (int)winPos; \
427 double winFrac = winPos - (double)iWinPos; \
428 const float* winTable1 = windowData + iWinPos; \
429 const float* winTable2 = winTable1 + 1; \
432 if (winPos > windowGuardFrame) \
433 winTable2 -= windowSamples; \
434 amp = lininterp(winFrac, winTable1[0], winTable2[0]); \
439 #define CALC_NEXT_GRAIN_AMP \
440 if(grain->winType < 0.) { \
441 CALC_NEXT_GRAIN_AMP_INTERNAL; \
443 CALC_NEXT_GRAIN_AMP_CUSTOM; \
447 #define GET_GRAIN_AMP_PARAMS \
448 if(grain->winType < 0.){ \
452 amp = grain->curamp; \
454 GET_GRAIN_WIN_RELAXED(grain->winType); \
455 if (!windowData) break; \
456 winPos = grain->winPos; \
457 winInc = grain->winInc; \
458 amp = grain->curamp; \
461 #define SAVE_GRAIN_AMP_PARAMS \
464 grain->winPos = winPos; \
465 grain->winInc = winInc; \
466 grain->curamp = amp; \
467 grain->counter -= nsmps;
469 #define WRAP_CHAN(offset) \
470 out1 = OUT(grain->chan) + offset; \
471 if(numOutputs > 1) { \
472 if((grain->chan + 1) >= (int)numOutputs) \
473 out2 = OUT(0) + offset; \
475 out2 = OUT(grain->chan + 1) + offset; \
478 #define GET_PAN_PARAMS \
479 float pan1 = grain->pan1; \
480 uint32 chan1 = grain->chan; \
481 float *out1 = OUT(chan1); \
482 if(numOutputs > 1){ \
483 pan2 = grain->pan2; \
484 uint32 chan2 = chan1 + 1; \
485 if (chan2 >= numOutputs) chan2 = 0; \
490 //////////////////// InGrain ////////////////////
492 inline void GrainIn_next_play_active(GrainIn
* unit
, int inNumSamples
)
494 const uint32 numOutputs
= unit
->mNumOutputs
;
496 for (int i
=0; i
< unit
->mNumActive
; ) {
497 GrainInG
*grain
= unit
->mGrains
+ i
;
507 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
508 for (int j
=0; j
<nsmps
; ++j
) {
509 float outval
= amp
* in
[j
];
510 // begin change / add //
511 out1
[j
] += outval
* pan1
;
512 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
518 SAVE_GRAIN_AMP_PARAMS
520 if (grain
->counter
<= 0)
521 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
527 template <bool full_rate
>
528 inline void GrainIn_next_start_new(GrainIn
* unit
, int inNumSamples
, int position
)
530 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
531 Print("Too many grains!\n");
535 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
537 GET_GRAIN_WIN(winType
)
538 if (winType
>= 0 && (windowData
== NULL
))
541 GrainInG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
542 float winSize
= grain_in_at
<full_rate
>(unit
, 1, position
);
543 double counter
= winSize
* SAMPLERATE
;
544 counter
= sc_max(4., counter
);
545 grain
->counter
= (int)counter
;
546 grain
->winType
= winType
;
550 const uint32 numOutputs
= unit
->mNumOutputs
;
553 float *in1
= in
+ position
;
555 float pan
= grain_in_at
<full_rate
>(unit
, 3, position
);
561 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
562 for (int j
=0; j
<nsmps
; ++j
) {
563 float outval
= amp
* in1
[j
];
564 // begin add / change
565 out1
[j
] += outval
* pan1
;
566 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
571 SAVE_GRAIN_AMP_PARAMS
573 if (grain
->counter
<= 0)
574 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
577 void GrainIn_next_a(GrainIn
*unit
, int inNumSamples
)
579 ClearUnitOutputs(unit
, inNumSamples
);
583 GrainIn_next_play_active(unit
, inNumSamples
);
586 for (int i
=0; i
<inNumSamples
; ++i
) {
587 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
588 GrainIn_next_start_new
<true>(unit
, inNumSamples
, i
);
589 unit
->curtrig
= trig
[i
];
593 void GrainIn_next_k(GrainIn
*unit
, int inNumSamples
)
595 ClearUnitOutputs(unit
, inNumSamples
);
597 unit
->mFirst
= false;
598 float maxGrains
= IN0(5);
599 unit
->mMaxGrains
= (int)maxGrains
;
600 unit
->mGrains
= (GrainInG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainInG
));
603 GrainIn_next_play_active(unit
, inNumSamples
);
607 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
608 GrainIn_next_start_new
<false>(unit
, inNumSamples
, 0);
609 unit
->curtrig
= trig
;
613 void GrainIn_Ctor(GrainIn
*unit
)
615 if (INRATE(0) == calc_FullRate
)
616 SETCALC(GrainIn_next_a
);
618 SETCALC(GrainIn_next_k
);
620 unit
->mNumActive
= 0;
622 GrainIn_next_k(unit
, 1);
625 void GrainIn_Dtor(GrainIn
*unit
)
627 RTFree(unit
->mWorld
, unit
->mGrains
);
630 inline void GrainSin_next_play_active(GrainSin
* unit
, int inNumSamples
)
632 const unsigned int numOutputs
= unit
->mNumOutputs
;
634 float *table0
= ft
->mSineWavetable
;
635 float *table1
= table0
+ 1;
637 for (int i
=0; i
< unit
->mNumActive
; ) {
638 GrainSinG
*grain
= unit
->mGrains
+ i
;
651 int32 thisfreq
= grain
->freq
;
652 int32 oscphase
= grain
->oscphase
;
654 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
655 for (int j
=0; j
<nsmps
; ++j
) {
656 float outval
= amp
* lookupi1(table0
, table1
, oscphase
, unit
->m_lomask
);
657 // begin change / add //
658 out1
[j
] += outval
* pan1
;
659 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
663 oscphase
+= thisfreq
;
666 SAVE_GRAIN_AMP_PARAMS
668 grain
->oscphase
= oscphase
;
669 if (grain
->counter
<= 0)
670 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
676 template <bool full_rate
>
677 inline void GrainSin_next_start_new(GrainSin
* unit
, int inNumSamples
, int position
)
679 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
680 Print("Too many grains!\n");
684 float winType
= grain_in_at
<full_rate
>(unit
, 4, position
);
686 GET_GRAIN_WIN(winType
)
687 if (winType
>= 0 && (windowData
== NULL
))
690 GrainSinG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
691 float freq
= grain_in_at
<full_rate
>(unit
, 2, position
);
692 float winSize
= grain_in_at
<full_rate
>(unit
, 1, position
);
693 int32 thisfreq
= grain
->freq
= (int32
)(unit
->m_cpstoinc
* freq
);
695 double counter
= winSize
* SAMPLERATE
;
696 counter
= sc_max(4., counter
);
697 grain
->counter
= (int)counter
;
698 grain
->winType
= winType
;
702 const uint32 numOutputs
= unit
->mNumOutputs
;
704 float *table0
= ft
->mSineWavetable
;
705 float *table1
= table0
+ 1;
708 float pan
= grain_in_at
<full_rate
>(unit
, 3, position
);
716 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
717 for (int j
=0; j
<nsmps
; ++j
) {
718 float outval
= amp
* lookupi1(table0
, table1
, oscphase
, unit
->m_lomask
);
719 // begin add / change
720 out1
[j
] += outval
* pan1
;
721 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
725 oscphase
+= thisfreq
;
727 grain
->oscphase
= oscphase
;
729 SAVE_GRAIN_AMP_PARAMS
731 if (grain
->counter
<= 0)
732 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
735 void GrainSin_next_a(GrainSin
*unit
, int inNumSamples
)
737 ClearUnitOutputs(unit
, inNumSamples
);
739 GrainSin_next_play_active(unit
, inNumSamples
);
742 for (int i
=0; i
<inNumSamples
; ++i
) {
743 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
744 GrainSin_next_start_new
<true>(unit
, inNumSamples
, i
);
745 unit
->curtrig
= trig
[i
];
749 void GrainSin_next_k(GrainSin
*unit
, int inNumSamples
)
751 ClearUnitOutputs(unit
, inNumSamples
);
753 unit
->mFirst
= false;
754 float maxGrains
= IN0(5);
755 unit
->mMaxGrains
= (int)maxGrains
;
756 unit
->mGrains
= (GrainSinG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainSinG
));
759 GrainSin_next_play_active(unit
, inNumSamples
);
764 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
765 GrainSin_next_start_new
<false>(unit
, inNumSamples
, 0);
766 unit
->curtrig
= trig
;
769 void GrainSin_Ctor(GrainSin
*unit
)
771 if (INRATE(0) == calc_FullRate
)
772 SETCALC(GrainSin_next_a
);
774 SETCALC(GrainSin_next_k
);
775 int tableSizeSin
= ft
->mSineSize
;
776 unit
->m_lomask
= (tableSizeSin
- 1) << 3;
777 unit
->m_radtoinc
= tableSizeSin
* (rtwopi
* 65536.);
778 unit
->m_cpstoinc
= tableSizeSin
* SAMPLEDUR
* 65536.;
780 unit
->mNumActive
= 0;
782 GrainSin_next_k(unit
, 1);
785 void GrainSin_Dtor(GrainSin
*unit
)
787 RTFree(unit
->mWorld
, unit
->mGrains
);
791 inline void GrainFM_next_play_active(GrainFM
*unit
, int inNumSamples
)
793 const uint32 numOutputs
= unit
->mNumOutputs
;
796 float *table0
= ft
->mSineWavetable
;
797 float *table1
= table0
+ 1;
799 for (int i
=0; i
< unit
->mNumActive
; ) {
800 GrainFMG
*grain
= unit
->mGrains
+ i
;
804 int32 mfreq
= grain
->mfreq
;
805 int32 moscphase
= grain
->moscphase
;
806 int32 coscphase
= grain
->coscphase
;
807 float deviation
= grain
->deviation
;
808 float carbase
= grain
->carbase
;
817 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
818 for (int j
=0; j
<nsmps
; ++j
) {
819 float thismod
= lookupi1(table0
, table1
, moscphase
, unit
->m_lomask
) * deviation
;
820 float outval
= amp
* lookupi1(table0
, table1
, coscphase
, unit
->m_lomask
);
821 // begin change / add //
822 out1
[j
] += outval
* pan1
;
823 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
827 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carbase
+ thismod
)); // needs to be calced in the loop!
830 } // need to save float carbase, int32 mfreq, float deviation
831 grain
->coscphase
= coscphase
;
832 grain
->moscphase
= moscphase
;
834 SAVE_GRAIN_AMP_PARAMS
836 if (grain
->counter
<= 0)
837 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
843 template <bool full_rate
>
844 inline void GrainFM_next_start_new(GrainFM
* unit
, int inNumSamples
, int position
)
846 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
847 Print("Too many grains!\n");
851 float winType
= grain_in_at
<full_rate
>(unit
, 6, position
);
853 GET_GRAIN_WIN(winType
)
854 if (winType
>= 0 && (windowData
== NULL
))
857 GrainFMG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
858 float winSize
= GRAIN_IN_AT(unit
, 1, position
);
859 float carfreq
= GRAIN_IN_AT(unit
, 2, position
);
860 float modfreq
= GRAIN_IN_AT(unit
, 3, position
);
861 float index
= GRAIN_IN_AT(unit
, 4, position
);
862 float deviation
= grain
->deviation
= index
* modfreq
;
863 int32 mfreq
= grain
->mfreq
= (int32
)(unit
->m_cpstoinc
* modfreq
);
864 grain
->carbase
= carfreq
;
867 double counter
= winSize
* SAMPLERATE
;
868 counter
= sc_max(4., counter
);
869 grain
->counter
= (int)counter
;
870 grain
->winType
= winType
; //GRAIN_IN_AT(unit, 6, i);
873 const uint32 numOutputs
= unit
->mNumOutputs
;
875 float *table0
= ft
->mSineWavetable
;
876 float *table1
= table0
+ 1;
879 float pan
= GRAIN_IN_AT(unit
, 5, position
);
886 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
887 for (int j
=0; j
<nsmps
; ++j
) {
888 float thismod
= lookupi1(table0
, table1
, moscphase
, unit
->m_lomask
) * deviation
;
889 float outval
= amp
* lookupi1(table0
, table1
, coscphase
, unit
->m_lomask
);
890 // begin add / change
891 out1
[j
] += outval
* pan1
;
892 if(numOutputs
> 1) out2
[j
] += outval
* pan2
;
896 int32 cfreq
= (int32
)(unit
->m_cpstoinc
* (carfreq
+ thismod
)); // needs to be calced in the loop!
899 } // need to save float carbase, int32 mfreq, float deviation
900 grain
->coscphase
= coscphase
;
901 grain
->moscphase
= moscphase
;
903 SAVE_GRAIN_AMP_PARAMS
905 if (grain
->counter
<= 0)
906 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
909 void GrainFM_next_a(GrainFM
*unit
, int inNumSamples
)
911 ClearUnitOutputs(unit
, inNumSamples
);
913 GrainFM_next_play_active(unit
, inNumSamples
);
916 for (int i
=0; i
<inNumSamples
; ++i
) {
917 if ((unit
->curtrig
<= 0) && (trig
[i
] > 0.0))
918 GrainFM_next_start_new
<true>(unit
, inNumSamples
, i
);
919 unit
->curtrig
= trig
[i
];
923 void GrainFM_next_k(GrainFM
*unit
, int inNumSamples
)
925 ClearUnitOutputs(unit
, inNumSamples
);
928 unit
->mFirst
= false;
929 float maxGrains
= IN0(7);
930 unit
->mMaxGrains
= (int)maxGrains
;
931 unit
->mGrains
= (GrainFMG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainFMG
));
934 GrainFM_next_play_active(unit
, inNumSamples
);
937 if ((unit
->curtrig
<= 0) && (trig
> 0.0))
938 GrainFM_next_start_new
<false>(unit
, inNumSamples
, 0);
940 unit
->curtrig
= trig
;
943 void GrainFM_Ctor(GrainFM
*unit
)
945 if (INRATE(0) == calc_FullRate
)
946 SETCALC(GrainFM_next_a
);
948 SETCALC(GrainFM_next_k
);
949 int tableSizeSin
= ft
->mSineSize
;
950 unit
->m_lomask
= (tableSizeSin
- 1) << 3;
951 unit
->m_radtoinc
= tableSizeSin
* (rtwopi
* 65536.);
952 unit
->m_cpstoinc
= tableSizeSin
* SAMPLEDUR
* 65536.;
954 unit
->mNumActive
= 0;
956 GrainFM_next_k(unit
, 1);
959 void GrainFM_Dtor(GrainFM
*unit
)
961 RTFree(unit
->mWorld
, unit
->mGrains
);
964 #define GRAIN_BUF_LOOP_BODY_4_MONO \
965 phase = sc_gloop(phase, loopMax); \
966 int32 iphase = (int32)phase; \
967 const float* table1 = bufData + iphase; \
968 const float* table0 = table1 - 1; \
969 const float* table2 = table1 + 1; \
970 const float* table3 = table1 + 2; \
972 table0 += bufSamples; \
973 } else if (iphase >= guardFrame) { \
974 if (iphase == guardFrame) { \
975 table3 -= bufSamples; \
977 table2 -= bufSamples; \
978 table3 -= bufSamples; \
981 float fracphase = phase - (double)iphase; \
982 float a = table0[0]; \
983 float b = table1[0]; \
984 float c = table2[0]; \
985 float d = table3[0]; \
986 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
987 out1[j] += outval * pan1; \
989 #define GRAIN_BUF_LOOP_BODY_4_STEREO \
990 GRAIN_BUF_LOOP_BODY_4_MONO \
991 out2[j] += outval * pan2;
993 #define GRAIN_BUF_LOOP_BODY_2_MONO \
994 phase = sc_gloop(phase, loopMax); \
995 int32 iphase = (int32)phase; \
996 const float* table1 = bufData + iphase; \
997 const float* table2 = table1 + 1; \
998 if (iphase > guardFrame) { \
999 table2 -= bufSamples; \
1001 float fracphase = phase - (double)iphase; \
1002 float b = table1[0]; \
1003 float c = table2[0]; \
1004 float outval = amp * (b + fracphase * (c - b)); \
1005 out1[j] += outval * pan1; \
1007 #define GRAIN_BUF_LOOP_BODY_2_STEREO \
1008 GRAIN_BUF_LOOP_BODY_2_MONO \
1009 out2[j] += outval * pan2;
1011 #define GRAIN_BUF_LOOP_BODY_1_MONO \
1012 phase = sc_gloop(phase, loopMax); \
1013 int32 iphase = (int32)phase; \
1014 float outval = amp * bufData[iphase]; \
1015 out1[j] += outval * pan1;
1017 #define GRAIN_BUF_LOOP_BODY_1_STEREO \
1018 GRAIN_BUF_LOOP_BODY_1_MONO \
1019 out2[j] += outval * pan2;
1022 #define GRAIN_BUF_PLAY_GRAIN(WINDOW) \
1024 if (numOutputs == 1) \
1026 if (grain->interp >= 4) { \
1027 for (int j=0; j<nsmps; j++) { \
1028 GRAIN_BUF_LOOP_BODY_4_MONO \
1029 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1032 } else if (grain->interp >= 2) { \
1033 for (int j=0; j<nsmps; j++) { \
1034 GRAIN_BUF_LOOP_BODY_2_MONO \
1035 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1039 for (int j=0; j<nsmps; j++) { \
1040 GRAIN_BUF_LOOP_BODY_1_MONO \
1041 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1046 if (grain->interp >= 4) { \
1047 for (int j=0; j<nsmps; j++) { \
1048 GRAIN_BUF_LOOP_BODY_4_STEREO \
1049 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1052 } else if (grain->interp >= 2) { \
1053 for (int j=0; j<nsmps; j++) { \
1054 GRAIN_BUF_LOOP_BODY_2_STEREO \
1055 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1059 for (int j=0; j<nsmps; j++) { \
1060 GRAIN_BUF_LOOP_BODY_1_STEREO \
1061 CALC_NEXT_GRAIN_AMP_##WINDOW; \
1069 static inline bool GrainBuf_grain_cleanup(GrainBuf
* unit
, GrainBufG
* grain
)
1071 if (grain
->counter
<= 0)
1073 *grain
= unit
->mGrains
[--unit
->mNumActive
]; // remove grain
1080 template <bool IsMono
>
1081 static inline void GrainBuf_next_play_active(GrainBuf
*unit
, int inNumSamples
)
1083 const uint32 numOutputs
= IsMono
? 1 : unit
->mNumOutputs
;
1085 World
*world
= unit
->mWorld
;
1087 for (int i
=0; i
< unit
->mNumActive
; ) {
1088 GrainBufG
*grain
= unit
->mGrains
+ i
;
1089 uint32 bufnum
= grain
->bufnum
;
1094 grain
->counter
-= inNumSamples
;
1095 if (!GrainBuf_grain_cleanup(unit
, grain
))
1100 double loopMax
= (double)bufFrames
;
1101 double rate
= grain
->rate
;
1102 double phase
= grain
->phase
;
1105 GET_GRAIN_AMP_PARAMS
1112 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
1114 if (grain
->winType
< 0.)
1115 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
1117 GRAIN_BUF_PLAY_GRAIN(CUSTOM
);
1119 if (GrainBuf_grain_cleanup(unit
, grain
))
1123 grain
->phase
= phase
;
1125 SAVE_GRAIN_AMP_PARAMS
1129 template <bool full_rate
, bool IsMono
>
1130 static inline void GrainBuf_next_start_new(GrainBuf
*unit
, int inNumSamples
, int position
)
1132 World
*world
= unit
->mWorld
;
1134 if (unit
->mNumActive
+1 >= unit
->mMaxGrains
) {
1135 Print("Too many grains!\n");
1139 GrainBufG
*grain
= unit
->mGrains
+ unit
->mNumActive
++;
1140 float winType
= grain_in_at
<full_rate
>(unit
, 7, position
);
1142 GET_GRAIN_WIN(winType
)
1143 if (winType
>= 0 && (windowData
== NULL
))
1146 int32 bufnum
= grain_in_at
<full_rate
>(unit
, 2, position
);
1147 grain
->bufnum
= bufnum
;
1151 if ( (bufChannels
!= 1) || (!bufData
) ) {
1152 GrainBuf_grain_cleanup(unit
, grain
);
1156 float bufSampleRate
= buf
->samplerate
;
1157 float bufRateScale
= bufSampleRate
* SAMPLEDUR
;
1158 double loopMax
= (double)bufFrames
;
1160 double counter
= grain_in_at
<full_rate
>(unit
, 1, position
) * SAMPLERATE
;
1161 counter
= sc_max(4., counter
);
1162 grain
->counter
= (int)counter
;
1164 double rate
= grain
->rate
= grain_in_at
<full_rate
>(unit
, 3, position
) * bufRateScale
;
1165 double phase
= grain_in_at
<full_rate
>(unit
, 4, position
) * bufFrames
;
1166 grain
->interp
= (int)grain_in_at
<full_rate
>(unit
, 5, position
);
1167 grain
->winType
= winType
;
1171 const uint32 numOutputs
= IsMono
? 1 : unit
->mNumOutputs
;
1174 float pan
= grain_in_at
<full_rate
>(unit
, 6, position
);
1182 int nsmps
= sc_min(grain
->counter
, inNumSamples
- position
);
1184 if (grain
->winType
< 0.)
1185 GRAIN_BUF_PLAY_GRAIN(INTERNAL
);
1187 GRAIN_BUF_PLAY_GRAIN(CUSTOM
);
1189 grain
->phase
= phase
;
1191 SAVE_GRAIN_AMP_PARAMS
1193 GrainBuf_grain_cleanup(unit
, grain
);
1197 template <bool MultiChannel
>
1198 static void GrainBuf_next_a(GrainBuf
*unit
, int inNumSamples
)
1200 ClearUnitOutputs(unit
, inNumSamples
);
1202 GrainBuf_next_play_active
<MultiChannel
>(unit
, inNumSamples
);
1204 float *trig
= IN(0);
1205 for (int i
=0; i
<inNumSamples
; i
++) {
1206 if ((trig
[i
] > 0) && (unit
->curtrig
<=0))
1207 GrainBuf_next_start_new
<true, MultiChannel
>(unit
, inNumSamples
, i
);
1208 unit
->curtrig
= trig
[i
];
1212 template <bool MultiChannel
>
1213 static void GrainBuf_next_k(GrainBuf
* unit
, int inNumSamples
)
1215 ClearUnitOutputs(unit
, inNumSamples
);
1217 GrainBuf_next_play_active
<MultiChannel
>(unit
, inNumSamples
);
1219 float trig
= IN0(0);
1220 if ((trig
> 0) && (unit
->curtrig
<=0))
1221 GrainBuf_next_start_new
<false, MultiChannel
>(unit
, inNumSamples
, 0);
1222 unit
->curtrig
= trig
;
1225 inline_functions
static void GrainBuf_next_k_1(GrainBuf
* unit
, int inNumSamples
)
1227 GrainBuf_next_k
<true>(unit
, inNumSamples
);
1230 inline_functions
static void GrainBuf_next_k_2(GrainBuf
* unit
, int inNumSamples
)
1232 GrainBuf_next_k
<false>(unit
, inNumSamples
);
1235 inline_functions
static void GrainBuf_next_a_1(GrainBuf
* unit
, int inNumSamples
)
1237 GrainBuf_next_a
<true>(unit
, inNumSamples
);
1240 inline_functions
static void GrainBuf_next_a_2(GrainBuf
* unit
, int inNumSamples
)
1242 GrainBuf_next_a
<false>(unit
, inNumSamples
);
1245 void GrainBuf_Ctor(GrainBuf
*unit
)
1247 unit
->mNumActive
= 0;
1248 unit
->curtrig
= 0.f
;
1250 float maxGrains
= IN0(8);
1251 unit
->mMaxGrains
= (int)maxGrains
;
1252 unit
->mGrains
= (GrainBufG
*)RTAlloc(unit
->mWorld
, unit
->mMaxGrains
* sizeof(GrainBufG
));
1254 if (unit
->mNumOutputs
== 1) {
1255 if (INRATE(0) == calc_FullRate
)
1256 SETCALC(GrainBuf_next_a_1
);
1258 SETCALC(GrainBuf_next_k_1
);
1260 if (INRATE(0) == calc_FullRate
)
1261 SETCALC(GrainBuf_next_a_2
);
1263 SETCALC(GrainBuf_next_k_2
);
1266 (unit
->mCalcFunc
)(unit
, 1);
1269 void GrainBuf_Dtor(GrainBuf
*unit
)
1271 RTFree(unit
->mWorld
, unit
->mGrains
);
1275 #define BUF_GRAIN_LOOP_BODY_4_N \
1276 phase = sc_gloop(phase, loopMax); \
1277 int32 iphase = (int32)phase; \
1278 const float* table1 = bufData + iphase * bufChannels; \
1279 const float* table0 = table1 - bufChannels; \
1280 const float* table2 = table1 + bufChannels; \
1281 const float* table3 = table2 + bufChannels; \
1282 if (iphase == 0) { \
1283 table0 += bufSamples; \
1284 } else if (iphase >= guardFrame) { \
1285 if (iphase == guardFrame) { \
1286 table3 -= bufSamples; \
1288 table2 -= bufSamples; \
1289 table3 -= bufSamples; \
1292 float fracphase = phase - (double)iphase; \
1293 float a = table0[n]; \
1294 float b = table1[n]; \
1295 float c = table2[n]; \
1296 float d = table3[n]; \
1297 float outval = amp * cubicinterp(fracphase, a, b, c, d); \
1298 ZXP(out1) += outval; \
1300 #define BUF_GRAIN_LOOP_BODY_2_N \
1301 phase = sc_gloop(phase, loopMax); \
1302 int32 iphase = (int32)phase; \
1303 const float* table1 = bufData + iphase * bufChannels; \
1304 const float* table2 = table1 + bufChannels; \
1305 if (iphase > guardFrame) { \
1306 table2 -= bufSamples; \
1308 float fracphase = phase - (double)iphase; \
1309 float b = table1[n]; \
1310 float c = table2[n]; \
1311 float outval = amp * (b + fracphase * (c - b)); \
1312 ZXP(out1) += outval; \
1314 // amp needs to be calculated by looking up values in window
1316 #define BUF_GRAIN_LOOP_BODY_1_N \
1317 phase = sc_gloop(phase, loopMax); \
1318 int32 iphase = (int32)phase; \
1319 float outval = amp * bufData[iphase + n]; \
1320 ZXP(out1) += outval; \
1323 #define GET_WARP_WIN_RELAXED(WINTYPE) \
1325 assert(WINTYPE < unit->mWorld->mNumSndBufs); \
1326 window = unit->mWorld->mSndBufs + (int)WINTYPE; \
1327 while (!TRY_ACQUIRE_SNDBUF_SHARED(window)) { \
1328 RELEASE_SNDBUF_SHARED(buf); \
1329 ACQUIRE_SNDBUF_SHARED(buf); \
1331 windowData = window->data; \
1332 if (windowData == NULL) \
1333 RELEASE_SNDBUF_SHARED(window); \
1334 windowSamples = window->samples; \
1335 windowFrames = window->frames; \
1336 windowGuardFrame = windowFrames - 1; \
1339 #define GET_WARP_AMP_PARAMS \
1340 if(grain->winType < 0.){ \
1344 amp = grain->curamp; \
1346 GET_WARP_WIN_RELAXED(grain->winType); \
1347 if (!windowData) break; \
1348 winPos = grain->winPos; \
1349 winInc = grain->winInc; \
1350 amp = grain->curamp; \
1354 void Warp1_next(Warp1
*unit
, int inNumSamples
)
1356 ClearUnitOutputs(unit
, inNumSamples
);
1362 for (uint32 n
=0; n
< numOutputs
; n
++) {
1363 int nextGrain
= unit
->mNextGrain
[n
];
1364 for (int i
=0; i
< unit
->mNumActive
[n
]; ) {
1365 WarpWinGrain
*grain
= unit
->mGrains
[n
] + i
;
1367 double loopMax
= (double)bufFrames
;
1369 double rate
= grain
->rate
;
1370 double phase
= grain
->phase
;
1372 GET_GRAIN_AMP_PARAMS
1373 float *out1
= out
[n
];
1374 int nsmps
= sc_min(grain
->counter
, inNumSamples
);
1375 if (grain
->interp
>= 4) {
1376 for (int j
=0; j
<nsmps
; ++j
) {
1377 BUF_GRAIN_LOOP_BODY_4_N
1381 } else if (grain
->interp
>= 2) {
1382 for (int j
=0; j
<nsmps
; ++j
) {
1383 BUF_GRAIN_LOOP_BODY_2_N
1388 for (int j
=0; j
<nsmps
; ++j
) {
1389 BUF_GRAIN_LOOP_BODY_1_N
1395 grain
->phase
= phase
;
1396 SAVE_GRAIN_AMP_PARAMS
1397 if (grain
->counter
<= 0)
1398 *grain
= unit
->mGrains
[n
][--unit
->mNumActive
[n
]]; // remove grain
1403 for (int i
=0; i
<inNumSamples
; ++i
) {
1405 if (nextGrain
== 0) {
1407 if (unit
->mNumActive
[n
]+1 >= kMaxGrains
) break;
1408 // uint32 bufnum = (uint32)GRAIN_IN_AT(unit, 0, i);
1409 // if (bufnum >= numBufs) break;
1411 float bufSampleRate
= buf
->samplerate
;
1412 float bufRateScale
= bufSampleRate
* SAMPLEDUR
;
1413 double loopMax
= (double)bufFrames
;
1415 WarpWinGrain
*grain
= unit
->mGrains
[n
] + unit
->mNumActive
[n
]++;
1416 // grain->bufnum = bufnum;
1418 float overlaps
= GRAIN_IN_AT(unit
, 5, i
);
1419 float counter
= GRAIN_IN_AT(unit
, 3, i
) * SAMPLERATE
;
1420 double winrandamt
= unit
->mParent
->mRGen
->frand2() * (double)GRAIN_IN_AT(unit
, 6, i
);
1421 counter
= sc_max(4., floor(counter
+ (counter
* winrandamt
)));
1422 grain
->counter
= (int)counter
;
1424 nextGrain
= (int)(counter
/ overlaps
);
1426 unit
->mNextGrain
[n
] = nextGrain
;
1428 float rate
= grain
->rate
= GRAIN_IN_AT(unit
, 2, i
) * bufRateScale
;
1429 float phase
= GRAIN_IN_AT(unit
, 1, i
) * (float)bufFrames
;
1430 grain
->interp
= (int)GRAIN_IN_AT(unit
, 7, i
);
1431 float winType
= grain
->winType
= (int)GRAIN_IN_AT(unit
, 4, i
); // the buffer that holds the grain shape
1434 if (winType
>= unit
->mWorld
->mNumSndBufs
) {
1435 Print("Envelope buffer out of range!\n");
1439 GET_GRAIN_WIN_RELAXED(winType
)
1440 if (windowData
|| (winType
< 0.)) {
1443 float *out1
= out
[n
] + i
;
1445 int nsmps
= sc_min(grain
->counter
, inNumSamples
- i
);
1446 if (grain
->interp
>= 4) {
1447 for (int j
=0; j
<nsmps
; ++j
) {
1448 BUF_GRAIN_LOOP_BODY_4_N
1452 } else if (grain
->interp
>= 2) {
1453 for (int j
=0; j
<nsmps
; ++j
) {
1454 BUF_GRAIN_LOOP_BODY_2_N
1459 for (int j
=0; j
<nsmps
; ++j
) {
1460 BUF_GRAIN_LOOP_BODY_1_N
1466 grain
->phase
= phase
;
1467 SAVE_GRAIN_AMP_PARAMS
1469 if (grain
->counter
<= 0)
1470 *grain
= unit
->mGrains
[n
][--unit
->mNumActive
[n
]]; // remove grain
1475 unit
->mNextGrain
[n
] = nextGrain
;
1479 void Warp1_Ctor(Warp1
*unit
)
1481 SETCALC(Warp1_next
);
1483 for(int i
= 0; i
< 16; i
++){
1484 unit
->mNumActive
[i
] = 0;
1485 unit
->mNextGrain
[i
] = 1;
1488 ClearUnitOutputs(unit
, 1);
1489 unit
->m_fbufnum
= -1e9f
;
1493 ////////////////////////////////////////////////////////////////////////////////////////////////////////
1499 DefineDtorCantAliasUnit(GrainIn
);
1500 DefineDtorCantAliasUnit(GrainSin
);
1501 DefineDtorCantAliasUnit(GrainFM
);
1502 DefineDtorCantAliasUnit(GrainBuf
);
1503 DefineSimpleCantAliasUnit(Warp1
);