#include "ScriptEngine.hpp" #include "z_libpd.h" #include "util/z_print_util.h" using namespace rack; #define BUFFERSIZE MAX_BUFFER_SIZE * NUM_ROWS // there is no multi-instance support for receiving messages from libpd // for now, received values for the prototype gui will be stored in global variables float g_lights[NUM_ROWS][3] = {}; float g_switchLights[NUM_ROWS][3] = {}; std::string g_utility[2] = {}; bool g_display_is_valid = false; std::vector split (const std::string &s, char delim) { std::vector result; std::stringstream ss (s); std::string item; while (getline (ss, item, delim)) { result.push_back (item); } return result; } struct LibPDEngine : ScriptEngine { ~LibPDEngine() { libpd_free_instance(_lpd); } void sendInitialStates(const ProcessBlock* block); static void receiveLights(const char *s); bool knobChanged(const float* knobs, int idx); bool switchChanged(const bool* knobs, int idx); void sendKnob(const int idx, const float value); void sendSwitch(const int idx, const bool value); t_pdinstance *_lpd; int _pd_block_size = 64; int _sampleRate = 0; int _ticks = 0; bool _init = true; float _old_knobs[NUM_ROWS] = {}; bool _old_switches[NUM_ROWS] = {}; float _output[BUFFERSIZE] = {}; float _input[BUFFERSIZE] = {};// = (float*)malloc(1024*2*sizeof(float)); const static std::map _light_map; const static std::map _switchLight_map; const static std::map _utility_map; std::string getEngineName() override { return "Pure Data"; } int run(const std::string& path, const std::string& script) override { ProcessBlock* block = getProcessBlock(); _sampleRate = block->sampleRate; setBufferSize(_pd_block_size); setFrameDivider(1); libpd_init(); _lpd = libpd_new_instance(); libpd_set_printhook((t_libpd_printhook)libpd_print_concatenator); libpd_set_concatenated_printhook( receiveLights ); if(libpd_num_instances()>2) { display("Sorry, multi instance support in libpd is under development!"); return -1; } //display(std::to_string(libpd_num_instances())); libpd_init_audio(NUM_ROWS, NUM_ROWS, _sampleRate); // compute audio [; pd dsp 1( libpd_start_message(1); // one enstry in list libpd_add_float(1.0f); libpd_finish_message("pd", "dsp"); std::string name = string::filename(path); std::string dir = string::directory(path); libpd_openfile(name.c_str(), dir.c_str()); sendInitialStates(block); return 0; } int process() override { // block ProcessBlock* block = getProcessBlock(); // get samples prototype int rows = NUM_ROWS; for (int s = 0; s < _pd_block_size; s++) { for (int r = 0; r < rows; r++) { _input[s*rows+r] = block->inputs[r][s]; } } libpd_set_instance(_lpd); // knobs for (int i=0; iknobs, i) ){ sendKnob(i, block->knobs[i]); } } // lights for(int i=0; ilights[i][0] = g_lights[i][0]; block->lights[i][1] = g_lights[i][1]; block->lights[i][2] = g_lights[i][2]; } // switch lights for(int i=0; iswitchLights[i][0] = g_switchLights[i][0]; block->switchLights[i][1] = g_switchLights[i][1]; block->switchLights[i][2] = g_switchLights[i][2]; } // switches for(int i=0; iswitches, i) ){ sendSwitch(i, block->switches[i]); } } // display if(g_display_is_valid){ display(g_utility[1]); g_display_is_valid = false; } // process samples in libpd _ticks = 1; libpd_process_float(_ticks, _input, _output); //return samples to prototype for (int s = 0; s < _pd_block_size; s++) { for (int r = 0; r < rows; r++) { block->outputs[r][s] = _output[s*rows+r]; } } return 0; } }; __attribute__((constructor(1000))) static void constructor() { addScriptEngine("pd"); } void LibPDEngine::receiveLights(const char *s) { std::string str = std::string(s); std::vector atoms = split (str, ' '); if(atoms[0]=="toVCV:"){ // parse lights list bool light_is_valid = true; int light_idx = -1; try { light_idx = _light_map.at(atoms[1]); // map::at throws an out-of-range } catch (const std::out_of_range& oor) { light_is_valid = false; //display("Warning:"+atoms[1]+" not found!"); } //std::cout << v[1] << ", " << g_led_map[v[1]] << std::endl; if(light_is_valid && atoms.size()==5){ g_lights[light_idx][0] = stof(atoms[2]); // red g_lights[light_idx][1] = stof(atoms[3]); // green g_lights[light_idx][2] = stof(atoms[4]); // blue } else { // error } // parse switch lights list bool switchLight_is_valid = true; int switchLight_idx = -1; try { switchLight_idx = _switchLight_map.at(atoms[1]); // map::at throws an out-of-range } catch (const std::out_of_range& oor) { switchLight_is_valid = false; //display("Warning:"+atoms[1]+" not found!"); } //std::cout << v[1] << ", " << g_led_map[v[1]] << std::endl; if(switchLight_is_valid && atoms.size()==5){ g_switchLights[switchLight_idx][0] = stof(atoms[2]); // red g_switchLights[switchLight_idx][1] = stof(atoms[3]); // green g_switchLights[switchLight_idx][2] = stof(atoms[4]); // blue } else { // error } // parse switch lights list bool utility_is_valid = true; int utility_idx = -1; try { utility_idx = _utility_map.at(atoms[1]); // map::at throws an out-of-range } catch (const std::out_of_range& oor) { utility_is_valid = false; //g_display_is_valid = true; //display("Warning:"+atoms[1]+" not found!"); } //std::cout << v[1] << ", " << g_led_map[v[1]] << std::endl; if(utility_is_valid && atoms.size()>=3){ g_utility[0] = atoms[1]; // display g_utility[1] = {""}; for(int i=0; i LibPDEngine::_light_map{ { "L1", 0 }, { "L2", 1 }, { "L3", 2 }, { "L4", 3 }, { "L5", 4 }, { "L6", 5 } }; const std::map LibPDEngine::_switchLight_map{ { "S1", 0 }, { "S2", 1 }, { "S3", 2 }, { "S4", 3 }, { "S5", 4 }, { "S6", 5 } }; const std::map LibPDEngine::_utility_map{ { "display", 0 } }; void LibPDEngine::sendKnob(const int idx, const float value){ std::string knob = "K"+std::to_string(idx+1); libpd_start_message(1); libpd_add_float(value); libpd_finish_message("fromVCV", knob.c_str()); } void LibPDEngine::sendSwitch(const int idx, const bool value){ std::string sw = "S"+std::to_string(idx+1); libpd_start_message(1); libpd_add_float(value); libpd_finish_message("fromVCV", sw.c_str()); } void LibPDEngine::sendInitialStates(const ProcessBlock* block){ // knobs for (int i=0; iknobs[i]); sendSwitch(i, block->knobs[i]); } std::string version = "pd "+std::to_string(PD_MAJOR_VERSION)+"."+ std::to_string(PD_MINOR_VERSION)+"." +std::to_string(PD_BUGFIX_VERSION); display(version); }