Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / plugins / TestUGens.cpp
bloba9fade33b700e5d37717b821c43547c27bf17c53
1 /*
2 * TestUGens.cpp
3 * Plugins
4 * Copyright (c) 2007 Scott Wilson <i@scottwilson.ca>. All rights reserved.
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.
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.
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
20 * Created by Scott Wilson on 22/06/2007.
21 * Modified by James Harkins on 28/07/2007.
26 #include "SC_PlugIn.h"
27 #include <cstdio>
29 //////////////////////////////////////////////////////////////////////////////////////////////////
31 // FIXME: once we completely move to c++11, we should get rid of sc_fpclassify
33 // Visual C++ doesn't have fpclassify (C99), so define it here if needed
34 #ifdef _MSC_VER
35 #include <float.h>
36 enum { FP_NORMAL, FP_NAN, FP_INFINITE, FP_SUBNORMAL };
38 static int sc_fpclassify(float x)
40 int result;
41 int kind = _fpclass((double)x);
42 switch (kind)
44 case _FPCLASS_NINF:
45 result = FP_INFINITE;
46 break;
47 case _FPCLASS_PINF:
48 result = FP_INFINITE;
49 break;
50 case _FPCLASS_SNAN:
51 result = FP_NAN;
52 break;
53 case _FPCLASS_QNAN:
54 result = FP_NAN;
55 break;
56 case _FPCLASS_ND:
57 result = FP_SUBNORMAL;
58 break;
59 case _FPCLASS_PD:
60 result = FP_SUBNORMAL;
61 break;
62 default:
63 result = FP_NORMAL;
65 return result;
68 #else
69 inline int sc_fpclassify(float x)
71 return std::fpclassify(x);
73 #endif // _WIN32
75 //////////////////////////////////////////////////////////////////////////////////////////////////
77 static InterfaceTable *ft;
79 struct CheckBadValues : public Unit
81 long sameCount;
82 int prevclass;
85 // declare unit generator functions
86 extern "C"
88 void CheckBadValues_Ctor(CheckBadValues* unit);
89 void CheckBadValues_next(CheckBadValues* unit, int inNumSamples);
92 static const char *CheckBadValues_fpclassString(int fpclass);
93 inline int CheckBadValues_fold_fpclasses(int fpclass);
95 //////////////////////////////////////////////////////////////////////////////////////////////////
97 void CheckBadValues_Ctor(CheckBadValues* unit)
99 unit->prevclass = FP_NORMAL;
100 unit->sameCount = 0;
101 SETCALC(CheckBadValues_next);
102 CheckBadValues_next(unit, 1);
106 void CheckBadValues_next(CheckBadValues* unit, int inNumSamples)
108 float *in = ZIN(0);
109 float *out = ZOUT(0);
110 float id = ZIN0(1);
111 int post = (int) ZIN0(2);
113 float samp;
114 int classification;
116 switch(post) {
117 case 1: // post a line on every bad value
118 LOOP1(inNumSamples,
119 samp = ZXP(in);
120 classification = sc_fpclassify(samp);
121 switch (classification)
123 case FP_INFINITE:
124 printf("Infinite number found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id);
125 ZXP(out) = 2;
126 break;
127 case FP_NAN:
128 printf("NaN found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id);
129 ZXP(out) = 1;
130 break;
131 case FP_SUBNORMAL:
132 printf("Denormal found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id);
133 ZXP(out) = 3;
134 break;
135 default:
136 ZXP(out) = 0;
139 break;
140 case 2:
141 LOOP1(inNumSamples,
142 samp = ZXP(in);
143 classification = CheckBadValues_fold_fpclasses(sc_fpclassify(samp));
144 if(classification != unit->prevclass) {
145 if(unit->sameCount == 0) {
146 printf("CheckBadValues: %s found in Synth %d, ID %d\n",
147 CheckBadValues_fpclassString(classification), unit->mParent->mNode.mID, (int)id);
148 } else {
149 printf("CheckBadValues: %s found in Synth %d, ID %d (previous %d values were %s)\n",
150 CheckBadValues_fpclassString(classification), unit->mParent->mNode.mID, (int)id,
151 (int)unit->sameCount, CheckBadValues_fpclassString(unit->prevclass)
154 unit->sameCount = 0;
156 switch (classification)
158 case FP_INFINITE:
159 ZXP(out) = 2;
160 break;
161 case FP_NAN:
162 ZXP(out) = 1;
163 break;
164 case FP_SUBNORMAL:
165 ZXP(out) = 3;
166 break;
167 default:
168 ZXP(out) = 0;
170 unit->sameCount++;
171 unit->prevclass = classification;
173 break;
174 default: // no post
175 LOOP1(inNumSamples,
176 samp = ZXP(in);
177 classification = sc_fpclassify(samp);
178 switch (classification)
180 case FP_INFINITE:
181 ZXP(out) = 2;
182 break;
183 case FP_NAN:
184 ZXP(out) = 1;
185 break;
186 case FP_SUBNORMAL:
187 ZXP(out) = 3;
188 break;
189 default:
190 ZXP(out) = 0;
193 break;
197 const char *CheckBadValues_fpclassString(int fpclass)
199 switch(fpclass) {
200 case FP_NORMAL: return "normal";
201 case FP_NAN: return "NaN";
202 case FP_INFINITE: return "infinity";
203 #ifndef _MSC_VER
204 case FP_ZERO: return "zero";
205 #endif
206 case FP_SUBNORMAL: return "denormal";
207 default: return "unknown";
211 #ifndef _MSC_VER
212 inline int CheckBadValues_fold_fpclasses(int fpclass)
214 switch(fpclass) {
215 case FP_ZERO: return FP_NORMAL; // a bit hacky. we mean "zero is fine too".
216 default: return fpclass;
219 #else
220 inline int CheckBadValues_fold_fpclasses(int fpclass)
222 return fpclass;
224 #endif
226 ////////////////////////////////////////////////////////////////////
228 // the load function is called by the host when the plug-in is loaded
229 PluginLoad(Test)
231 ft = inTable;
233 DefineSimpleUnit(CheckBadValues);