diff --git a/.gitmodules b/.gitmodules
index 2e035855f8a44c3c9035b0aad61fc9dd90e33e78..1527b7a1e22cf4fbb1f3978292fcb2533ac784be 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,4 @@
 [submodule "src/godot-cpp"]
 	path = src/godot-cpp
 	url = https://github.com/GodotNativeTools/godot-cpp
+    branch = 4.2
diff --git a/SConstruct b/SConstruct
index 1ced9da4bc2d12fa6638fe72a235cfd7d55105e5..43122b64a3e6c5b9232174008b12d614c7032327 100644
--- a/SConstruct
+++ b/SConstruct
@@ -29,7 +29,10 @@ env = SConscript("src/godot-cpp/SConstruct")
 # - CPPDEFINES are for pre-processor defines
 # - LINKFLAGS are for linking flags
 
-env.Append(CPPPATH=['.', 'src/libpd/libpd_wrapper', 'src/libpd/libpd_wrapper/util', 'src/libpd/cpp','src/libpd/pure-data/src',  'src/rtaudio'])
+env.Append(CPPPATH=['.', 'src/libpd/libpd_wrapper',
+                    'src/libpd/libpd_wrapper/util',
+                    'src/libpd/cpp','src/libpd/pure-data/src',  'src/rtaudio'], 
+           CCFLAGS=["-fexceptions"])
 
 env.Append(CFLAGS=['-DUSEAPI_DUMMY', '-DPD', '-DHAVE_UNISTD_H',\
 		'-D_GNU_SOURCE','-DLIBPD_EXTRA'])
diff --git a/demo/Main.tscn b/demo/Main.tscn
index 37ec47b180647eca5791778c1713e8bc67423eb9..810ce477b0a1883d9e949d9c95ca2ea3c2ab72d0 100644
--- a/demo/Main.tscn
+++ b/demo/Main.tscn
@@ -6,6 +6,7 @@ script/source = "extends Control
 @onready var _gdpd = GdPd.new()
 
 func _ready():
+	add_child(_gdpd)
 	pass
 	
 func _process(delta):
@@ -42,6 +43,23 @@ func _on_Start_pressed() :
 	
 	# 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(ProjectSettings.globalize_path(\"res://patch1.pd\"))
