From 55c95213b4583584b0cfcaa53d102cf13c7b3adb Mon Sep 17 00:00:00 2001 From: Florent Berthaut <florent.berthaut@univ-lille.fr> Date: Wed, 1 Jan 2025 21:25:37 +0100 Subject: [PATCH] Add new branch with integrated osc --- .gitignore | 2 + .gitmodules | 3 + SConstruct | 26 ++++++- demo/Main.tscn | 37 ++++++---- demo/{ => patches}/patch1.pd | Bin 849 -> 813 bytes demo/{ => patches}/patch2.pd | Bin patches/gdpd.pd | Bin 0 -> 1814 bytes patches/gdpd_receive.pd | Bin 0 -> 146 bytes patches/gdpd_send.pd | Bin 0 -> 146 bytes src/gdpd.cpp | 129 +++++++++++++++++++++-------------- src/gdpd.h | 21 ++++++ src/liblo | 1 + 12 files changed, 154 insertions(+), 65 deletions(-) rename demo/{ => patches}/patch1.pd (55%) rename demo/{ => patches}/patch2.pd (100%) create mode 100644 patches/gdpd.pd create mode 100644 patches/gdpd_receive.pd create mode 100644 patches/gdpd_send.pd create mode 160000 src/liblo diff --git a/.gitignore b/.gitignore index c95efac..fa09e8c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ *.import demo/build demo/export_presets.cfg +demo/android +build diff --git a/.gitmodules b/.gitmodules index aee1cce..6c592ef 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,3 +6,6 @@ path = src/godot-cpp url = https://github.com/GodotNativeTools/godot-cpp branch = 4.2 +[submodule "src/liblo"] + path = src/liblo + url = https://github.com/radarsat1/liblo.git diff --git a/SConstruct b/SConstruct index dff6e8f..ba31074 100644 --- a/SConstruct +++ b/SConstruct @@ -19,6 +19,21 @@ fiddle_file = open("src/libpd/pure-data/extra/fiddle~/fiddle~.c","w") fiddle_file.writelines(out_lines) fiddle_file.close() +#Generate liblo headers +import fileinput + +#threadinclude = '#include "lo/lo_serverthread.h"' +threadinclude = '' +with open("src/liblo/lo/lo.h.in", "r") as file: + filedata = file.read() + filedata = filedata.replace("@THREADS_INCLUDE@", threadinclude) +with open("src/liblo/lo/lo.h", "w") as file: + file.write(filedata) +with open("src/liblo/lo/lo_endian.h.in", "r") as file: + filedata = file.read() + filedata = filedata.replace("@LO_BIGENDIAN@", "0") +with open("src/liblo/lo/lo_endian.h", "w") as file: + file.write(filedata) env = SConscript("src/godot-cpp/SConstruct") @@ -33,6 +48,7 @@ env = SConscript("src/godot-cpp/SConstruct") env.Append(CPPPATH=['.', 'src/libpd/libpd_wrapper', 'src/libpd/libpd_wrapper/util', + "src/liblo", 'src/libpd/cpp','src/libpd/pure-data/src', 'src/rtaudio'], CCFLAGS=["-fexceptions"]) @@ -85,7 +101,15 @@ sources = Glob('src/*.cpp') + Glob('src/rtaudio/*.cpp') +\ Glob('src/libpd/pure-data/src/s_net.c') +\ Glob('src/libpd/pure-data/src/s_path.c') +\ Glob('src/libpd/pure-data/src/s_print.c') +\ - Glob('src/libpd/pure-data/src/s_utf8.c') + Glob('src/libpd/pure-data/src/s_utf8.c') +\ + Glob("src/liblo/src/*.c",\ + exclude=["src/liblo/src/*test*",\ + "src/liblo/src/*.cpp",\ + "src/liblo/src/*thread*"]) + +env.Append(CPPDEFINES=[ 'LO_SO_VERSION={11,1,4}', + 'PACKAGE_VERSION=\\"0.31\\"', 'PACKAGE_NAME=\\"liblo\\"', + 'PRINTF_LL=""']) if env["platform"] == "linux": env.Append(CPPDEFINES=['__UNIX_JACK__', 'HAVE_LIBDL']) diff --git a/demo/Main.tscn b/demo/Main.tscn index dd3ecf6..83f3d8a 100644 --- a/demo/Main.tscn +++ b/demo/Main.tscn @@ -7,32 +7,41 @@ script/source = "extends Control func _ready(): add_child(_gdpd) - pass - + func _process(delta): # Get messages from the patch while _gdpd.has_message() : var msg = _gdpd.get_next() print(\"got message from pd \", msg) - pass func _load_patch(pd_patch : String) : + + var fullpath = \"\" if OS.has_feature(\"editor\"): fullpath = ProjectSettings.globalize_path(pd_patch) else: - fullpath = OS.get_executable_path().get_base_dir().path_join(pd_patch.lstrip(\"res://\")) - #fullpath = pd_patch - #print(DirAccess.get_files_at(\"res://\")) + var file = pd_patch.split(\"/\")[-1] + var path = pd_patch.trim_suffix(file) + # Copy files from the patches folder from res to user + if OS.get_name() == \"Android\" : + fullpath = \"/sdcard/Android/data/com.example.gdpd/files/\" + else : + fullpath = OS.get_user_data_dir() + var dir = DirAccess.open(\"res://\") + fullpath = fullpath.path_join(file) + # FIXME do that in C++, and for all .pd and .wav files of the project, on start + dir.copy(\"res://\"+path+\"/\"+file, fullpath) + - print(fullpath) + print(\"fullpath = \", fullpath) # separate file name from directory var patch_name = fullpath.split(\"/\")[-1] var patch_dir = fullpath.trim_suffix(patch_name) # load patch - _gdpd.openfile(patch_name, \"./\") + _gdpd.openfile(patch_name, patch_dir) func _on_Start_pressed() : # retrieve the list of available input and outputs @@ -43,8 +52,8 @@ func _on_Start_pressed() : _gdpd.init_devices(inps[0], outs[0]) # the patch path should be absolute - _load_patch(\"res://patch1.pd\") - _load_patch(\"res://patch2.pd\") + _load_patch(\"patches/patch1.pd\") + _load_patch(\"patches/patch2.pd\") # send message to [receive from_godot] with one symbol _gdpd.start_message(1) @@ -60,8 +69,8 @@ func _on_start_non_rt_pressed(): _gdpd.init_nort() # the patch path should be absolute - _load_patch(\"res://patch1.pd\") - _load_patch(\"res://patch2.pd\") + _load_patch(\"patches/patch1.pd\") + _load_patch(\"patches/patch2.pd\") # send message to [receive from_godot] with one symbol _gdpd.start_message(1) @@ -72,8 +81,8 @@ func _on_start_non_rt_pressed(): _gdpd.subscribe(\"to_godot\") func _on_Stop_pressed(): - _gdpd.closefile(\"patch1.pd\") - _gdpd.closefile(\"patch2.pd\") + _gdpd.closefile(\"patches/patch1.pd\") + _gdpd.closefile(\"patches/patch2.pd\") _gdpd.stop() func _on_HSlider_value_changed(value): diff --git a/demo/patch1.pd b/demo/patches/patch1.pd similarity index 55% rename from demo/patch1.pd rename to demo/patches/patch1.pd index 82d8b965ff63eba8b115f18be8216809c79ee721..bee8fcfdb3037ab223c4eb996dfd8858c0f2d870 100644 GIT binary patch delta 289 zcmcb}wwBFK*-s%kF|RDKSi#cFK*7}1Si#cNOu@v=Ou^8|noBuCAtg0AC$T71LAM~W zBtt<@Pd_mwB|ooNKRu-&MSr5ys>w!-mjcZU%@s@y@T&!zmY<ZRU}k8cU~Z`ZG5{`S zWUgRn3K5GhPR&c1tjH)L22~Val$xBHS(d6$kXVwOVK`ZosZ`8T!2ql`IX^EiHMvB= rT){xW(0K9!CJ`|sG$~7vl-cBmOd|T`Xi|p83I+-$=z<`#EI@()Y}-*Z delta 315 zcmZ3>c9Bg=*-s%kF|RDKSiwNS$XvnD(#Sx;($ZML&}gFFsuXhtLsMggoXp}9g~Wn_ z)VvgHF69V?{G==eBLi~<b4!IHg|wpl-1zkTl>8EeoVkLbxw%5ILP<WljDfj=p|Pn# zQGRJjszO0xNpgna#CvxHL8ciRm_TeQDay>9Y|2zBW@xNn05&u^KQAvexkSNS!9c-s z@&P6hAqzAaLxaf|m_#BC4HXO&49(FcjX<Ji=%U671|SnrY%nwfDK$h_YCc(jS%k|1 JBxeAU0{}2nRkr{D diff --git a/demo/patch2.pd b/demo/patches/patch2.pd similarity index 100% rename from demo/patch2.pd rename to demo/patches/patch2.pd diff --git a/patches/gdpd.pd b/patches/gdpd.pd new file mode 100644 index 0000000000000000000000000000000000000000..952c2b7a6e0b70d2284d1c748246add79a565407 GIT binary patch literal 1814 zcmY%PQ%FwCD@!a^urxDJFf}z+urxJOFflVzFf_8}QjSo_Ps&m-G%-^!GBZ`kOD!o% zO-{`$OI6S<RnSdBRbXVGkdvR7l9ZU24wlF*PKW3;F;&RPEG|jSQ!p~N)H5<P&@(bL z)H5<PQm`~KGz6;!*<xyLp<rxk2(qO(H7^C56_y4H`NhcviABY!aBU#R85=^ZP$((N z%te(kF;FPVFD*$`NKYw9flHYg8!H%DnqWE@Bw=i5sgRtXmzSDcg3ZN<a51(tP%t%D zC`d`p&nqd)&jA|`@-|4q*jOR4D7{$004xgfAV}2002~$yIjMQ+B^fAEhDNB)0ckNY zH&ZY)wNxlkNCH8)dQ&3>Lo;)Q;>z5l{2YZC6+|e4EHN}NRwz!*0lD8m!B7F=U~pKO znL<M(H!(90ZlaN?rGl}EDK;ZPx=f7B6!J?;a#Bm+I*iQ~j4TZmiWJg{@^j<U^HcH> zav&`rmy{?ZDkQ>n7#SETfD9^zYC(<>a|1I46C;Hpg_8Vu)TlBuS1>XJM|@g-QEno_ z5)(^H1tS9kbSHx%02Dr!kf2V@1BDMFsez=yI*p9su^gjf2vUFuD05Rwu%*Rd=b(7a z+}J|F&=6v_LP1e#0Vu74T&w^OPmmR+CT0qzX5dr@vL7A>CMG5dhQ@}NF=}F_U~Gi$ z7f>1inPdpcT$#lsa0`o(A_5e2<|YcLVGYt{0kQ@b0k9NppkSb20!@`LF+&9d1tT;u zBL$F3Na}^DGf^;5Fhx^ms$igCh9+jFV4z@#E@-Y`pkRTf&_cmL!5B@<5~SG>P0$eJ z7)x|Pkh=}h9b^b{IY>P?%wbM9GzJ-q;c;V7{=g6g`O^r)TvG)@1w(UmH<&6IDHt1| zi-JPH2tyPU1cqh`klYG)8OX!vmVxvt7@`N45jZ=ehm8@)!^Y^rXaw>wh9KBy=rIHG zDk!#50?Y{H1q}V52s1(t10#?RjL}086eyVCWeoBHC^AqiGX|wUV|0&!1QbAqqpAgY i7vwusQIL1Bi5e;xp$8+#si4e;nz)TkKxx4O6gvR>E7iLI literal 0 HcmV?d00001 diff --git a/patches/gdpd_receive.pd b/patches/gdpd_receive.pd new file mode 100644 index 0000000000000000000000000000000000000000..d5fa2d14c1273045d6dd60cd2a1e9e5a1a37b48f GIT binary patch literal 146 zcmY%PQ%FwCD@!a^urxDJFf}z+urxJOFflVzFf_8}QjSo_Ps&m-G%{1LFi|K{NGr<E zjZaT0NI{V@v@lV~FD=PQEkPAFuv93@FD*$`h*2>F%OvOL<)tQ<C>SUhC>SXipokeM J7$_Km!~oa@C9ePg literal 0 HcmV?d00001 diff --git a/patches/gdpd_send.pd b/patches/gdpd_send.pd new file mode 100644 index 0000000000000000000000000000000000000000..61e18c7c8ea264bcef5e1d3525271bb6a4d40f0f GIT binary patch literal 146 zcmY%PQ%FwCD@!a^urxDJFf}z+urxJOFflVzFf_8}QjSo_Ps&m-w@@%KQ^?HANi9JZ zGc-0)C{`%Rk55l2NI{mcG*HONEG|(fC`v6z%}Y^;Q85HdC+Fwor6!js7$_Jh7%3Q_ Mh#4suC>Vmo0O@WfLjV8( literal 0 HcmV?d00001 diff --git a/src/gdpd.cpp b/src/gdpd.cpp index e5dd8aa..fd6f6fa 100644 --- a/src/gdpd.cpp +++ b/src/gdpd.cpp @@ -98,7 +98,7 @@ Array GdPd::get_available_output_devices() { } -int GdPd::init_devices(String inputDevice, String outputDevice) { +void GdPd::init_devices(String inputDevice, String outputDevice) { std::string inpStr(inputDevice.utf8().get_data()); std::string outStr(outputDevice.utf8().get_data()); @@ -120,11 +120,9 @@ int GdPd::init_devices(String inputDevice, String outputDevice) { m_bufferFrames = 128; m_realtime=true; - - return start(); } -int GdPd::init_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize) { +void GdPd::init_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize) { m_inputDevice = m_audio.getDefaultInputDevice(); m_outputDevice = m_audio.getDefaultOutputDevice(); RtAudio::DeviceInfo inpInfo = m_audio.getDeviceInfo(m_inputDevice); @@ -135,12 +133,9 @@ int GdPd::init_parameters(int nbInputs, int nbOutputs, int sampleRate, int buffe m_bufferFrames = std::max<int>(64, bufferSize); m_realtime=true; - - return start(); } int GdPd::init_nort() { - m_nbInputs=0; m_nbOutputs=2; m_sampleRate=44100; @@ -173,56 +168,79 @@ int GdPd::init_nort() { } int GdPd::start() { - RtAudio::StreamParameters outParams, inpParams; - inpParams.deviceId = m_inputDevice; - inpParams.nChannels = m_nbInputs; - outParams.deviceId = m_outputDevice; - outParams.nChannels = m_nbOutputs; - print("Output channels = "+std::to_string(outParams.nChannels)); - print("Input channels = "+std::to_string(inpParams.nChannels)); - - - if(!m_pd.init(m_nbInputs, m_nbOutputs, m_sampleRate, true)) { - print("GDPD : Error starting libpd"); - return 1; - } - - //libpd_set_verbose(1); - - //start dsp - m_pd.computeAudio(true); - if(m_realtime) { - //intialize rtaudio - if(m_audio.getDeviceCount()==0){ - UtilityFunctions::print("There are no available sound devices."); + if(m_mode==OSC) { + + //Create OSC sender + m_sender = NULL; + m_sender = lo_server_new_multicast( + MULTICAST_ADDRESS.c_str(), SENDER_PORT, NULL); + m_receiver = NULL; + m_receiver = lo_server_new_multicast( + MULTICAST_ADDRESS.c_str(), RECEIVER_PORT, NULL); + /* + m_sender = lo_server_new_with_proto( + to_string(UDP_SERVER_PORT).c_str(), + LO_UDP, NULL); + */ + if(m_receiver!=NULL) { + lo_server_add_method(m_receiver, NULL, NULL, oscHandler, this); + } + else { + cout<<"GdPd : Could not create UDP connection"<<endl; + } + } + else { + RtAudio::StreamParameters outParams, inpParams; + inpParams.deviceId = m_inputDevice; + inpParams.nChannels = m_nbInputs; + outParams.deviceId = m_outputDevice; + outParams.nChannels = m_nbOutputs; + print("Output channels = "+std::to_string(outParams.nChannels)); + print("Input channels = "+std::to_string(inpParams.nChannels)); + + if(!m_pd.init(m_nbInputs, m_nbOutputs, m_sampleRate, true)) { + print("GDPD : Error starting libpd"); return 1; } - RtAudio::StreamOptions options; - options.streamName = "gdpd"; - options.flags = RTAUDIO_SCHEDULE_REALTIME; - if(m_audio.getCurrentApi() != RtAudio::MACOSX_CORE) { - options.flags |= RTAUDIO_MINIMIZE_LATENCY; + //libpd_set_verbose(1); + + //start dsp + m_pd.computeAudio(true); + + if(m_mode==AUDIO_RT) { + //intialize rtaudio + if(m_audio.getDeviceCount()==0){ + UtilityFunctions::print("There are no available sound devices."); + return 1; + } + + RtAudio::StreamOptions options; + options.streamName = "gdpd"; + options.flags = RTAUDIO_SCHEDULE_REALTIME; + if(m_audio.getCurrentApi() != RtAudio::MACOSX_CORE) { + options.flags |= RTAUDIO_MINIMIZE_LATENCY; + } + try { + m_audio.openStream(&outParams, &inpParams, RTAUDIO_FLOAT32, + m_sampleRate, &m_bufferFrames, &audioCallback, + this, &options); + m_audio.startStream(); + print("Stream started"); + } + catch(RtAudioError& e) { + UtilityFunctions::print(e.getMessage().c_str()); + } } - try { - m_audio.openStream(&outParams, &inpParams, RTAUDIO_FLOAT32, - m_sampleRate, &m_bufferFrames, &audioCallback, - this, &options); - m_audio.startStream(); - print("Stream started"); + else { } - catch(RtAudioError& e) { - UtilityFunctions::print(e.getMessage().c_str()); - } - } - else { - } - //create message hook - m_pd.subscribe("to_gdpd"); - m_pd.setReceiver(this); - m_init=true; + //create message hook + m_pd.subscribe("to_gdpd"); + m_pd.setReceiver(this); + m_init=true; + } print("Initialized"); @@ -241,6 +259,17 @@ void GdPd::stop() { print("Stopped"); } +void GdPd::process(float delta) { + /* + if(m_udpServer!=NULL) { + lo_server_recv_noblock(m_udpServer, 10); + }*/ +} + +void GdPd::handleOSC(const char* path, const char* types, + lo_arg** argv, int argc, lo_message msg) { +} + void GdPd::processAudio(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames) { int ticks = nBufferFrames / libpd_blocksize(); diff --git a/src/gdpd.h b/src/gdpd.h index 90e8d59..b092b32 100644 --- a/src/gdpd.h +++ b/src/gdpd.h @@ -42,6 +42,8 @@ #include "PdBase.hpp" #include "RtAudio.h" +#include <lo/lo.h> + using namespace godot; class GdPdStreamPlayback; @@ -52,6 +54,18 @@ class GdPd : public Node, public pd::PdReceiver { protected: static void _bind_methods(); + static int oscHandler(const char *path, const char *types, + lo_arg ** argv, + int argc, lo_message msg, void *user_data) { + GdPd* gdpd = (GdPd*)user_data; + gdpd->handleOSC(path, types, argv, argc, msg); + return 0; + } + static void errorHandler(int num, const char *msg, const char *path){ + std::cout<<"GdPd Error : "<<msg<<" "<<path<<std::endl; + } + virtual void handleOSC(const char* path, const char* types, + lo_arg** argv, int argc, lo_message msg){}; private: bool m_realtime; @@ -75,6 +89,13 @@ private: enum Mode {OSC, AUDIO, AUDIO_RT}; int m_mode; + const int SENDER_PORT = 9211; + const int RECEIVER_PORT = 9212; + const std::string MULTICAST_ADDRESS = "239.210.211.212"; + lo_server m_sender; + lo_server m_receiver; + int m_senderPort; + int m_receiverPort; private: int start(); diff --git a/src/liblo b/src/liblo new file mode 160000 index 0000000..a3dc0cb --- /dev/null +++ b/src/liblo @@ -0,0 +1 @@ +Subproject commit a3dc0cb3b73d0cfdf31463f26df72342f3c26e2b -- GitLab