@@ 0,0 1,275 @@
+#include <SC_PlugIn.h>
+#include "kreflect.h"
+
+#ifdef SUPERCOLLIDER_MAKEDEF
+#include <stdio.h>
+#undef SETCALC
+#define SETCALC(fn)
+#undef SAMPLERATE
+#define SAMPLERATE 44100
+#undef BUFLENGTH
+#define BUFLENGTH 1
+#undef RTAlloc
+#define RTAlloc(m,sz) malloc(sz)
+#endif
+
+static InterfaceTable *ft = nullptr;
+
+using namespace KReflect;
+
+class Class;
+
+static bool SymbolIsVisible(krt_sym const & sym) {
+ return sym.size > 0 && (sym.flags & KRT_FLAG_NO_DEFAULT) == 0;
+}
+
+struct Instance : public Unit {
+ krt_class *k;
+ float* outBuf;
+ float* params;
+ void* instance;
+ krt_process_call audioClock = nullptr;
+
+ void Clear(int numSamples) {
+ Unit* unit = this;
+ for(int c=0;c<mNumOutputs;c++) {
+ for(int f=0;f<numSamples;f++) {
+ OUT(c)[f] = 0.f;
+ }
+ }
+ }
+
+ void Next(int numSamples) {
+ Unit* unit = this;
+ char *ptr = (char*)params;
+ int scIn = 0;
+
+ void *scratch = alloca(k->result_type_size);
+ for(int i=0;i<k->num_symbols;++i) {
+ auto& sym{k->symbols[i]};
+ if (SymbolIsVisible(sym)) {
+ if ((sym.flags & KRT_FLAG_STREAMING) != 0) {
+ *k->var(instance, sym.slot_index) = IN(scIn++);
+ } else {
+ float pv = IN0(scIn++);
+ if (pv != *(float*)ptr) {
+ *(float*)ptr = pv;
+ *k->var(instance, sym.slot_index) = ptr;
+ if (sym.process) {
+ sym.process(instance, scratch, 1);
+ }
+ }
+ }
+ }
+
+ ptr += sym.size;
+ }
+
+ if (audioClock) {
+ if (mNumOutputs > 1) {
+ audioClock(instance, outBuf, numSamples);
+ Deinterleave(mOutBuf, outBuf, numSamples, mNumOutputs);
+ } else {
+ audioClock(instance, mOutBuf[0], numSamples);
+ }
+ } else {
+ Clear(numSamples);
+ }
+ }
+};
+
+static float SampleRate = 44100.f;
+
+class Class {
+ krt_class *k;
+ size_t paramSize, unitSize;
+ const char *name;
+public:
+ Class(const char *name, krt_class *k):k(k),name(name) {
+ paramSize = SizeOfParams();
+ unitSize = k->get_size();
+ }
+
+ size_t SizeOfParams() {
+ size_t psz = 0;
+ for(int i=0;i<k->num_symbols;i++) {
+ psz += k->symbols[i].size;
+ }
+ psz = (psz + 15) & -16;
+ return psz;
+ }
+
+
+ static void NextProc(Instance* unit, int numSamples) {
+ unit->Next(numSamples);
+ }
+
+ static void NextFailure(Instance* unit, int numSamples) {
+ unit->Clear(numSamples);
+ }
+
+ int GetNumOutputs() {
+ return GetFloatTypeDim(k->result_type_descriptor);
+ }
+
+ void Construct(Instance* unit) {
+ unit->k = k;
+
+ char *bytes = (char*)RTAlloc(unit->mWorld, paramSize + unitSize);
+ unit->params = (float*)bytes;
+ memset(unit->params, 0, paramSize);
+ unit->instance = bytes + paramSize;
+ unit->audioClock = nullptr;
+
+ memset(unit->instance, 0, k->get_size());
+ SampleRate = SAMPLERATE;
+
+ char *ptr = (char *)unit->params;
+ for(int i=0;i<k->num_symbols;++i) {
+ auto& sym{k->symbols[i]};
+
+ if (!strcmp(sym.sym, "#Rate{audio}")) {
+ k->configure(sym.slot_index, &SampleRate);
+ } else if ((KRT_FLAG_NO_DEFAULT & sym.flags) != 0) {
+ Print("Configuration variable %s[%s] not supported\n", name, sym.sym);
+ SETCALC(NextFailure);
+ return;
+ } else if (!strcmp(sym.sym, "audio")) {
+ unit->audioClock = sym.process;
+ }
+ }
+
+ k->construct(unit->instance, nullptr);
+ SETCALC(NextProc);
+
+ if (unit->mNumOutputs > 1) {
+ unit->outBuf = (float*)RTAlloc(unit->mWorld, k->result_type_size * BUFLENGTH);
+ } else {
+ unit->outBuf = nullptr;
+ }
+ }
+
+ void Destruct(Instance* unit) {
+ if (unit->outBuf) {
+ RTFree(unit->mWorld, unit->params);
+ RTFree(unit->mWorld, unit->outBuf);
+ unit->params = nullptr;
+ unit->instance = nullptr;
+ unit->outBuf = nullptr;
+ }
+ }
+
+#ifdef SUPERCOLLIDER_MAKEDEF
+ void WriteSynthDef(FILE* sdef) {
+ Instance *instance = (Instance *)malloc(sizeof(Instance));
+ Construct(instance);
+
+ fprintf(sdef, "%s : %s {\n\t*ar { arg ", Sanitize(name).c_str(), GetNumOutputs() == 1 ? "UGen" : "MultiOutUGen");
+ bool first = true;
+ std::vector<std::string> symNames;
+ std::map<std::string, float> defaultVals;
+ for(int i=0;i<k->num_symbols;++i) {
+ auto& sym{k->symbols[i]};
+ if (SymbolIsVisible(sym)) {
+ std::string symName { sym.sym };
+ float **slot = (float**)k->var(instance->instance, sym.slot_index);
+ defaultVals[sym.sym] = (*slot ? **slot : 0.f);
+ symNames.push_back(Sanitize(StripOrdinal(symName)));
+ }
+ }
+
+ for(auto &dv : defaultVals) {
+ if (first) {
+ first = false;
+ } else {
+ fprintf(sdef, ", ");
+ }
+ std::string sym = dv.first;
+ fprintf(sdef, "%s = %f", Sanitize(StripOrdinal(dv.first)).c_str(), dv.second);
+
+ }
+
+ fprintf(sdef, ";\n");
+
+ for(int i=0;i<k->num_symbols;++i) {
+ auto& sym{k->symbols[i]};
+ if (sym.size > 0 && (sym.flags & KRT_FLAG_NO_DEFAULT) == 0) {
+ if ((sym.flags & KRT_FLAG_STREAMING) != 0) {
+ auto nm = Sanitize(StripOrdinal(sym.sym));
+ fprintf(sdef, "\t\t(%s.rate != 'audio').if {\n", nm.c_str());
+ fprintf(sdef, "\t\t\t^\"<%s> must be an audio signal\".throw;\n", nm.c_str());
+ fprintf(sdef, "\t\t};\n");
+ }
+ }
+ }
+
+ fprintf(sdef, "\t\t^this.multiNew('audio'");
+ for(auto &s:symNames) {
+ fprintf(sdef, ", %s", s.c_str());
+ }
+ fprintf(sdef, ");\n\t}");
+
+ if (GetNumOutputs() > 1) {
+ fprintf(sdef,
+ "\n\n\tinit { arg ... theInputs;\n"
+ "\t\tinputs = theInputs;\n"
+ "\t\t^this.initOutputs(%i, rate);\n"
+ "\t}", GetNumOutputs());
+ }
+
+ fprintf(sdef, "\n}\n\n");
+ free(instance);
+ }
+#endif
+};
+
+#define F(CLASS) \
+extern "C" krt_class* CLASS ## _GetClassData(); \
+static Class Wrap ## CLASS { #CLASS, CLASS ## _GetClassData() }; \
+void Construct ## CLASS(Unit* i) { Wrap ## CLASS . Construct((Instance*)i); } \
+void Destruct ## CLASS(Unit* i) { Wrap ## CLASS . Destruct((Instance*)i); }
+DSP_CLASSES
+#undef F
+
+void Export(const char *className, Class *c, UnitCtorFunc ctor, UnitDtorFunc dtor) {
+ (*ft->fDefineUnit)(
+ className,
+ sizeof(Instance),
+ ctor,
+ dtor,
+ kUnitDef_CantAliasInputsToOutputs
+ );
+}
+
+extern "C" {
+#ifdef WIN32
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT __attribute__((visibility("default")))
+#endif
+
+ EXPORT void load(InterfaceTable* SCHost) {
+ ft = SCHost;
+ #define F(CLASS) Export(#CLASS, &Wrap ## CLASS, Construct ## CLASS, Destruct ## CLASS);
+ DSP_CLASSES
+ #undef F
+ }
+
+ EXPORT int api_version(void) { return sc_api_version; }
+}
+
+#ifdef SUPERCOLLIDER_MAKEDEF
+int main(int n, char *argv[]) {
+ FILE *def = stdout;
+ if (n>1) {
+ def = fopen(argv[1],"wt");
+ }
+#define F(CLASS) Wrap ## CLASS . WriteSynthDef(def);
+ DSP_CLASSES
+#undef F
+ if (def != stdout) {
+ fclose(def);
+ }
+ return 0;
+}
+#endif