From 624684c477f8218e1b9eebcb89c36081c1f05f84 Mon Sep 17 00:00:00 2001 From: Florent Berthaut <florent.berthaut@univ-lille.fr> Date: Mon, 6 Jan 2025 23:48:19 +0100 Subject: [PATCH] Fix osc sending/receiving --- SConstruct | 7 +- demo/Main.tscn | 159 +++++++++++---------------- demo/patches/patch1.pd | Bin 813 -> 908 bytes patches/gdpd.pd | Bin 1814 -> 2266 bytes src/gdpd.cpp | 242 ++++++++++++++++++++++++++++++----------- src/gdpd.h | 45 ++++---- 6 files changed, 274 insertions(+), 179 deletions(-) diff --git a/SConstruct b/SConstruct index ba31074..5326d1c 100644 --- a/SConstruct +++ b/SConstruct @@ -112,7 +112,7 @@ env.Append(CPPDEFINES=[ 'LO_SO_VERSION={11,1,4}', 'PRINTF_LL=""']) if env["platform"] == "linux": - env.Append(CPPDEFINES=['__UNIX_JACK__', 'HAVE_LIBDL']) + env.Append(CPPDEFINES=['__UNIX_JACK__', 'HAVE_LIBDL', 'HAVE_POLL=1']) env.Append(LIBS=['jack', 'pthread']) env.Append(LDPATH=['/usr/lib/x86_64-linux-gnu']) env.Append(CFLAGS=['-Wno-int-to-pointer-cast', '-Wno-pointer-to-int-cast', @@ -129,7 +129,8 @@ elif env["platform"] == "android": '-fomit-frame-pointer']) env.Append(CXXFLAGS=['-std=c++17']) elif env["platform"] == "windows": - env.Append(CPPDEFINES=['NOMINMAX', '__WINDOWS_DS__', 'PD_INTERNAL']) + env.Append(CPPDEFINES=['NOMINMAX', '__WINDOWS_DS__', + 'PD_INTERNAL', 'HAVE_SELECT=1']) elif env["platform"] == "macos": env.Append(CPPDEFINES=['NOMINMAX', '__MACOSX_CORE__', 'PD_INTERNAL']) @@ -146,4 +147,6 @@ else: source=sources, ) +# Copy pd patches + Default(library) diff --git a/demo/Main.tscn b/demo/Main.tscn index 83f3d8a..a9b4740 100644 --- a/demo/Main.tscn +++ b/demo/Main.tscn @@ -3,102 +3,59 @@ [sub_resource type="GDScript" id="1"] script/source = "extends Control -@onready var _gdpd = GdPd.new() +@onready var _gdpd = $GdPd 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) - -func _load_patch(pd_patch : String) : - - - var fullpath = \"\" - if OS.has_feature(\"editor\"): - fullpath = ProjectSettings.globalize_path(pd_patch) - else: - 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 = \", 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, patch_dir) - -func _on_Start_pressed() : - # retrieve the list of available input and outputs - var inps = _gdpd.get_available_input_devices() - var outs = _gdpd.get_available_output_devices() - - # initialise the first ones - _gdpd.init_devices(inps[0], outs[0]) - - # the patch path should be absolute - _load_patch(\"patches/patch1.pd\") - _load_patch(\"patches/patch2.pd\") - - # send message to [receive from_godot] with one symbol - _gdpd.start_message(1) - _gdpd.add_symbol(\"hello\") - _gdpd.finish_list(\"from_godot\") - - # listen to messages sent with [send to_godot] - _gdpd.subscribe(\"to_godot\") - - -func _on_start_non_rt_pressed(): - # initialise without realtime - _gdpd.init_nort() - - # the patch path should be absolute - _load_patch(\"patches/patch1.pd\") - _load_patch(\"patches/patch2.pd\") - - # send message to [receive from_godot] with one symbol - _gdpd.start_message(1) - _gdpd.add_symbol(\"hello\") - _gdpd.finish_list(\"from_godot\") - - # listen to messages sent with [send to_godot] - _gdpd.subscribe(\"to_godot\") - + #while $GdPd.has_message() : + # var msg = _gdpd.get_next() + # print(\"got message from pd \", msg) + pass + func _on_Stop_pressed(): - _gdpd.closefile(\"patches/patch1.pd\") - _gdpd.closefile(\"patches/patch2.pd\") + _gdpd.close_patch(\"patches/patch1.pd\") + #_gdpd.close_patch(\"patches/patch2.pd\") _gdpd.stop() func _on_HSlider_value_changed(value): + _gdpd.send(\"patch1\", [\"pitch\", value]) # send message to [receive from_godot] with three elements - _gdpd.start_message(3) - _gdpd.add_symbol(\"patch1\") - _gdpd.add_symbol(\"pitch\") - _gdpd.add_float(value) - _gdpd.finish_list(\"from_godot\") + #_gdpd.start_message(3) + #_gdpd.add_symbol(\"patch1\") + #_gdpd.add_symbol(\"pitch\") + #_gdpd.add_float(value) + #_gdpd.finish_list(\"from_godot\") + pass func _on_HSlider2_value_changed(value): - _gdpd.start_message(3) - _gdpd.add_symbol(\"patch2\") - _gdpd.add_symbol(\"pitch\") - _gdpd.add_float(value) - _gdpd.finish_list(\"from_godot\") + #_gdpd.start_message(3) + #_gdpd.add_symbol(\"patch2\") + #_gdpd.add_symbol(\"pitch\") + #_gdpd.add_float(value) + #_gdpd.finish_list(\"from_godot\") + pass + +func _on_gd_pd_got_message(address: String, arguments: Array) -> void: + print(\"got message \", address, arguments) + +func _on_start_osc_pressed() -> void: + _gdpd.set_mode(0) + _gdpd.start() + +func _on_start_audio_no_rt_pressed() -> void: + _gdpd.set_mode(1) + _gdpd.open_patch(\"patches/patch1.pd\") + #_load_patch(\"patches/patch2.pd\") + _gdpd.start() + +func _on_start_audio_rt_pressed() -> void: + _gdpd.set_mode(2) + _gdpd.open_patch(\"patches/patch1.pd\") + #_load_patch(\"patches/patch2.pd\") + _gdpd.start() " [node name="Control" type="Control"] @@ -110,29 +67,37 @@ grow_horizontal = 2 grow_vertical = 2 script = SubResource("1") -[node name="Start" type="Button" parent="."] +[node name="StartOSC" type="Button" parent="."] layout_mode = 0 offset_left = 72.0 offset_top = 80.0 offset_right = 176.0 offset_bottom = 128.0 -text = "Start" +text = "Start OSC" -[node name="Stop" type="Button" parent="."] +[node name="StartAudioNoRT" type="Button" parent="."] +layout_mode = 0 +offset_left = 184.0 +offset_top = 80.0 +offset_right = 288.0 +offset_bottom = 128.0 +text = "Start Audio" + +[node name="StartAudioRT" type="Button" parent="."] layout_mode = 0 offset_left = 296.0 offset_top = 80.0 -offset_right = 399.0 +offset_right = 402.0 offset_bottom = 128.0 -text = "Stop" +text = "Start Audio RT" -[node name="StartNonRT" type="Button" parent="."] +[node name="Stop" type="Button" parent="."] layout_mode = 0 -offset_left = 184.0 +offset_left = 424.0 offset_top = 80.0 -offset_right = 290.0 +offset_right = 527.0 offset_bottom = 128.0 -text = "Start Non RT" +text = "Stop" [node name="HSlider" type="HSlider" parent="."] layout_mode = 0 @@ -166,8 +131,12 @@ offset_right = 204.0 offset_bottom = 260.0 text = "Send pitch to patch2" -[connection signal="pressed" from="Start" to="." method="_on_Start_pressed"] +[node name="GdPd" type="GdPd" parent="."] + +[connection signal="pressed" from="StartOSC" to="." method="_on_start_osc_pressed"] +[connection signal="pressed" from="StartAudioNoRT" to="." method="_on_start_audio_no_rt_pressed"] +[connection signal="pressed" from="StartAudioRT" to="." method="_on_start_audio_rt_pressed"] [connection signal="pressed" from="Stop" to="." method="_on_Stop_pressed"] -[connection signal="pressed" from="StartNonRT" to="." method="_on_start_non_rt_pressed"] [connection signal="value_changed" from="HSlider" to="." method="_on_HSlider_value_changed"] [connection signal="value_changed" from="HSlider2" to="." method="_on_HSlider2_value_changed"] +[connection signal="got_message" from="GdPd" to="." method="_on_gd_pd_got_message"] diff --git a/demo/patches/patch1.pd b/demo/patches/patch1.pd index bee8fcfdb3037ab223c4eb996dfd8858c0f2d870..f1d010c8f321d83c238049dde8fe6d065bccbc77 100644 GIT binary patch delta 278 zcmZ3>*26x*Svn;(IVZ6wRYA8Pu_Qx5PfuS@Pro3sBsn9sc%p3(lab-XiOrJ@8H-rW z6pTy_C$C_1G&NT+H&DQ%Pv4qLIYJ>nDNDi3&_cn|QXxI1AZ4-;lg8xlj4H|?F+(F0 zg@U5Yyb`d=+~RZvBXb2qBMXI$)SR4r#mS~jr9y_53I<^5<ovw6)Z`Kc^T`*OL?)kS lVvROLlQA?@Fi<c@7c^BcP%yMW7d2BbP{0th1Stg@000B`O!oi) delta 209 zcmeBSU&}VZd18tWlY#lfP0bRy#pw!0<_d;J777K4CCM3v3K^+6Ir)l{4H(N=%@vGH zEhn#GbmX*9Ft=1lPbo;5?8>A$S({0I@-(J`dP@ZZYcAyoh2;Faywv0p1#<-h1w&&r mK?{(e5t^VSNYD&T(9lT10AvP=nIQ8NOwd(=Y_ebhi2?v8tv8(j diff --git a/patches/gdpd.pd b/patches/gdpd.pd index 952c2b7a6e0b70d2284d1c748246add79a565407..8d7aefbadbc8185576f6f091f5a2c131fae9377b 100644 GIT binary patch literal 2266 zcmY%PQ%FwCD@!a^urxDJFf}z+urxJOFflVzFf_8}QjSo_Ps&m-G%-^!GBZ`kOD!o% zO-{`$OI6S<RnSdBRbXVGkdvR7l9ZU2jw)ekppajjT##5)oQfi0Y-p;GlUZD%P*Rkc ziz;Jcpiq=wT9T@eo>GtkmohUpRxq+O!L-KM(m=t~T%jN(IX|zYC_e|RBeytR0VH8; ztdLlgUaVjM76thSBx+#*u{$R<FTErKMas|!(*_fBGX+CaONA1JBoKtFH!?9%Fto5x zD6Y&+%Fj`VQ89!|fow4}Fjgo|%}GrzQ7}+2R6qo&k*TGEv56@*eW1`bF)~xgFD=PQ zEkPJ(u3%(os8FPkR+OI`pPrwRkB|dt0a;g~kf@Ld*I{H}qyRFg7^($1D9sJb6ikd1 ziWExn<59xc#L`m1$iM*IVW7YS`PInK5FBo)c_6<kSQ;5ZJPeWtYc(=fNY2m81Nk^c z#So+b;b{wFBL$G7iov$ReE`yHYGS5fY6gyOkil?2n1I69*bpP!LF$c-&|L|NT#$?* zC@q3gRzXo}L26!#LNQW6g1l~SqJSD!AYB$9YmfsF9IR%h(4<(9SdxrLDCWi%3WkQz zL<F-26p{)Ebs&$Km?{_<LzJcFLDL{e+}y}i!N|f=AtkdI8eVWeo0*v_7#V^yO<I0Y zZej@}SP<rdylG-!p<rZYp^#CWqhM%mpkQPGN?}Ik3LrW)x1gj_0h!b_QqVO7Nf{a` zD5oWZpn|di7{F-*1xQ?ij5js6P%ySIQz%K#ff$W!7=&#=yon$Wg96jY1d`)Z^FRs1 zP{GL9QqRcHK+nj~P|pZj;DFSEGP<#$B|IgesRL<-q$-eNa|06vV^f4;LnCuN13d#h zw8RJYk*Oi55Gw{H3DgqI#K1_w*w7GEP+<>qXe5Dy*9aPqFfl^~0|jF<G(jVfAexx5 zf`NhwnwW`#fr61GnxH92vpJfenSz0W1)3NrzR_*A0H*{rg_a5i3g`wx5`-a|N<&ad zWr*$~Ly#vyi42@f;XXG~FjO!!MmNDo!AQXf-J>97AfG}K8QcW0SJ4dsdDRfZ05gzf z7@h!m7nJT%9R~8R5xUnv?gzynic*j&1!Hvo8iC@<2tBw#p2GC6kqO9Q256ozG698x zDY_`gzaYa=-2n2iF?u+He5HU*)KI|~!!~d*peF?*3k9%R)G!AnHw8m<wICxEjL_4z zF(}^AEi(ouZuB4nxfC-XjX??A1j7W7hcN^}sTm_Cj6pub6a_`FF?#5N?14G~0E2K! Av;Y7A 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 diff --git a/src/gdpd.cpp b/src/gdpd.cpp index fd6f6fa..4a470d8 100644 --- a/src/gdpd.cpp +++ b/src/gdpd.cpp @@ -37,16 +37,34 @@ const int PCM_BUFFER_SIZE = 4096 * 4; void GdPd::_bind_methods() { ADD_GROUP("GdPd", "gdpd_"); + /* + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_RANGE, "0,2"), + "set_mode", "get_mode"); +*/ + /* + ClassDB::add_property(get_class_static(), PropertyInfo(Variant::INT, "mode", + PROPERTY_HINT_ENUM, "OSC, AUDIO, AUDIO_RT", + PROPERTY_USAGE_DEFAULT), "set_mode", "get_mode"); + */ + ClassDB::bind_method(D_METHOD("get_available_input_devices"), &GdPd::get_available_input_devices); ClassDB::bind_method(D_METHOD("get_available_output_devices"), &GdPd::get_available_output_devices); - ClassDB::bind_method(D_METHOD("init_devices"), &GdPd::init_devices); - ClassDB::bind_method(D_METHOD("init_parameters"), &GdPd::init_parameters); - ClassDB::bind_method(D_METHOD("init_nort"), &GdPd::init_nort); + ClassDB::bind_method(D_METHOD("set_rt_devices"), &GdPd::set_rt_devices); + ClassDB::bind_method(D_METHOD("set_rt_parameters"), &GdPd::set_rt_parameters); + ClassDB::bind_method(D_METHOD("set_rt_defaults"), &GdPd::set_rt_defaults); + ClassDB::bind_method(D_METHOD("start"), &GdPd::start); ClassDB::bind_method(D_METHOD("stop"), &GdPd::stop); - ClassDB::bind_method(D_METHOD("openfile"), &GdPd::openfile); - ClassDB::bind_method(D_METHOD("closefile"), &GdPd::closefile); + ClassDB::bind_method(D_METHOD("open_patch"), &GdPd::open_patch); + ClassDB::bind_method(D_METHOD("close_patch"), &GdPd::close_patch); + + ClassDB::bind_method(D_METHOD("set_mode", "p_mode"), &GdPd::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &GdPd::get_mode); + + ClassDB::bind_method(D_METHOD("send"), &GdPd::send); + + /* ClassDB::bind_method(D_METHOD("subscribe"), &GdPd::subscribe); ClassDB::bind_method(D_METHOD("has_message"), &GdPd::has_message); ClassDB::bind_method(D_METHOD("get_next"), &GdPd::get_next); @@ -55,11 +73,22 @@ void GdPd::_bind_methods() { ClassDB::bind_method(D_METHOD("add_float"), &GdPd::add_float); ClassDB::bind_method(D_METHOD("finish_list"), &GdPd::finish_list); ClassDB::bind_method(D_METHOD("set_volume"), &GdPd::set_volume); + */ + + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", + PROPERTY_HINT_ENUM, "OSC, AUDIO, AUDIO_RT", + PROPERTY_USAGE_DEFAULT), + "set_mode", "get_mode"); + ADD_SIGNAL(MethodInfo("got_message", + PropertyInfo(Variant::STRING, "address"), + PropertyInfo(Variant::ARRAY, "arguments"))); } -GdPd::GdPd() : m_vol(1) { - //create message array +GdPd::GdPd() { + mode = 0; + m_receiver = NULL; + //m_sender = NULL; m_messages = new Array(); m_init=false; } @@ -67,6 +96,14 @@ GdPd::GdPd() : m_vol(1) { GdPd::~GdPd() {} +void GdPd::set_mode(const int p_mode) { + std::cout<<"mode "<<p_mode<<std::endl; + mode = p_mode; +} + +int GdPd::get_mode() const { + return mode; +} int GdPd::audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, @@ -79,26 +116,29 @@ int GdPd::audioCallback(void *outputBuffer, void *inputBuffer, Array GdPd::get_available_input_devices() { Array gdlist; + /* for(int d=0; d<m_audio.getDeviceCount(); d++) { if(m_audio.getDeviceInfo(d).inputChannels>0) { gdlist.push_back(m_audio.getDeviceInfo(d).name.c_str()); } - } + }*/ return gdlist; } Array GdPd::get_available_output_devices() { Array gdlist; + /* for(int d=0; d<m_audio.getDeviceCount(); d++) { if(m_audio.getDeviceInfo(d).outputChannels>0) { gdlist.push_back(m_audio.getDeviceInfo(d).name.c_str()); } - } + }*/ return gdlist; } -void GdPd::init_devices(String inputDevice, String outputDevice) { +void GdPd::set_rt_devices(String inputDevice, String outputDevice) { + /* std::string inpStr(inputDevice.utf8().get_data()); std::string outStr(outputDevice.utf8().get_data()); @@ -118,11 +158,12 @@ void GdPd::init_devices(String inputDevice, String outputDevice) { m_nbOutputs = outInfo.outputChannels; m_sampleRate = outInfo.preferredSampleRate; m_bufferFrames = 128; - - m_realtime=true; + */ } -void GdPd::init_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize) { +void GdPd::set_rt_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); @@ -131,11 +172,15 @@ void GdPd::init_parameters(int nbInputs, int nbOutputs, int sampleRate, int buff m_nbOutputs = std::min<int>(nbOutputs, outInfo.outputChannels); m_sampleRate = sampleRate; m_bufferFrames = std::max<int>(64, bufferSize); + */ +} + +void GdPd::set_rt_defaults() { - m_realtime=true; } -int GdPd::init_nort() { +/* +int GdPd::start() { m_nbInputs=0; m_nbOutputs=2; m_sampleRate=44100; @@ -152,45 +197,44 @@ int GdPd::init_nort() { m_pd.setReceiver(this); m_init=true; - // Create stream player - AudioStreamPlayer* p = memnew(AudioStreamPlayer()); - add_child(p); - - Ref<GdPdStream> s = memnew(GdPdStream()); - s->setGdPd(this); - - p->set_stream(s); - p->play(); print("Initialized"); return 0; -} +}*/ int GdPd::start() { + print("Starting with mode "+std::to_string(mode)); - if(m_mode==OSC) { - - //Create OSC sender - m_sender = NULL; + if(mode==OSC) {//OSC MODE + //Create OSC sender and receiver (multicast if no address has been set) + /* m_sender = lo_server_new_multicast( - MULTICAST_ADDRESS.c_str(), SENDER_PORT, NULL); - m_receiver = NULL; + MULTICAST_ADDRESS.c_str(), + std::to_string(SENDER_PORT).c_str(), + errorHandler); + */ + m_destination = lo_address_new(MULTICAST_ADDRESS.c_str(), + std::to_string(SENDER_PORT).c_str()); m_receiver = lo_server_new_multicast( - MULTICAST_ADDRESS.c_str(), RECEIVER_PORT, NULL); + MULTICAST_ADDRESS.c_str(), + std::to_string(RECEIVER_PORT).c_str(), + errorHandler); /* - m_sender = lo_server_new_with_proto( - to_string(UDP_SERVER_PORT).c_str(), + m_receiver = lo_server_new_with_proto( + std::to_string(RECEIVER_PORT).c_str(), LO_UDP, NULL); - */ + */ if(m_receiver!=NULL) { lo_server_add_method(m_receiver, NULL, NULL, oscHandler, this); + m_init = true; } else { - cout<<"GdPd : Could not create UDP connection"<<endl; + print("Could not create UDP connection"); } } - else { + /* + else { //AUDIO MODE RtAudio::StreamParameters outParams, inpParams; inpParams.deviceId = m_inputDevice; inpParams.nChannels = m_nbInputs; @@ -209,7 +253,7 @@ int GdPd::start() { //start dsp m_pd.computeAudio(true); - if(m_mode==AUDIO_RT) { + if(mode==AUDIO_RT) { //intialize rtaudio if(m_audio.getDeviceCount()==0){ UtilityFunctions::print("There are no available sound devices."); @@ -234,44 +278,91 @@ int GdPd::start() { } } else { + // Create stream player + AudioStreamPlayer* p = memnew(AudioStreamPlayer()); + add_child(p); + + Ref<GdPdStream> s = memnew(GdPdStream()); + s->setGdPd(this); + + p->set_stream(s); + p->play(); } //create message hook - m_pd.subscribe("to_gdpd"); + m_pd.subscribe("to_godot"); m_pd.setReceiver(this); m_init=true; } print("Initialized"); + */ return 0; } void GdPd::stop() { m_init=false; - if(m_realtime) { - m_audio.stopStream(); - m_audio.closeStream(); + if(mode==OSC) { + lo_server_del_method(m_receiver, NULL, NULL); + lo_server_free(m_receiver); + lo_address_free(m_destination); } + /* else { + if(mode==AUDIO_RT) { + m_audio.stopStream(); + m_audio.closeStream(); + } + else { + } + m_pd.computeAudio(false); } - m_pd.computeAudio(false); + */ print("Stopped"); } -void GdPd::process(float delta) { +void GdPd::send(String address, Array arguments) { + if(mode==OSC) { + lo_message msg = lo_message_new(); + lo_message_add_int32(msg, 10); + std::string addrStr(address.utf8().get_data()); + addrStr = std::string("/gdpd/patch/")+addrStr; + lo_send_message(m_destination, addrStr.c_str(), msg); + } +} + +void GdPd::_process(double delta) { + if(!m_init) { + return; + } + + if(mode==OSC) { + if(m_receiver!=NULL) { + int res = lo_server_recv_noblock(m_receiver, 1); + //print("received "+std::to_string(res)); + } + } /* - if(m_udpServer!=NULL) { - lo_server_recv_noblock(m_udpServer, 10); - }*/ + else { + m_pd.receiveMessages(); + + //FIXME for each message, call signal with address and arguments + emit_signal("got_message", "blup"); + } + */ } void GdPd::handleOSC(const char* path, const char* types, - lo_arg** argv, int argc, lo_message msg) { + lo_arg** argv, int argc, lo_message msg) { + print(path); + //FIXME call signal with address and arguments + emit_signal("got_message", "blup"); } void GdPd::processAudio(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames) { + /* int ticks = nBufferFrames / libpd_blocksize(); m_pd.processFloat(ticks, (float*)inputBuffer, (float*)outputBuffer); @@ -280,9 +371,32 @@ void GdPd::processAudio(void *outputBuffer, void *inputBuffer, for(int b=0; b<nBufferFrames*m_nbOutputs; ++b) { ((float*)outputBuffer)[b]*=m_vol; } + */ } -bool GdPd::openfile(godot::String baseStr, godot::String dirStr) { +bool GdPd::open_patch(godot::String patch) { + std::string patchStr(patch.utf8().get_data()); + + /* + var fullpath = "" + if OS.has_feature("editor"): + fullpath = ProjectSettings.globalize_path(pd_patch) + else: + 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) + var patch_name = fullpath.split("/")[-1] + var patch_dir = fullpath.trim_suffix(patch_name) +*/ + /* std::string baseS(baseStr.utf8().get_data()); std::string dirS(dirStr.utf8().get_data()); @@ -299,24 +413,27 @@ bool GdPd::openfile(godot::String baseStr, godot::String dirStr) { else { print("Opened patch "+baseS); m_patchsMap[baseS] = p1; - } + }*/ return true; } -void GdPd::closefile(godot::String baseStr) { - std::string baseS(baseStr.utf8().get_data()); - if(m_patchsMap.find(baseS)!=m_patchsMap.end()) { - m_pd.closePatch(m_patchsMap[baseS]); - m_patchsMap.erase(baseS); - print("Closed patch "+baseS); - } +void GdPd::close_patch(godot::String patch) { + std::string patchStr(patch.utf8().get_data()); + /* + if(m_patchsMap.find(patchStr)!=m_patchsMap.end()) { + m_pd.closePatch(m_patchsMap[patchStr]); + m_patchsMap.erase(patchStr); + print("Closed patch "+patchStr); + }*/ } +/* void GdPd::subscribe(String symbStr) { std::string symbS(symbStr.utf8().get_data()); m_pd.subscribe(symbS.c_str()); -} +}*/ +/* bool GdPd::has_message() { if(m_init) { //receive new messages @@ -357,9 +474,10 @@ int GdPd::finish_list(String destStr) { int res = libpd_finish_list(destS.c_str()); return res; } +*/ void GdPd::print(const std::string& message) { - UtilityFunctions::print((std::string("GDPD : ")+message).c_str()); + UtilityFunctions::print((std::string("GdPd : ")+message).c_str()); } void GdPd::receiveList(const std::string& dest, const pd::List& list) { @@ -378,10 +496,6 @@ void GdPd::receiveList(const std::string& dest, const pd::List& list) { m_messages->push_back(gdlist); } -void GdPd::set_volume(float vol) { - m_vol=vol; -} - /* GdPdStream */ GdPdStream::GdPdStream() { @@ -423,3 +537,5 @@ int32_t GdPdStreamPlayback::_mix_resampled(AudioFrame *buffer, float GdPdStreamPlayback::_get_stream_sampling_rate() const { return AudioServer::get_singleton()->get_mix_rate(); } + + diff --git a/src/gdpd.h b/src/gdpd.h index b092b32..f41ff85 100644 --- a/src/gdpd.h +++ b/src/gdpd.h @@ -58,14 +58,15 @@ protected: lo_arg ** argv, int argc, lo_message msg, void *user_data) { GdPd* gdpd = (GdPd*)user_data; + std::cout<<"got osc message"<<std::endl; 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){}; + void handleOSC(const char* path, const char* types, + lo_arg** argv, int argc, lo_message msg); private: bool m_realtime; @@ -87,33 +88,42 @@ private: bool m_init; enum Mode {OSC, AUDIO, AUDIO_RT}; - int m_mode; + int 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_sender; lo_server m_receiver; + lo_address m_destination; int m_senderPort; int m_receiverPort; -private: - int start(); - public: GdPd(); virtual ~GdPd(); - //libpd functions + void set_mode(const int p_mode); + int get_mode() const; + Array get_available_input_devices(); Array get_available_output_devices(); - int init_nort(); - int init_devices(String inputDevice, String outputDevice); - int init_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize); + void set_rt_devices(String inputDevice, String outputDevice); + void set_rt_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize); + void set_rt_defaults(); + + int start(); void stop(); - bool openfile(String basename, String dirname); - void closefile(String basename); + + void _process(double delta) override; + + bool open_patch(String basename); + void close_patch(String basename); + + void send(String destination, Array arguments); + + /* bool has_message(); Array get_next(); int blocksize(); @@ -122,15 +132,12 @@ public: void add_symbol(String symbStr); void add_float(float val); int finish_list(String destStr); + */ - //libpd hooks virtual void print(const std::string& message); - void receiveList(const std::string& dest, const pd::List& list); - - //godot functions - void set_volume(float vol); - inline const float& get_volume(){return m_vol;} + //libpd hooks + void receiveList(const std::string& dest, const pd::List& list); //rtaudio static int audioCallback(void *outputBuffer, void *inputBuffer, -- GitLab