nshaheedmove to c_str657ab673 years agoHistory
302 lines · 8.5 KB · C++
RawDownload
//-----------------------------------------------------------------------------// name: Patch.cpp// desc: Pipe UGen signals into UGen methods directly!//       The primary use of this is easily and efficiently//       control UGen parameters with tick-level LFOs.// // example:// SinOsc sin => Pan2 pan => dac;//// // Our LFO is fed into Patch's input...// SinOsc lfo = > Patch p = > blackhole;// 1 = > lfo.freq;//// // ... where it then updates the pan position at every tick// p.connect(pan, "pan");// // 1::hour = > now;//// authors: Nick Shaheed (nshaheed@ccrma.stanford.edu)// date: Winter 2022////----------------------------------------------------------------------------- // TODO: add disconnect method #include "chuck_dl.h"#include "chuck_vm.h" // general includes#include <stdio.h>#include <limits.h>#include <iostream> // declaration of chugin constructorCK_DLL_CTOR(patch_ctor);// declaration of chugin desctructorCK_DLL_DTOR(patch_dtor); // Patch methodsCK_DLL_MFUN(patch_connect);CK_DLL_MFUN(patch_disconnect);CK_DLL_MFUN(patch_getMethod);CK_DLL_MFUN(patch_setMethod); // for Chugins extending UGen, this is mono synthesis function for 1 sampleCK_DLL_TICK(patch_tick); // this is a special offset reserved for Chugin internal datat_CKINT patch_data_offset = 0; // The Patch classclass Patch{public:    // constructor    Patch( t_CKFLOAT fs)    {        m_func = nullptr;    }     // for Chugins extending UGen    SAMPLE tick( SAMPLE in )    {        // if the method is set, patch through the value        if (m_func) {            // default: this passes whatever input is patched into Chugin            t_CKFLOAT val = (t_CKFLOAT)in;            Chuck_DL_Return ret;             // these three lines took a very long time to figure out...            Chuck_VM_Code* func = m_func->code;            // cast the function as a dynamically-linked member func            f_mfun f = (f_mfun)func->native_func;            // call said function            f((Chuck_Object*)(m_dest), &val, &ret, m_vm, m_shred, m_api); // api?        }        return in;    }     // set parameter example    void connect( Chuck_UGen* dest, std::string method, Chuck_VM* vm, Chuck_VM_Shred* shred, CK_DL_API api)    {        m_dest = dest;        m_vm = vm;        m_api = api;        m_shred = shred;         findMethod(method);    }     void disconnect() {        m_dest = NULL;        m_vm = NULL;        m_api = NULL;        m_shred = NULL;        m_func = NULL;    };     std::string getMethod() { return m_func->base_name; }      void setMethod(std::string method) {        findMethod(method);    }    private:    // instance data    Chuck_UGen* m_dest;    Chuck_VM_Shred* m_shred;    Chuck_VM* m_vm;    Chuck_Func* m_func;    CK_DL_API m_api;     // Given a UGen, try to the find the methods among its    // associated functions.    void findMethod(std::string method) {        Chuck_Func* found = NULL;         for (int i = 0; i < m_dest->vtable->funcs.size(); i++)        {            Chuck_Func* func = m_dest->vtable->funcs[i];             // funcs can be overwritten or have multiple defn, look for the right one            if (func->base_name == method &&                func->def->arg_list != NULL &&                // we only want funcs with one arg                func->def->arg_list->next == NULL &&                // ensure arg is float                func->def->arg_list->type == m_shred->vm_ref->env()->t_float)            {                found = func;                break;            }        }         if (!found) {            std::cerr << "Patch.connect(): unable to find method " << method << std::endl;            return;        }         Chuck_Func* curr = found;        // traverse overloads to find top of stack        while (curr->next != NULL) {            if (curr->def->arg_list != NULL &&                // we only want funcs with one arg                curr->def->arg_list->next == NULL &&                // ensure arg is float                curr->def->arg_list->type == m_shred->vm_ref->env()->t_float)            {                found = curr;            }            curr = curr->next;        }         m_func = found;         return;    }};  // query function: chuck calls this when loading the Chugin// NOTE: developer will need to modify this function to// add additional functions to this ChuginCK_DLL_QUERY( Patch ){    // hmm, don't change this...    QUERY->setname(QUERY, "Patch");        // begin the class definition    // can change the second argument to extend a different ChucK class    QUERY->begin_class(QUERY, "Patch", "UGen");     QUERY->doc_class(QUERY, "Pipe UGen signals into UGen methods directly! "        "The primary use of this is to easily and efficiently "        "control UGen parameters with tick-level LFOs."    );     // register the constructor (probably no need to change)    QUERY->add_ctor(QUERY, patch_ctor);    // register the destructor (probably no need to change)    QUERY->add_dtor(QUERY, patch_dtor);        // for UGen's only: add tick function    QUERY->add_ugen_func(QUERY, patch_tick, NULL, 1, 1);     // connect method    QUERY->add_mfun(QUERY, patch_connect, "void", "connect");    QUERY->add_arg(QUERY, "UGen", "dest" );    QUERY->add_arg(QUERY, "string", "method");    QUERY->doc_func(QUERY, "Call the method in dest with Patch's input. "        "Method must be a method that takes a single float as an input, "        "i.e. setters such as SinOsc.freq and Pan2.pan.");        QUERY->add_mfun(QUERY, patch_disconnect, "void", "disconnect");    QUERY->doc_func(QUERY, "Disconnect the currently attached method from Patch. "        "If the method is not set, nothing will happen.");     // method getter and setter    QUERY->add_mfun(QUERY, patch_getMethod, "string", "method");    QUERY->doc_func(QUERY, "Get method name");     QUERY->add_mfun(QUERY, patch_setMethod, "string", "method");    QUERY->add_arg(QUERY, "string", "method");    QUERY->doc_func(QUERY, "Set method name");         // this reserves a variable in the ChucK internal class to store     // referene to the c++ class we defined above    patch_data_offset = QUERY->add_mvar(QUERY, "int", "@p_data", false);      // end the class definition    // IMPORTANT: this MUST be called!    QUERY->end_class(QUERY);     // wasn't that a breeze?    return TRUE;}  // implementation for the constructorCK_DLL_CTOR(patch_ctor){    // get the offset where we'll store our internal c++ class pointer    OBJ_MEMBER_INT(SELF, patch_data_offset) = 0;        // instantiate our internal c++ class representation    Patch * p_obj = new Patch(API->vm->get_srate(API, SHRED));        // store the pointer in the ChucK object member    OBJ_MEMBER_INT(SELF, patch_data_offset) = (t_CKINT) p_obj;}  // implementation for the destructorCK_DLL_DTOR(patch_dtor){    // get our c++ class pointer    Patch * p_obj = (Patch *) OBJ_MEMBER_INT(SELF, patch_data_offset);    // check it    if( p_obj )    {        // clean up        delete p_obj;        OBJ_MEMBER_INT(SELF, patch_data_offset) = 0;        p_obj = NULL;    }}  // implementation for tick functionCK_DLL_TICK(patch_tick){    // get our c++ class pointer    Patch * p_obj = (Patch *) OBJ_MEMBER_INT(SELF, patch_data_offset);     // invoke our tick function; store in the magical out variable    if(p_obj) *out = p_obj->tick(in);     // yes    return TRUE;} // get the name of the current method being patchedCK_DLL_MFUN(patch_getMethod){    Patch* p_obj = (Patch*)OBJ_MEMBER_INT(SELF, patch_data_offset);        std::string method = p_obj->getMethod();    RETURN->v_string = (Chuck_String*)API->object->create_string(API, SHRED, method.c_str());} // get the name of the current method being patchedCK_DLL_MFUN(patch_setMethod){    Patch* p_obj = (Patch*)OBJ_MEMBER_INT(SELF, patch_data_offset);    Chuck_String* method = (Chuck_String*)GET_NEXT_STRING(ARGS);     p_obj->setMethod(method->str());    RETURN->v_string = method;}  // connect the ugen's method so that patch's input will set itCK_DLL_MFUN(patch_connect){    // get our c++ class pointer    Patch * p_obj = (Patch *) OBJ_MEMBER_INT(SELF, patch_data_offset);    Chuck_UGen * dest = (Chuck_UGen *)GET_NEXT_OBJECT(ARGS);    Chuck_String* method = (Chuck_String*)GET_NEXT_STRING(ARGS);     p_obj->connect(dest, method->str(), VM, SHRED, API); } CK_DLL_MFUN(patch_disconnect){    // get our c++ class pointer    Patch* p_obj = (Patch*)OBJ_MEMBER_INT(SELF, patch_data_offset);     p_obj->disconnect();}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t