|
|
@@ -3,102 +3,98 @@ |
|
|
|
#include "util/z_print_util.h" |
|
|
|
using namespace rack; |
|
|
|
|
|
|
|
#define BUFFERSIZE MAX_BUFFER_SIZE * NUM_ROWS |
|
|
|
static const int 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; |
|
|
|
static float g_lights[NUM_ROWS][3] = {}; |
|
|
|
static float g_switchLights[NUM_ROWS][3] = {}; |
|
|
|
static std::string g_utility[2] = {}; |
|
|
|
static bool g_display_is_valid = false; |
|
|
|
|
|
|
|
std::vector<std::string> split (const std::string &s, char delim) { |
|
|
|
std::vector<std::string> result; |
|
|
|
std::stringstream ss (s); |
|
|
|
std::string item; |
|
|
|
static std::vector<std::string> split(const std::string& s, char delim) { |
|
|
|
std::vector<std::string> result; |
|
|
|
std::stringstream ss(s); |
|
|
|
std::string item; |
|
|
|
|
|
|
|
while (getline (ss, item, delim)) { |
|
|
|
result.push_back (item); |
|
|
|
} |
|
|
|
while (getline(ss, item, delim)) { |
|
|
|
result.push_back(item); |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct LibPDEngine : ScriptEngine { |
|
|
|
t_pdinstance* _lpd = NULL; |
|
|
|
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<std::string, int> _light_map; |
|
|
|
const static std::map<std::string, int> _switchLight_map; |
|
|
|
const static std::map<std::string, int> _utility_map; |
|
|
|
|
|
|
|
~LibPDEngine() { |
|
|
|
libpd_free_instance(_lpd); |
|
|
|
|
|
|
|
if (_lpd) |
|
|
|
libpd_free_instance(_lpd); |
|
|
|
} |
|
|
|
|
|
|
|
void sendInitialStates(const ProcessBlock* block); |
|
|
|
static void receiveLights(const char *s); |
|
|
|
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<std::string, int> _light_map; |
|
|
|
const static std::map<std::string, int> _switchLight_map; |
|
|
|
const static std::map<std::string, int> _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(); |
|
|
|
_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 ); |
|
|
|
libpd_set_printhook((t_libpd_printhook)libpd_print_concatenator); |
|
|
|
libpd_set_concatenated_printhook(receiveLights); |
|
|
|
|
|
|
|
|
|
|
|
if(libpd_num_instances()>2) |
|
|
|
{ |
|
|
|
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); |
|
|
|
//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"); |
|
|
|
// 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 version = "pd "+std::to_string(PD_MAJOR_VERSION)+"."+ |
|
|
|
std::to_string(PD_MINOR_VERSION)+"."+ |
|
|
|
std::to_string(PD_BUGFIX_VERSION); |
|
|
|
std::string version = "pd " + std::to_string(PD_MAJOR_VERSION) + "." + |
|
|
|
std::to_string(PD_MINOR_VERSION) + "." + |
|
|
|
std::to_string(PD_BUGFIX_VERSION); |
|
|
|
|
|
|
|
display(version); |
|
|
|
|
|
|
|
std::string name = string::filename(path); |
|
|
|
std::string dir = string::directory(path); |
|
|
|
libpd_openfile(name.c_str(), dir.c_str()); |
|
|
|
|
|
|
|
sendInitialStates(block); |
|
|
|
|
|
|
|
std::string name = string::filename(path); |
|
|
|
std::string dir = string::directory(path); |
|
|
|
libpd_openfile(name.c_str(), dir.c_str()); |
|
|
|
|
|
|
|
sendInitialStates(block); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@@ -109,83 +105,77 @@ struct LibPDEngine : ScriptEngine { |
|
|
|
// 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]; |
|
|
|
} |
|
|
|
for (int r = 0; r < rows; r++) { |
|
|
|
_input[s * rows + r] = block->inputs[r][s]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
libpd_set_instance(_lpd); |
|
|
|
|
|
|
|
// knobs |
|
|
|
for (int i=0; i<NUM_ROWS; i++){ |
|
|
|
if( knobChanged(block->knobs, i) ){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
if (knobChanged(block->knobs, i)) { |
|
|
|
sendKnob(i, block->knobs[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
// lights |
|
|
|
for(int i=0; i<NUM_ROWS; i++){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
block->lights[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; i<NUM_ROWS; i++){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
block->switchLights[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; i<NUM_ROWS; i++){ |
|
|
|
if( switchChanged(block->switches, i) ){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
if (switchChanged(block->switches, i)) { |
|
|
|
sendSwitch(i, block->switches[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// display |
|
|
|
if(g_display_is_valid){ |
|
|
|
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]; // scale up again to +-5V signal |
|
|
|
// there is a correction multilpier, because libpd's output is too quiet(?) |
|
|
|
} |
|
|
|
} |
|
|
|
for (int r = 0; r < rows; r++) { |
|
|
|
block->outputs[r][s] = _output[s * rows + r]; // scale up again to +-5V signal |
|
|
|
// there is a correction multilpier, because libpd's output is too quiet(?) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
__attribute__((constructor(1000))) |
|
|
|
static void constructor() { |
|
|
|
addScriptEngine<LibPDEngine>("pd"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void LibPDEngine::receiveLights(const char *s) { |
|
|
|
void LibPDEngine::receiveLights(const char* s) { |
|
|
|
std::string str = std::string(s); |
|
|
|
std::vector<std::string> atoms = split (str, ' '); |
|
|
|
std::vector<std::string> atoms = split(str, ' '); |
|
|
|
|
|
|
|
if(atoms[0]=="toVCV:"){ |
|
|
|
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 |
|
|
|
} |
|
|
|
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){ |
|
|
|
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 |
|
|
@@ -197,14 +187,14 @@ void LibPDEngine::receiveLights(const char *s) { |
|
|
|
bool switchLight_is_valid = true; |
|
|
|
int switchLight_idx = -1; |
|
|
|
try { |
|
|
|
switchLight_idx = _switchLight_map.at(atoms[1]); // map::at throws an out-of-range |
|
|
|
} |
|
|
|
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){ |
|
|
|
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 |
|
|
@@ -216,19 +206,19 @@ void LibPDEngine::receiveLights(const char *s) { |
|
|
|
// parse switch lights list |
|
|
|
bool utility_is_valid = true; |
|
|
|
try { |
|
|
|
_utility_map.at(atoms[1]); // map::at throws an out-of-range |
|
|
|
} |
|
|
|
_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){ |
|
|
|
if (utility_is_valid && atoms.size() >= 3) { |
|
|
|
g_utility[0] = atoms[1]; // display |
|
|
|
g_utility[1] = {""}; |
|
|
|
for(unsigned i=0; i<atoms.size()-2; i++){ |
|
|
|
g_utility[1] += " " +atoms[i+2]; // concatenate message |
|
|
|
g_utility[1] = {""}; |
|
|
|
for (unsigned i = 0; i < atoms.size() - 2; i++) { |
|
|
|
g_utility[1] += " " + atoms[i + 2]; // concatenate message |
|
|
|
} |
|
|
|
g_display_is_valid = true; |
|
|
|
} |
|
|
@@ -236,24 +226,24 @@ void LibPDEngine::receiveLights(const char *s) { |
|
|
|
// error |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
// print out on command line |
|
|
|
std::cout << "libpd prototype unrecognizes message: " << std::string(s) << std::endl; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
bool LibPDEngine::knobChanged(const float* knobs, int i){ |
|
|
|
bool LibPDEngine::knobChanged(const float* knobs, int i) { |
|
|
|
bool knob_changed = false; |
|
|
|
if (_old_knobs[i] != knobs[i]){ |
|
|
|
if (_old_knobs[i] != knobs[i]) { |
|
|
|
knob_changed = true; |
|
|
|
_old_knobs[i] = knobs[i]; |
|
|
|
} |
|
|
|
return knob_changed; |
|
|
|
} |
|
|
|
|
|
|
|
bool LibPDEngine::switchChanged(const bool* switches, int i){ |
|
|
|
bool LibPDEngine::switchChanged(const bool* switches, int i) { |
|
|
|
bool switch_changed = false; |
|
|
|
if (_old_switches[i] != switches[i]){ |
|
|
|
if (_old_switches[i] != switches[i]) { |
|
|
|
switch_changed = true; |
|
|
|
_old_switches[i] = switches[i]; |
|
|
|
} |
|
|
@@ -266,7 +256,7 @@ const std::map<std::string, int> LibPDEngine::_light_map{ |
|
|
|
{ "L3", 2 }, |
|
|
|
{ "L4", 3 }, |
|
|
|
{ "L5", 4 }, |
|
|
|
{ "L6", 5 } |
|
|
|
{ "L6", 5 } |
|
|
|
}; |
|
|
|
|
|
|
|
const std::map<std::string, int> LibPDEngine::_switchLight_map{ |
|
|
@@ -275,7 +265,7 @@ const std::map<std::string, int> LibPDEngine::_switchLight_map{ |
|
|
|
{ "S3", 2 }, |
|
|
|
{ "S4", 3 }, |
|
|
|
{ "S5", 4 }, |
|
|
|
{ "S6", 5 } |
|
|
|
{ "S6", 5 } |
|
|
|
}; |
|
|
|
|
|
|
|
const std::map<std::string, int> LibPDEngine::_utility_map{ |
|
|
@@ -283,28 +273,28 @@ const std::map<std::string, int> LibPDEngine::_utility_map{ |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void LibPDEngine::sendKnob(const int idx, const float value){ |
|
|
|
std::string knob = "K"+std::to_string(idx+1); |
|
|
|
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()); |
|
|
|
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); |
|
|
|
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()); |
|
|
|
libpd_add_float(value); |
|
|
|
libpd_finish_message("fromVCV", sw.c_str()); |
|
|
|
} |
|
|
|
|
|
|
|
void LibPDEngine::sendInitialStates(const ProcessBlock* block){ |
|
|
|
void LibPDEngine::sendInitialStates(const ProcessBlock* block) { |
|
|
|
// knobs |
|
|
|
for (int i=0; i<NUM_ROWS; i++){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
sendKnob(i, block->knobs[i]); |
|
|
|
sendSwitch(i, block->knobs[i]); |
|
|
|
} |
|
|
|
|
|
|
|
for(int i=0; i<NUM_ROWS; i++){ |
|
|
|
for (int i = 0; i < NUM_ROWS; i++) { |
|
|
|
g_lights[i][0] = 0; |
|
|
|
g_lights[i][1] = 0; |
|
|
|
g_lights[i][2] = 0; |
|
|
@@ -317,6 +307,10 @@ void LibPDEngine::sendInitialStates(const ProcessBlock* block){ |
|
|
|
//g_utility[1] = ""; |
|
|
|
|
|
|
|
//g_display_is_valid = false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
__attribute__((constructor(1000))) |
|
|
|
static void constructor() { |
|
|
|
addScriptEngine<LibPDEngine>("pd"); |
|
|
|
} |