diff --git a/examples/audio-trough.pd b/examples/audio-trough.pd index 529bd3e..29ce98b 100644 --- a/examples/audio-trough.pd +++ b/examples/audio-trough.pd @@ -1,9 +1,52 @@ -#N canvas 653 457 450 300 12; -#X obj 151 125 adc~ 1 2 3 4 5 6; -#X obj 152 184 dac~ 1 2 3 4 5 6; -#X connect 0 0 1 0; -#X connect 0 1 1 1; -#X connect 0 2 1 2; -#X connect 0 3 1 3; -#X connect 0 4 1 4; -#X connect 0 5 1 5; +#N canvas 2220 331 802 519 12; +#X obj 112 43 adc~ 1 2 3 4 5 6, f 47; +#X obj 113 199 dac~ 1 2 3 4 5 6, f 47; +#X obj 112 127 *~ 1; +#X obj 137 94 r K1; +#X obj 178 126 *~ 1; +#X obj 242 128 *~ 1; +#X obj 308 127 *~ 1; +#X obj 372 127 *~ 1; +#X obj 438 126 *~ 1; +#X obj 203 93 r K2; +#X obj 267 93 r K3; +#X obj 333 94 r K4; +#X obj 397 93 r K5; +#X obj 463 93 r K6; +#X obj 290 416 print toVCV; +#X msg 267 278 L3 \$1 0 0; +#X msg 333 310 L4 \$1 0 0; +#X msg 463 311 L6 \$1 0 0; +#X msg 136 277 L1 \$1 0 0; +#X msg 203 309 L2 \$1 0 0; +#X msg 397 280 L5 \$1 0 0; +#X connect 0 0 2 0; +#X connect 0 1 4 0; +#X connect 0 2 5 0; +#X connect 0 3 6 0; +#X connect 0 4 7 0; +#X connect 0 5 8 0; +#X connect 2 0 1 0; +#X connect 3 0 2 1; +#X connect 3 0 18 0; +#X connect 4 0 1 1; +#X connect 5 0 1 2; +#X connect 6 0 1 3; +#X connect 7 0 1 4; +#X connect 8 0 1 5; +#X connect 9 0 4 1; +#X connect 9 0 19 0; +#X connect 10 0 5 1; +#X connect 10 0 15 0; +#X connect 11 0 6 1; +#X connect 11 0 16 0; +#X connect 12 0 7 1; +#X connect 12 0 20 0; +#X connect 13 0 8 1; +#X connect 13 0 17 0; +#X connect 15 0 14 0; +#X connect 16 0 14 0; +#X connect 17 0 14 0; +#X connect 18 0 14 0; +#X connect 19 0 14 0; +#X connect 20 0 14 0; diff --git a/src/LibPDEngine.cpp b/src/LibPDEngine.cpp index b04fae3..212a37a 100644 --- a/src/LibPDEngine.cpp +++ b/src/LibPDEngine.cpp @@ -1,45 +1,54 @@ #include "ScriptEngine.hpp" #include "z_libpd.h" -#include -#include -using namespace std; +#include "util/z_print_util.h" +using namespace rack; #define BUFFERSIZE MAX_BUFFER_SIZE * NUM_ROWS -void chair_write_patch_to_file(const string &patch, const string &path, const string &name ) -{ - - ofstream myfile; - cout << "file to write: " << path + "/" + name << endl; - myfile.open (path + "/" + name); - myfile << patch; - myfile.close(); -} -void chair_load_patch(const string &patch, const string &name) -{ +// 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_leds[NUM_ROWS][3]; + +std::vector split (const std::string &s, char delim) { + std::vector result; + std::stringstream ss (s); + std::string item; - string path = "."; - chair_write_patch_to_file(patch, path, name); - - libpd_openfile(name.c_str(), path.c_str()); - - remove( (path + "/" + name).c_str() ); + while (getline (ss, item, delim)) { + result.push_back (item); + } + + return result; } + + struct LibPDEngine : ScriptEngine { ~LibPDEngine() { + libpd_free_instance(_lpd); + } - // // variables for libpd + + static void receiveLEDs(const char *s); + + bool knobChanged(const float* knobs, int idx); + + bool switchChanged(const float* knobs, int idx); + t_pdinstance *_lpd; int _pd_block_size = 64; int _sampleRate = 0; int _ticks = 0; + + float _old_knobs[NUM_ROWS]; + bool _old_switches[NUM_ROWS]; float _output[BUFFERSIZE]; float _input[BUFFERSIZE];// = (float*)malloc(1024*2*sizeof(float)); - // end variables for libpd + const static std::map _led_map; std::string getEngineName() override { @@ -49,49 +58,37 @@ struct LibPDEngine : ScriptEngine { 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_instance(_lpd); + libpd_set_printhook((t_libpd_printhook)libpd_print_concatenator); + libpd_set_concatenated_printhook( receiveLEDs ); + //libpd_set_printhook(receiveLEDs); + //libpd_bind("L2"); + //libpd_bind("foo"); + //libpd_set_listhook(receiveList); + //libpd_set_messagehook(receiveMessage); + + 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); - //cout << "_lpd is initialized" << endl; - - //cout << "num od pd instances: " << libpd_num_instances() << endl; - - // compute audio [; pd dsp 1( + + // 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 = "test.pd"; - std::string patch = "#N canvas 653 457 450 300 12;\n" - "#X obj 151 125 adc~ 1 2 3 4 5 6;\n" - "#X obj 152 184 dac~ 1 2 3 4 5 6;\n" - "#X connect 0 0 1 0;\n" - "#X connect 0 1 1 1;\n" - "#X connect 0 2 1 2;\n" - "#X connect 0 3 1 3;\n" - "#X connect 0 4 1 4;\n" - "#X connect 0 5 1 5;"; - - - - - - /*"#N canvas 333 425 105 153 10;\n" - "#X obj 32 79 dac~;\n" - "#X obj 32 27 adc~;\n" - "#X connect 1 0 0 0;\n" - "#X connect 1 1 0 1;";*/ - - //libpd_openfile(patch.c_str(), path.c_str()); - - chair_load_patch(patch, name); + std::string name = string::filename(path); + std::string dir = string::directory(path); + libpd_openfile(name.c_str(), dir.c_str()); return 0; } @@ -100,10 +97,7 @@ struct LibPDEngine : ScriptEngine { // block ProcessBlock* block = getProcessBlock(); - display(std::to_string(block->bufferSize)); - - // pass samples to/from libpd - _ticks = 1;//curr_bufSize / 64; + // get samples prototype int rows = NUM_ROWS; for (int s = 0; s < _pd_block_size; s++) { for (int r = 0; r < rows; r++) { @@ -112,8 +106,33 @@ struct LibPDEngine : ScriptEngine { } libpd_set_instance(_lpd); + + // knobs + for (int i=0; iknobs, i) ){ + std::string knob = "K"+std::to_string(i+1); + libpd_float(knob.c_str(), block->knobs[i]); + } + } + // leds + //display(std::to_string(g_leds[0])); + for(int i=0; ilights[i][0] = g_leds[i][0]; + block->lights[i][1] = g_leds[i][1]; + block->lights[i][2] = g_leds[i][2]; + } + // switches + for(int i=0; iswitches, i) ){ + std::string sw = "S"+std::to_string(i+1); + libpd_float(sw.c_str(), block->switches[i]); + } + } + // 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]; @@ -122,8 +141,6 @@ struct LibPDEngine : ScriptEngine { return 0; } - - }; @@ -131,3 +148,61 @@ __attribute__((constructor(1000))) static void constructor() { addScriptEngine("pd"); } + + +void LibPDEngine::receiveLEDs(const char *s) { + std::string str = std::string(s); + std::vector atoms = split (str, ' '); + + if(atoms[0]=="toVCV:"){ + // led list + bool led_is_valid = true; + int led_idx = -1; + try { + led_idx = _led_map.at(atoms[1]); // map::at throws an out-of-range + } + catch (const std::out_of_range& oor) { + led_is_valid = false; + //display("Warning:"+atoms[1]+" not found!"); + } + //std::cout << v[1] << ", " << g_led_map[v[1]] << std::endl; + if(led_is_valid && atoms.size()==5){ + g_leds[led_idx][0] = stof(atoms[2]); // red + g_leds[led_idx][1] = stof(atoms[3]); // green + g_leds[led_idx][2] = stof(atoms[4]); // blue + } + else { + + } + } + else { + // do nothing + } +} + +bool LibPDEngine::knobChanged(const float* knobs, int i){ + bool knob_changed = false; + if (_old_knobs[i] != knobs[i]){ + knob_changed = true; + _old_knobs[i] = knobs[i]; + } + return knob_changed; +} + +bool LibPDEngine::switchChanged(const float* switches, int i){ + bool switch_changed = false; + if (_old_switches[i] != switches[i]){ + switch_changed = true; + _old_switches[i] = switches[i]; + } + return switch_changed; +} + +const std::map LibPDEngine::_led_map{ + { "L1", 0 }, + { "L2", 1 }, + { "L3", 2 }, + { "L4", 3 }, + { "L5", 4 }, + { "L6", 5 } +}; \ No newline at end of file