1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 #pragma once
22 
23 #include "SC_PlugIn.h"
24 #include "SCComplex.h"
25 
26 #include <string.h>
27 
28 struct SCComplexBuf {
29     float dc, nyq;
30     SCComplex bin[1];
31 };
32 
33 struct SCPolarBuf {
34     float dc, nyq;
35     SCPolar bin[1];
36 };
37 
ToPolarApx(SndBuf * buf)38 static inline SCPolarBuf* ToPolarApx(SndBuf* buf) {
39     if (buf->coord == coord_Complex) {
40         SCComplexBuf* p = (SCComplexBuf*)buf->data;
41         int numbins = (buf->samples - 2) >> 1;
42         for (int i = 0; i < numbins; ++i) {
43             p->bin[i].ToPolarApxInPlace();
44         }
45         buf->coord = coord_Polar;
46     }
47 
48     return (SCPolarBuf*)buf->data;
49 }
50 
ToComplexApx(SndBuf * buf)51 static inline SCComplexBuf* ToComplexApx(SndBuf* buf) {
52     if (buf->coord == coord_Polar) {
53         SCPolarBuf* p = (SCPolarBuf*)buf->data;
54         int numbins = (buf->samples - 2) >> 1;
55         for (int i = 0; i < numbins; ++i) {
56             p->bin[i].ToComplexApxInPlace();
57         }
58         buf->coord = coord_Complex;
59     }
60     return (SCComplexBuf*)buf->data;
61 }
62 
63 struct PV_Unit : Unit {};
64 
65 
66 #define sc_clipbuf(x, hi) ((x) >= (hi) ? 0 : ((x) < 0 ? 0 : (x)))
67 
68 // for operation on one buffer
69 #define PV_GET_BUF                                                                                                     \
70     float fbufnum = ZIN0(0);                                                                                           \
71     if (fbufnum < 0.f) {                                                                                               \
72         ZOUT0(0) = -1.f;                                                                                               \
73         return;                                                                                                        \
74     }                                                                                                                  \
75     ZOUT0(0) = fbufnum;                                                                                                \
76     uint32 ibufnum = (uint32)fbufnum;                                                                                  \
77     World* world = unit->mWorld;                                                                                       \
78     SndBuf* buf;                                                                                                       \
79     if (ibufnum >= world->mNumSndBufs) {                                                                               \
80         int localBufNum = ibufnum - world->mNumSndBufs;                                                                \
81         Graph* parent = unit->mParent;                                                                                 \
82         if (localBufNum <= parent->localBufNum) {                                                                      \
83             buf = parent->mLocalSndBufs + localBufNum;                                                                 \
84         } else {                                                                                                       \
85             buf = world->mSndBufs;                                                                                     \
86         }                                                                                                              \
87     } else {                                                                                                           \
88         buf = world->mSndBufs + ibufnum;                                                                               \
89     }                                                                                                                  \
90     LOCK_SNDBUF(buf);                                                                                                  \
91     int numbins = (buf->samples - 2) >> 1;
92 
93 
94 // for operation on two input buffers, result goes in first one.
95 #define PV_GET_BUF2                                                                                                    \
96     float fbufnum1 = ZIN0(0);                                                                                          \
97     float fbufnum2 = ZIN0(1);                                                                                          \
98     if (fbufnum1 < 0.f || fbufnum2 < 0.f) {                                                                            \
99         ZOUT0(0) = -1.f;                                                                                               \
100         return;                                                                                                        \
101     }                                                                                                                  \
102     ZOUT0(0) = fbufnum1;                                                                                               \
103     uint32 ibufnum1 = (int)fbufnum1;                                                                                   \
104     uint32 ibufnum2 = (int)fbufnum2;                                                                                   \
105     World* world = unit->mWorld;                                                                                       \
106     SndBuf* buf1;                                                                                                      \
107     SndBuf* buf2;                                                                                                      \
108     if (ibufnum1 >= world->mNumSndBufs) {                                                                              \
109         int localBufNum = ibufnum1 - world->mNumSndBufs;                                                               \
110         Graph* parent = unit->mParent;                                                                                 \
111         if (localBufNum <= parent->localBufNum) {                                                                      \
112             buf1 = parent->mLocalSndBufs + localBufNum;                                                                \
113         } else {                                                                                                       \
114             buf1 = world->mSndBufs;                                                                                    \
115         }                                                                                                              \
116     } else {                                                                                                           \
117         buf1 = world->mSndBufs + ibufnum1;                                                                             \
118     }                                                                                                                  \
119     if (ibufnum2 >= world->mNumSndBufs) {                                                                              \
120         int localBufNum = ibufnum2 - world->mNumSndBufs;                                                               \
121         Graph* parent = unit->mParent;                                                                                 \
122         if (localBufNum <= parent->localBufNum) {                                                                      \
123             buf2 = parent->mLocalSndBufs + localBufNum;                                                                \
124         } else {                                                                                                       \
125             buf2 = world->mSndBufs;                                                                                    \
126         }                                                                                                              \
127     } else {                                                                                                           \
128         buf2 = world->mSndBufs + ibufnum2;                                                                             \
129     }                                                                                                                  \
130     LOCK_SNDBUF2(buf1, buf2);                                                                                          \
131     if (buf1->samples != buf2->samples)                                                                                \
132         return;                                                                                                        \
133     int numbins = (buf1->samples - 2) >> 1;
134 
135 #define MAKE_TEMP_BUF                                                                                                  \
136     if (!unit->m_tempbuf) {                                                                                            \
137         unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, buf->samples * sizeof(float));                                 \
138         unit->m_numbins = numbins;                                                                                     \
139     } else if (numbins != unit->m_numbins)                                                                             \
140         return;
141 
142 extern InterfaceTable* ft;
143