#include "NauModular.hpp" #include #ifdef ARCH_WIN #include #include #else #include #include #include #include #endif #include #include #include #include "tinyosc.h" #include "dsp/digital.hpp" #define osc_strncpy(_dst, _src, _len) strncpy(_dst, _src, _len) namespace rack_plugin_NauModular { struct Osc : Module{ enum ParamIds{ NUM_PARAMS }; enum InputIds{ GATE_INPUT, TRIG_INPUT, NUM_INPUTS }; enum OutputIds{ CV_OUTPUT, GATE_OUTPUT, TRIG_OUTPUT, NUM_OUTPUTS }; enum LightIds{ GATE_IN_LIGHT, TRIG_IN_LIGHT, CV_OUT_LIGHT, GATE_OUT_LIGHT, TRIG_OUT_LIGHT, NUM_LIGHTS }; Osc(); ~Osc(); void makeUDPSocket(); void checkIncomingOsc(); int makeFloatMsg(char * _buf, int _bufLen, std::string _addr, float _val); int makeGateMsg(char * _buf, int _bufLen, float _val); int makeTrigMsg(char * _buf, int _bufLen, float _val); void sendMsg(char * _buf, int _bufLen); void sendGateMsg(float _val); void sendTrigMsg(float _val=5.0); void step() override; void updateGateIn(); void updateTrigIn(); void openRemoteGate(float _val=5.0); void closeRemoteGate(); void openLocalGate(float _val=5.0); void closeLocalGate(); void setLocalCv(float _val); void setTrigNow(); bool isAnyOutputActive(); SchmittTrigger trigIn; float lastTrigInput; float lastTrigOutput; float thrTrig; float thrGateOpen; float thrGateClosed; float curTime; float stepTime; std::string ipOut; char * buffer; char * bufMsgOut; int portIn; int portOut; int s; int i; socklen_t slen; int recv_len; const int bufLen; const int msgBufLen; struct sockaddr_in si_me, si_other; bool bReady; bool bGateOpen; int n; }; Osc::Osc() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS), bufLen(1024), msgBufLen(1024){ portIn = 9000; portOut = 8000; ipOut = "127.0.0.1"; slen = sizeof(si_other); buffer = new char[bufLen]; bufMsgOut = new char[msgBufLen]; bReady = false; n = 0; lastTrigInput = 0.0; bGateOpen = false; thrTrig = 5; thrGateOpen = 5; thrGateClosed = 0; curTime = 0; #if ARCH_WIN WSADATA wsaData; WORD versionRequested = MAKEWORD(2,2); if(WSAStartup(versionRequested, &wsaData) != 0) { std::cout<<"OSC ERROR: Failed to start Windows networking"<0){ if(curTime > (lastTrigOutput+0.1)){ lights[TRIG_OUT_LIGHT].value = 0; outputs[TRIG_OUTPUT].value = 0; } } fd_set readSet; FD_ZERO(&readSet); FD_SET(s, &readSet); int microSec = stepTime * 1000000/2; struct timeval timeout = {0, microSec}; if(select(s+1, &readSet, NULL, NULL, &timeout)>0){ recv_len = 0; while((recv_len=(int)recvfrom(s, buffer, bufLen, 0, (struct sockaddr *)&si_other,&slen))>0){ if(tosc_isBundle(buffer)){ std::cout<<"OSC ERROR: no bundles, pleeze"<0){ openLocalGate(ff); }else{ closeLocalGate(); } }else if(sAddr=="/trigger"){ ff = tosc_getNextFloat(&msg); setTrigNow(); }else if(sAddr=="/cv"){ ff = tosc_getNextFloat(&msg); setLocalCv(ff); } } } } } int Osc::makeFloatMsg(char * _buf, int _bufLen, std::string _addr, float _val){ memset(_buf,0,_bufLen); uint32_t ii = (uint32_t)strlen(_addr.c_str()); if(_addr.c_str()==NULL || _addr.size()==0 || ii>=_bufLen)return -1; osc_strncpy(_buf, _addr.c_str(), _bufLen); ii = (ii+4)& ~0x3; _buf[ii++] = ','; int s_len = 1; osc_strncpy(_buf+ii, "f", _bufLen-ii-s_len); ii = (ii+4+s_len)& ~0x03; if((ii+4)>_bufLen)return -3; *((uint32_t *)(_buf+ii)) = htonl(*((uint32_t *)&_val)); ii+=4; return ii; } int Osc::makeGateMsg(char * _buf, int _bufLen, float _val){ return makeFloatMsg(_buf, _bufLen, "/gate", _val); } int Osc::makeTrigMsg(char * _buf, int _bufLen, float _val){ return makeFloatMsg(_buf, _bufLen, "/trigger", _val); } void Osc::sendMsg(char * _buf, int _bufLen){ if(bReady) sendto(s, _buf, _bufLen, 0, (struct sockaddr *)&si_other, slen); } void Osc::sendGateMsg(float _val){ int ll = makeGateMsg(bufMsgOut, msgBufLen, _val); if(ll>0){ sendMsg(bufMsgOut, ll); }else{ std::cout<<"OSC ERROR: cannot send gate message"<0){ sendMsg(bufMsgOut, ll); }else{ std::cout<<"OSC ERROR: cannot send trigger message"<=thrGateOpen){ openRemoteGate(curVal); }else if(curVal<=thrGateClosed){ closeRemoteGate(); } }else{ closeRemoteGate(); } } void Osc::openRemoteGate(float _val){ if(bGateOpen)return; lights[GATE_IN_LIGHT].value = 1.0; sendGateMsg(_val); bGateOpen = true; } void Osc::closeRemoteGate(){ if(!bGateOpen)return; lights[GATE_IN_LIGHT].value = 0.0; sendGateMsg(0); bGateOpen = false; } void Osc::closeLocalGate(){ lights[GATE_OUT_LIGHT].value = 0; outputs[GATE_OUTPUT].value = 0; } void Osc::openLocalGate(float _val){ lights[GATE_OUT_LIGHT].value = 1.0; outputs[GATE_OUTPUT].value = _val; } void Osc::setLocalCv(float _val){ lights[CV_OUT_LIGHT].value = fabs(_val)/12.0; outputs[CV_OUTPUT].value = _val; } void Osc::setTrigNow(){ lights[TRIG_OUT_LIGHT].value = 1; lastTrigOutput = curTime; outputs[TRIG_OUTPUT].value = 5; } void Osc::updateTrigIn(){ if(inputs[TRIG_INPUT].active){ float curVal = inputs[TRIG_INPUT].value; if(trigIn.process(curVal)){ lights[TRIG_IN_LIGHT].value = 1.0; sendTrigMsg(); lastTrigInput = curTime; } if(lights[TRIG_IN_LIGHT].value>0){ if(curTime>(lastTrigInput+0.1)){ lights[TRIG_IN_LIGHT].value = 0; } } }else{ trigIn.reset(); lights[TRIG_IN_LIGHT].value = 0.0; } } bool Osc::isAnyOutputActive(){ return (outputs[CV_OUTPUT].active || outputs[GATE_OUTPUT].active || outputs[TRIG_OUTPUT].active); } struct OscWidget : ModuleWidget{ OscWidget(Osc *module); }; OscWidget::OscWidget(Osc *module) : ModuleWidget(module){ box.size = Vec(6 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT); { SVGPanel *panel = new SVGPanel(); panel->box.size = box.size; panel->setBackground(SVG::load(assetPlugin(plugin, "res/Osc.svg"))); addChild(panel); } addInput(Port::create(Vec(10,75), Port::INPUT, module, Osc::GATE_INPUT)); addInput(Port::create(Vec(55,75), Port::INPUT, module, Osc::TRIG_INPUT)); addOutput(Port::create(Vec(32, 170), Port::OUTPUT, module, Osc::CV_OUTPUT)); addOutput(Port::create(Vec(10, 270), Port::OUTPUT, module, Osc::GATE_OUTPUT)); addOutput(Port::create(Vec(55, 270), Port::OUTPUT, module, Osc::TRIG_OUTPUT)); addChild(ModuleLightWidget::create>(Vec(16, 103), module, Osc::GATE_IN_LIGHT)); addChild(ModuleLightWidget::create>(Vec(62, 103), module, Osc::TRIG_IN_LIGHT)); addChild(ModuleLightWidget::create>(Vec(40, 200), module, Osc::CV_OUT_LIGHT)); addChild(ModuleLightWidget::create>(Vec(20, 250), module, Osc::GATE_OUT_LIGHT)); addChild(ModuleLightWidget::create>(Vec(60, 250), module, Osc::TRIG_OUT_LIGHT)); addChild(Widget::create(Vec(15, 0))); addChild(Widget::create(Vec(box.size.x - 30, 0))); addChild(Widget::create(Vec(15, 365))); addChild(Widget::create(Vec(box.size.x - 30, 365))); } } // namespace rack_plugin_NauModular using namespace rack_plugin_NauModular; RACK_PLUGIN_MODEL_INIT(NauModular, Osc) { Model *modelOsc = Model::create("NauModular", "Osc", "Osc", CONTROLLER_TAG); return modelOsc; }