+	_load_patch(ProjectSettings.globalize_path(\"res://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_Stop_pressed():
 	_gdpd.closefile(\"patch1.pd\")
@@ -62,6 +80,8 @@ func _on_HSlider2_value_changed(value):
 	_gdpd.add_symbol(\"pitch\")
 	_gdpd.add_float(value)
 	_gdpd.finish_list(\"from_godot\")
+
+
 "
 
 [node name="Control" type="Control"]
@@ -73,21 +93,29 @@ grow_horizontal = 2
 grow_vertical = 2
 script = SubResource("1")
 
+[node name="Start" type="Button" parent="."]
+layout_mode = 0
+offset_left = 72.0
+offset_top = 80.0
+offset_right = 176.0
+offset_bottom = 128.0
+text = "Start"
+
 [node name="Stop" type="Button" parent="."]
 layout_mode = 0
-offset_left = 213.0
-offset_top = 83.0
-offset_right = 316.0
-offset_bottom = 129.0
+offset_left = 296.0
+offset_top = 80.0
+offset_right = 399.0
+offset_bottom = 128.0
 text = "Stop"
 
-[node name="Start" type="Button" parent="."]
+[node name="StartNonRT" type="Button" parent="."]
 layout_mode = 0
-offset_left = 73.0
-offset_top = 83.0
-offset_right = 177.0
-offset_bottom = 134.0
-text = "Start"
+offset_left = 184.0
+offset_top = 80.0
+offset_right = 290.0
+offset_bottom = 128.0
+text = "Start Non RT"
 
 [node name="HSlider" type="HSlider" parent="."]
 layout_mode = 0
@@ -121,7 +149,8 @@ offset_right = 204.0
 offset_bottom = 260.0
 text = "Send pitch to patch2"
 
-[connection signal="pressed" from="Stop" to="." method="_on_Stop_pressed"]
 [connection signal="pressed" from="Start" to="." method="_on_Start_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"]
diff --git a/src/gdpd.cpp b/src/gdpd.cpp
index 40481dbb3e6a72e75bc434d69ca682fbd43c71d9..aae9f73dfe9545a101ab79f7a5bd805003093ae2 100644
--- a/src/gdpd.cpp
+++ b/src/gdpd.cpp
@@ -2,7 +2,7 @@
  *  gdpd.cpp
  *  Part of GdPd
  *  2023- see README for AUTHORS
- *  https://gitlab.univ-lille.fr/immersync
+ *  https://gitlab.univ-lille.fr/ivmi
  ****************************************************************************/
 /*
  *  This program is free software; you can redistribute it and/or modify
@@ -24,14 +24,16 @@
 
 
 #include <godot_cpp/core/class_db.hpp>
-
 #include <godot_cpp/classes/os.hpp>
 #include <godot_cpp/classes/global_constants.hpp>
 #include <godot_cpp/classes/label.hpp>
 #include <godot_cpp/variant/utility_functions.hpp>
+#include <godot_cpp/classes/audio_server.hpp>
 
 using namespace godot;
 
+const int PCM_BUFFER_SIZE = 4096 * 4;
+
 void GdPd::_bind_methods() {
 	ADD_GROUP("GdPd", "gdpd_");
 
@@ -40,7 +42,8 @@ void GdPd::_bind_methods() {
     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"), &GdPd::init);
+    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("stop"), &GdPd::stop);
     ClassDB::bind_method(D_METHOD("openfile"), &GdPd::openfile);
     ClassDB::bind_method(D_METHOD("closefile"), &GdPd::closefile);
@@ -52,6 +55,7 @@ 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);
+
 }
 
 GdPd::GdPd() : m_vol(1) {
@@ -62,12 +66,13 @@ GdPd::GdPd() : m_vol(1) {
 
 GdPd::~GdPd() {}
 
+
+
 int GdPd::audioCallback(void *outputBuffer, void *inputBuffer, 
 					    unsigned int nBufferFrames, double streamTime, 
 						RtAudioStreamStatus status, void *userData){
 	GdPd* gdpd = static_cast<GdPd*>(userData);
-	gdpd->processAudio(outputBuffer, inputBuffer, nBufferFrames, streamTime,
-					   status, userData);
+	gdpd->processAudio(outputBuffer, inputBuffer, nBufferFrames);
 	return 0;
 }
 
@@ -113,10 +118,13 @@ int GdPd::init_devices(String inputDevice, String outputDevice) {
 	m_nbOutputs = outInfo.outputChannels;
 	m_sampleRate = outInfo.preferredSampleRate;
 	m_bufferFrames = 128;
+
+    m_realtime=true;
+
 	return start();
 }
 
-int GdPd::init(int nbInputs, int nbOutputs, int sampleRate, int bufferSize) {
+int 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);
@@ -125,17 +133,54 @@ int GdPd::init(int nbInputs, int nbOutputs, int sampleRate, int bufferSize) {
 	m_nbOutputs = std::min<int>(nbOutputs, outInfo.outputChannels);
 	m_sampleRate = sampleRate;
 	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;
+    m_realtime=false;
+
+
+	if(!m_pd.init(m_nbInputs, m_nbOutputs, m_sampleRate, true)) {
+		print("GDPD : Error starting libpd");
+		return 1;
+	}
+
+	// Create message hook
+	m_pd.subscribe("to_gdpd");
+	m_pd.setReceiver(this);
+	m_init=true;
+
+    // Create stream player
+	AudioStreamPlayer* p = new AudioStreamPlayer();
+    add_child(p);
+
+    Ref<GdPdStream> s;
+    s.instantiate();
+    s->setGdPd(this);
+
+    p->set_stream(s);
+    p->play();
+
+	print("Initialized");
+
+	return 0;
+}
+
 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));
+    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)) {
@@ -148,27 +193,32 @@ int GdPd::start() {
 	//start dsp
 	m_pd.computeAudio(true);
 
-	//intialize rtaudio
-	if(m_audio.getDeviceCount()==0){
-		UtilityFunctions::print("There are no available sound devices.");
-	}
-
-	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());
-	}
+    if(m_realtime) {
+        //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());
+        }
+    }
+    else {
+    }
 
 	//create message hook
 	m_pd.subscribe("to_gdpd");
@@ -182,15 +232,18 @@ int GdPd::start() {
 
 void GdPd::stop() {
 	m_init=false;
-	m_audio.stopStream();
-	m_audio.closeStream();
+    if(m_realtime) {
+        m_audio.stopStream();
+        m_audio.closeStream();
+    }
+    else {
+    }
 	m_pd.computeAudio(false);
 	print("Stopped");
 }
 
 void GdPd::processAudio(void *outputBuffer, void *inputBuffer, 
-						unsigned int nBufferFrames, double streamTime, 
-						RtAudioStreamStatus status, void *userData) {
+						unsigned int nBufferFrames) {
 	int ticks = nBufferFrames / libpd_blocksize();
 
 	m_pd.processFloat(ticks, (float*)inputBuffer, (float*)outputBuffer);
@@ -301,4 +354,44 @@ void GdPd::set_volume(float vol) {
 	m_vol=vol;
 }
 
+/* GdPdStream */
+GdPdStream::GdPdStream() {
+
+}
 
+Ref<AudioStreamPlayback> GdPdStream::_instantiate_playback() const {
+    Ref<GdPdStreamPlayback> gdPlayback;
+    gdPlayback.instantiate();
+    gdPlayback->m_base = Ref<GdPdStream>(this);
+    return gdPlayback;
+}
+
+#define zeromem(to, count) memset(to, 0, count)
+
+/* GdPdStreamplayback */
+GdPdStreamPlayback::GdPdStreamPlayback() {
+    m_buffer.resize(4096*2,0.0);
+    AudioServer::get_singleton()->lock();
+	pcm_buffer = memalloc(PCM_BUFFER_SIZE);
+	zeromem(pcm_buffer, PCM_BUFFER_SIZE);
+	AudioServer::get_singleton()->unlock();
+}
+
+GdPdStreamPlayback::~GdPdStreamPlayback() {
+
+}
+
+int32_t GdPdStreamPlayback::_mix_resampled(AudioFrame *buffer, 
+                                           int32_t nbFrames) {
+    m_buffer.resize(4096*2, 0.0);
+    m_base->getGdPd()->processAudio(m_buffer.data(), NULL, nbFrames);
+    for(int i = 0; i < nbFrames; i++) {
+        buffer[i].left = m_buffer[i*2];
+        buffer[i].right = m_buffer[i*2+1];
+    }
+    return nbFrames;
+}
+
+double GdPdStreamPlayback::_get_stream_sampling_rate() const {
+    return AudioServer::get_singleton()->get_mix_rate();
+}
diff --git a/src/gdpd.h b/src/gdpd.h
index e0b97aacb3c2625bce0a312c6025ec58ed6f2ffb..44be93ac1792e34832b0a395aa951cad337da5bc 100644
--- a/src/gdpd.h
+++ b/src/gdpd.h
@@ -1,7 +1,8 @@
 /***************************************************************************
- *  gd4pd.h
+ *  gdpd.h
  *  Part of GdPd
  *  2023- see README for AUTHORS
+ *  https://gitlab.univ-lille.fr/ivmi
  ****************************************************************************/
 /*
  *  This program is free software; you can redistribute it and/or modify
@@ -34,19 +35,26 @@
 #include <godot_cpp/core/binder_common.hpp>
 #include <godot_cpp/classes/engine.hpp>
 #include <godot_cpp/classes/audio_stream.hpp>
+#include <godot_cpp/classes/audio_stream_playback_resampled.hpp>
+#include <godot_cpp/classes/audio_stream_player.hpp>
+#include <godot_cpp/classes/audio_frame.hpp>
 
 #include "PdBase.hpp"
 #include "RtAudio.h"
 
 using namespace godot;
 
-class GdPd : public AudioStream, public pd::PdReceiver {
-	GDCLASS(GdPd, AudioStream);
+class GdPdStreamPlayback;
+
+
+class GdPd : public Node, public pd::PdReceiver {
+	GDCLASS(GdPd, Node);
 
 protected:
 	static void _bind_methods();
 
 private:
+    bool m_realtime;
 	float *m_inBuf; 
 	float *m_outBuf;
 	Array* m_messages;
@@ -64,6 +72,8 @@ private:
 
 	bool m_init;
 
+	int start();
+
 public:
 
 	GdPd();
@@ -72,9 +82,9 @@ public:
 	//libpd functions
 	Array get_available_input_devices();
 	Array get_available_output_devices();
+    int init_nort();
 	int init_devices(String inputDevice, String outputDevice);
-	int init(int nbInputs, int nbOutputs, int sampleRate, int bufferSize);
-	int start();
+	int init_parameters(int nbInputs, int nbOutputs, int sampleRate, int bufferSize);
 	void stop();
 	bool openfile(String basename, String dirname);
 	void closefile(String basename);
@@ -101,9 +111,56 @@ public:
 							 unsigned int nBufferFrames, double streamTime, 
 							 RtAudioStreamStatus status, void *userData);
 	void processAudio(void *outputBuffer, void *inputBuffer, 
-					   unsigned int nBufferFrames, double streamTime, 
-					   RtAudioStreamStatus status, void *userData);
+					   unsigned int nBufferFrames);
+};
+
+class GdPdStream : public AudioStream {
+	GDCLASS(GdPdStream, AudioStream);
+    friend class GdPdStreamPlayback;
+
+private:
+    GdPd* m_gdpd;
+
+protected:
+	static void _bind_methods(){}
+
+public:
+	GdPdStream();
+    Ref<AudioStreamPlayback> _instantiate_playback() const override;
+
+    virtual String _get_stream_name() const {return "GdPd";}
+    virtual double _get_length() const { return 0; }
+
+    void setGdPd(GdPd* gdpd){m_gdpd=gdpd;}
+    GdPd* getGdPd(){return m_gdpd;}
 };
 
 
+class GdPdStreamPlayback: public AudioStreamPlaybackResampled {
+	GDCLASS(GdPdStreamPlayback, AudioStreamPlaybackResampled);
+    friend class GdPdStream;
+
+protected:
+    Ref<GdPdStream> m_base;
+    std::vector<float> m_buffer;
+    bool active;
+    void *pcm_buffer;
+
+	static void _bind_methods(){}
+
+public:
+    GdPdStreamPlayback();
+    ~GdPdStreamPlayback();
+
+    int32_t _mix_resampled(AudioFrame *dst_buffer, int32_t frame_count) override;
+    double _get_stream_sampling_rate() const override;
+
+    bool _is_playing() const override {return active;}
+    void _start(double from_pos) override {active=true;}
+    void _seek(double position) override {}
+    void _stop() override {active=false;}
+};
+
+
+
 #endif
diff --git a/src/godot-cpp b/src/godot-cpp
index 28494f0bd59f9c35289524e503648ed8b4baaa59..98c143a48365f3f3bf5f99d6289a2cb25e6472d1 160000
--- a/src/godot-cpp
+++ b/src/godot-cpp
@@ -1 +1 @@
-Subproject commit 28494f0bd59f9c35289524e503648ed8b4baaa59
+Subproject commit 98c143a48365f3f3bf5f99d6289a2cb25e6472d1
diff --git a/src/register_types.cpp b/src/register_types.cpp
index 3097aa76755a0ca5256cbc0f1c282e5fdc7f5bad..574b624de8725a9f0962a586f258646d6fef219c 100644
--- a/src/register_types.cpp
+++ b/src/register_types.cpp
@@ -15,6 +15,8 @@ void initialize_gdpd_module(ModuleInitializationLevel p_level) {
 		return;
 	}
 	ClassDB::register_class<GdPd>();
+	ClassDB::register_class<GdPdStream>();
+	ClassDB::register_class<GdPdStreamPlayback>();
 }
 
 void uninitialize_gdpd_module(ModuleInitializationLevel p_level) {
diff --git a/src/rtaudio/RtAudio.os b/src/rtaudio/RtAudio.os
index 4dd83fb517790ff7e696d80faeef48fc2feb7ed5..2ff0399f747003294a06aead1af63b69ec45ff03 100644
Binary files a/src/rtaudio/RtAudio.os and b/src/rtaudio/RtAudio.os differ